Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simulations #6

Merged
merged 1 commit into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Loading