Skip to content

Commit

Permalink
simulations
Browse files Browse the repository at this point in the history
  • Loading branch information
aanand1 committed Sep 9, 2024
1 parent 0e8d09b commit 0634388
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 0 deletions.
13 changes: 13 additions & 0 deletions core/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ type AtlasSdk struct {

userLastNonSequentialNonce map[uint64]map[common.Address]*big.Int
noncesMu sync.Mutex

atlasAddress map[uint64]common.Address
atlasVerificationAddress map[uint64]common.Address
simulatorAddress map[uint64]common.Address
sorterAddress map[uint64]common.Address
}

func NewAtlasSdk(ethClient []*ethclient.Client, chainOverrides map[uint64]*config.ChainConfig) (*AtlasSdk, error) {
Expand All @@ -42,6 +47,10 @@ func NewAtlasSdk(ethClient []*ethclient.Client, chainOverrides map[uint64]*confi
simulatorContract: make(map[uint64]*simulator.Simulator),
sorterContract: make(map[uint64]*sorter.Sorter),
userLastNonSequentialNonce: make(map[uint64]map[common.Address]*big.Int),
atlasAddress: make(map[uint64]common.Address),
atlasVerificationAddress: make(map[uint64]common.Address),
simulatorAddress: make(map[uint64]common.Address),
sorterAddress: make(map[uint64]common.Address),
}

for _, client := range ethClient {
Expand Down Expand Up @@ -82,6 +91,10 @@ func NewAtlasSdk(ethClient []*ethclient.Client, chainOverrides map[uint64]*confi
sdk.simulatorContract[chainIdUint64] = simulatorContract
sdk.sorterContract[chainIdUint64] = sorterContract
sdk.userLastNonSequentialNonce[chainIdUint64] = make(map[common.Address]*big.Int)
sdk.atlasAddress[chainIdUint64] = chainConf.Contract.Atlas
sdk.atlasVerificationAddress[chainIdUint64] = chainConf.Contract.AtlasVerification
sdk.simulatorAddress[chainIdUint64] = chainConf.Contract.Simulator
sdk.sorterAddress[chainIdUint64] = chainConf.Contract.Sorter
}

return sdk, nil
Expand Down
140 changes: 140 additions & 0 deletions core/simulate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package core

import (
"context"
"encoding/hex"
"fmt"
"math/big"

"github.com/FastLane-Labs/atlas-sdk-go/contract"
"github.com/FastLane-Labs/atlas-sdk-go/types"
"github.com/FastLane-Labs/atlas-sdk-go/utils"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
)

func (sdk *AtlasSdk) SimulateUserOperation(chainId uint64, userOp *types.UserOperation) error {
pData, err := contract.SimulatorAbi.Pack("simUserOperation", *userOp)
if err != nil {
return fmt.Errorf("failed to pack simUserOperation: %w", err)
}

if _, ok := sdk.ethClient[chainId]; !ok {
return fmt.Errorf("no ethClient for chainId %d", chainId)
}

simulatorAddr, ok := sdk.simulatorAddress[chainId]
if !ok {
return fmt.Errorf("no simulator Address for chainId %d", chainId)
}

bData, err := sdk.ethClient[chainId].CallContract(
context.Background(),
ethereum.CallMsg{
To: &simulatorAddr,
Gas: userOp.Gas.Uint64() + 1500000, // Add gas for validateCalls and others
GasFeeCap: new(big.Int).Set(userOp.MaxFeePerGas),
Value: new(big.Int).Set(userOp.Value),
Data: pData,
},
nil)
if err != nil {
return fmt.Errorf("failed to call simUserOperation: %w", err)
}

validOp, err := contract.SimulatorAbi.Unpack("simUserOperation", bData)
if err != nil {
return fmt.Errorf("failed to unpack simUserOperation: %w", err)
}

if !validOp[0].(bool) {
result := validOp[1].(uint8)
validCallResult := validOp[2].(*big.Int)
return fmt.Errorf(
"simUserOperation failed with result %d and outcome %s and pData %s",
result,
hex.EncodeToString(validCallResult.Bytes()),
hex.EncodeToString(pData),
)
}

return nil
}

func (sdk *AtlasSdk) SimulateSolverOperation(chainId uint64, userOp *types.UserOperation, solverOp *types.SolverOperation) error {
userOpHash, err := userOp.Hash(utils.FlagTrustedOpHash(userOp.CallConfig), chainId)
if err != nil {
return fmt.Errorf("failed to hash userOp: %w", err)
}
dAppOp := &types.DAppOperation{
From: common.Address{},
To: userOp.To,
Nonce: big.NewInt(0),
Deadline: userOp.Deadline,
Control: userOp.Control,
Bundler: common.Address{},
UserOpHash: userOpHash,
CallChainHash: common.Hash{},
Signature: []byte(""),
}

if utils.FlagVerifyCallChainHash(userOp.CallConfig) {
callChainHash, err := CallChainHash(userOp, []*types.SolverOperation{solverOp})
if err != nil {
return fmt.Errorf("failed to calculate callChainHash: %w", err)
}
dAppOp.CallChainHash = callChainHash
}

pData, err := contract.SimulatorAbi.Pack("simSolverCall", *userOp, *solverOp, *dAppOp)
if err != nil {
return fmt.Errorf("failed to pack simSolverCall: %w", err)
}

gasPrice := new(big.Int).Set(userOp.MaxFeePerGas)
if solverOp.MaxFeePerGas.Cmp(userOp.MaxFeePerGas) > 0 {
gasPrice.Set(solverOp.MaxFeePerGas)
}

if _, ok := sdk.ethClient[chainId]; !ok {
return fmt.Errorf("no ethClient for chainId %d", chainId)
}

simulatorAddr, ok := sdk.simulatorAddress[chainId]
if !ok {
return fmt.Errorf("no simulator Address for chainId %d", chainId)
}

bData, err := sdk.ethClient[chainId].CallContract(
context.Background(),
ethereum.CallMsg{
To: &simulatorAddr,
Gas: userOp.Gas.Uint64() + solverOp.Gas.Uint64() + 1500000, // Add gas for validateCalls and others
GasFeeCap: gasPrice,
Value: new(big.Int).Set(userOp.Value),
Data: pData,
},
nil,
)
if err != nil {
return fmt.Errorf("failed to call simSolverCall: %w", err)
}

validOp, err := contract.SimulatorAbi.Unpack("simSolverCall", bData)
if err != nil {
return fmt.Errorf("failed to unpack simSolverCall: %w pData %s", err, hex.EncodeToString(pData))
}

if !validOp[0].(bool) {
result := validOp[1].(uint8)
solverOutcomeResult := validOp[2].(*big.Int)
return fmt.Errorf(
"simSolverCall failed with result %d and outcome %s and pData %s",
result,
hex.EncodeToString(solverOutcomeResult.Bytes()),
hex.EncodeToString(pData),
)
}

return nil
}

0 comments on commit 0634388

Please sign in to comment.