Skip to content

Commit

Permalink
Merge pull request #1 from FastLane-Labs/fastlane_online_redeployment
Browse files Browse the repository at this point in the history
fastlane online redeployment changes
  • Loading branch information
aanand1 authored Aug 13, 2024
2 parents edda869 + ab2e292 commit c4a7d0b
Show file tree
Hide file tree
Showing 7 changed files with 489 additions and 162 deletions.
111 changes: 78 additions & 33 deletions bot/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package bot
import (
"bytes"
"context"
"encoding/hex"
"fmt"
"math/big"
"time"
Expand Down Expand Up @@ -148,39 +149,78 @@ func (b *Bot) handlePendingTx(tx *types.Transaction) {
return
}

signer := types.LatestSignerForChainID(tx.ChainId())
swapper, err := types.Sender(signer, tx)
rawTx, err := tx.MarshalJSON()
if err != nil {
log.Error("failed to get sender address of tx", "err", err, "chainId", tx.ChainId())
log.Error("failed to marshal tx to json", "err", err)
return
}

log.Info("detected userOperation tx in mempool", "hash", tx.Hash().Hex(), "rawTx", hex.EncodeToString(rawTx))

decodedUserInput, err := userMethod.Inputs.UnpackValues(tx.Data()[4:])
if err != nil {
log.Error("failed to unpack user method", "err", err)
return
}

if len(decodedUserInput) != 6 {
if len(decodedUserInput) != 1 {
log.Error("unexpected decoded user input length", "len", len(decodedUserInput))
return
}

swapIntent := decodedUserInput[0].(struct {
userOperation, ok := decodedUserInput[0].(struct {
From common.Address "json:\"from\""
To common.Address "json:\"to\""
Value *big.Int "json:\"value\""
Gas *big.Int "json:\"gas\""
MaxFeePerGas *big.Int "json:\"maxFeePerGas\""
Nonce *big.Int "json:\"nonce\""
Deadline *big.Int "json:\"deadline\""
Dapp common.Address "json:\"dapp\""
Control common.Address "json:\"control\""
CallConfig uint32 "json:\"callConfig\""
SessionKey common.Address "json:\"sessionKey\""
Data []uint8 "json:\"data\""
Signature []uint8 "json:\"signature\""
})
if !ok {
log.Error("failed to cast user operation, type of decodedUserInput[0] is not fastlaneOnline.UserOperation",
"decodedUserInput[0]", decodedUserInput[0], "type",
fmt.Sprintf("%T", decodedUserInput[0]),
)
return
}

userOperationDataMethodStr := "swap"
userOperationDataMethod, exists := FastlaneOnlineAbi.Methods[userOperationDataMethodStr]
if !exists {
panic("method not found in user operation abi - " + userOperationDataMethodStr)
}

decodedUserOperationData, err := userOperationDataMethod.Inputs.UnpackValues(userOperation.Data[4:])
if err != nil {
log.Error("failed to unpack user operation data", "err", err)
return
}

if len(decodedUserOperationData) != 2 {
log.Error("unexpected decoded user operation data length", "len", len(decodedUserOperationData))
return
}

swapIntent, ok := decodedUserOperationData[0].(struct {
TokenUserBuys common.Address "json:\"tokenUserBuys\""
MinAmountUserBuys *big.Int "json:\"minAmountUserBuys\""
TokenUserSells common.Address "json:\"tokenUserSells\""
AmountUserSells *big.Int "json:\"amountUserSells\""
})
baselineCall := decodedUserInput[1].(struct {
To common.Address "json:\"to\""
Data []uint8 "json:\"data\""
Success bool "json:\"success\""
})
deadline := decodedUserInput[2].(*big.Int)
gas := decodedUserInput[3].(*big.Int)
maxFeePerGas := decodedUserInput[4].(*big.Int)
userOpHash := decodedUserInput[5].([32]byte)
if !ok {
log.Error("failed to cast swap intent, type of decodedUserOperationData[0] is not fastlaneOnline.SwapIntent",
"decodedUserOperationData[0]", decodedUserOperationData[0],
"type", fmt.Sprintf("%T", decodedUserOperationData[0]),
)
return
}

effectiveTokenUserSells := swapIntent.TokenUserSells
if effectiveTokenUserSells == (common.Address{}) {
Expand Down Expand Up @@ -256,16 +296,22 @@ func (b *Bot) handlePendingTx(tx *types.Transaction) {
return
}

userOpHash, err := utils.UserOpHash(userOperation, b.domain)
if err != nil {
log.Error("error hashing user op", "err", err)
return
}

solverOp := &operation.SolverOperation{
From: config.SOLVER_EOA,
To: common.HexToAddress(b.config.AtlasAddress),
Value: big.NewInt(0),
Gas: b.solverGasLimit,
MaxFeePerGas: maxFeePerGas,
Deadline: deadline,
MaxFeePerGas: userOperation.MaxFeePerGas,
Deadline: userOperation.Deadline,
Solver: common.HexToAddress(b.config.SolverContractAddress),
Control: common.HexToAddress(b.config.FastlaneOnlineAddress),
UserOpHash: common.BytesToHash(userOpHash[:]),
UserOpHash: userOpHash,
BidToken: swapIntent.TokenUserBuys,
BidAmount: bidAmount,
Data: solverOpData,
Expand Down Expand Up @@ -296,7 +342,7 @@ func (b *Bot) handlePendingTx(tx *types.Transaction) {
if tx.Type() == types.LegacyTxType {
frontrunTxOps.GasPrice = big.NewInt(0).Add(tx.GasPrice(), gasMargin)
} else if tx.Type() == types.DynamicFeeTxType {
frontrunTxOps.GasFeeCap = tx.GasFeeCap()
frontrunTxOps.GasFeeCap = big.NewInt(0).Add(tx.GasFeeCap(), gasMargin)
frontrunTxOps.GasTipCap = big.NewInt(0).Add(tx.GasTipCap(), gasMargin)
} else {
log.Error("unknown user tx type", "txType", tx.Type())
Expand All @@ -305,22 +351,21 @@ func (b *Bot) handlePendingTx(tx *types.Transaction) {

broadcastTx, err := b.fastlaneOnlineContract.AddSolverOp(
frontrunTxOps,
fastlaneOnline.SwapIntent{
TokenUserBuys: swapIntent.TokenUserBuys,
MinAmountUserBuys: swapIntent.MinAmountUserBuys,
TokenUserSells: swapIntent.TokenUserSells,
AmountUserSells: swapIntent.AmountUserSells,
},
fastlaneOnline.BaselineCall{
To: baselineCall.To,
Data: baselineCall.Data,
Success: baselineCall.Success,
fastlaneOnline.UserOperation{
From: userOperation.From,
To: userOperation.To,
Value: userOperation.Value,
Gas: userOperation.Gas,
MaxFeePerGas: userOperation.MaxFeePerGas,
Nonce: userOperation.Nonce,
Deadline: userOperation.Deadline,
Dapp: userOperation.Dapp,
Control: userOperation.Control,
CallConfig: userOperation.CallConfig,
SessionKey: userOperation.SessionKey,
Data: userOperation.Data,
Signature: userOperation.Signature,
},
deadline,
gas,
maxFeePerGas,
common.BytesToHash(userOpHash[:]),
swapper,
fastlaneOnline.SolverOperation{
From: solverOp.From,
To: solverOp.To,
Expand Down
8 changes: 4 additions & 4 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ swap_paths_bin_file: swap_paths_polygon.bin

mempool_connection_eth_method: alchemy_pendingTransactions

fastlane_online_address: 0x0E3009d01e85ac49D164E453Ec81283EAAf46fB5
solver_contract_address: 0x1c8930Fde5500B881ABe94f6aD9CfA10375066f6
atlas_address: 0x892F8f6779ca6927c1A6Cc74319e03d2abEf18D5
atlas_verification_address: 0xc05DDBe9745ce9DB45C32F5e4C1DA7a3c4FDa220
fastlane_online_address: 0x3BF81d7D921E7a6A1999ce3dfa3B348c50fE8DFd
solver_contract_address: 0x6F6D7157602bB7b2F2a1dA67dCb99d9C40605eaC
atlas_address: 0x20eA1943264FED9471f4E9430C935986A60905E3
atlas_verification_address: 0xd72A38636d88B7F7326340add69a1A494E74c913
weth_address: 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270

frontrun_gas_margin_gwei: 1
Expand Down
477 changes: 356 additions & 121 deletions contract/fastlaneOnline/fastlaneOnline.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ services:
command:
- --profit_margin_x10000=500
- --frontrun_gas_margin_gwei=1
- --fastlane_online_address=0x0E3009d01e85ac49D164E453Ec81283EAAf46fB5
- --solver_contract_address=0x1c8930Fde5500B881ABe94f6aD9CfA10375066f6
- --fastlane_online_address=0x3BF81d7D921E7a6A1999ce3dfa3B348c50fE8DFd
- --solver_contract_address=0x6F6D7157602bB7b2F2a1dA67dCb99d9C40605eaC
- --pools_config_file=pools_config_polygon.yaml
- --pools_bin_file=pools_polygon.bin
- --swap_paths_bin_file=swap_paths_polygon.bin
Expand Down
2 changes: 1 addition & 1 deletion events/chain_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (c *EthClientConnection) reconnect() {
log.Info("ethClient conn: reconnecting...")
newConn, err := NewEthClientConnection(c.conf)
if err == nil {
c.Client = newConn.Client
*c.Client = *newConn.Client
c.Start()
return
}
Expand Down
6 changes: 5 additions & 1 deletion pools/uniswapV3.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func (p *UniswapV3Pool) HandleLog(aLog *types.Log) error {
p.tick = spacedTick
if prevTick == p.tick {
if p.liquidity.Cmp(oldLiquidity) != 0 {
log.Error("liquidity changed but tick stayed the same", "pool", p.address.Hex(), "liquidity", oldLiquidity, "newLiquidity", p.liquidity)
log.Debug("error - liquidity changed but tick stayed the same", "pool", p.address.Hex(), "liquidity", oldLiquidity, "newLiquidity", p.liquidity)
}
} else {
if p.stateLoaderStatus == nil {
Expand Down Expand Up @@ -413,6 +413,8 @@ func deltaXFromPriceDiff(liquidity, currPrice, finalPrice *big.Int, roundUp bool
func finalPriceFromDeltaY(dy, liquidity, initialPrice *big.Int, add bool) *big.Int {
if liquidity.Cmp(big.NewInt(0)) == 0 {
return initialPrice
} else if dy.Cmp(big.NewInt(0)) == 0 {
return initialPrice
} else {
uint160Max := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 161), big.NewInt(1))
quotient := new(big.Int)
Expand Down Expand Up @@ -443,6 +445,8 @@ func finalPriceFromDeltaY(dy, liquidity, initialPrice *big.Int, add bool) *big.I
func finalPriceFromDeltaX(dx, liquidity, initialPrice *big.Int, add bool) *big.Int {
if liquidity.Cmp(big.NewInt(0)) == 0 {
return initialPrice
} else if dx.Cmp(big.NewInt(0)) == 0 {
return initialPrice
} else {
numer1 := new(big.Int).Lsh(liquidity, 96)
if add {
Expand Down
43 changes: 43 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package utils

import (
"fmt"
"math/big"

"github.com/FastLane-Labs/atlas-operations-relay/operation"
opsRelayUtils "github.com/FastLane-Labs/atlas-operations-relay/utils"
"github.com/FastLane-Labs/fastlane-online-solver/config"
"github.com/FastLane-Labs/fastlane-online-solver/contract/fastlaneOnline"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
)
Expand Down Expand Up @@ -35,3 +40,41 @@ func Domain(conf *config.Config, chainId int64) *apitypes.TypedDataDomain {
VerifyingContract: conf.AtlasVerificationAddress,
}
}

func UserOpHash(userOperation struct {
From common.Address "json:\"from\""
To common.Address "json:\"to\""
Value *big.Int "json:\"value\""
Gas *big.Int "json:\"gas\""
MaxFeePerGas *big.Int "json:\"maxFeePerGas\""
Nonce *big.Int "json:\"nonce\""
Deadline *big.Int "json:\"deadline\""
Dapp common.Address "json:\"dapp\""
Control common.Address "json:\"control\""
CallConfig uint32 "json:\"callConfig\""
SessionKey common.Address "json:\"sessionKey\""
Data []uint8 "json:\"data\""
Signature []uint8 "json:\"signature\""
}, domain *apitypes.TypedDataDomain) (common.Hash, error) {
opsRelayUserOp := &operation.UserOperation{
From: userOperation.From,
To: userOperation.To,
Value: userOperation.Value,
Gas: userOperation.Gas,
MaxFeePerGas: userOperation.MaxFeePerGas,
Nonce: userOperation.Nonce,
Deadline: userOperation.Deadline,
Dapp: userOperation.Dapp,
Control: userOperation.Control,
CallConfig: userOperation.CallConfig,
SessionKey: userOperation.SessionKey,
Data: userOperation.Data,
Signature: userOperation.Signature,
}

userOpHash, relayErr := opsRelayUserOp.Hash(opsRelayUtils.FlagTrustedOpHash(opsRelayUserOp.CallConfig), domain)
if relayErr != nil {
return common.Hash{}, fmt.Errorf("failed to hash user operation: %v", relayErr)
}
return userOpHash, nil
}

0 comments on commit c4a7d0b

Please sign in to comment.