From 0c0b75dbe9a1ef483ab524457bca9bd54381847b Mon Sep 17 00:00:00 2001 From: tre Date: Mon, 16 Sep 2024 11:37:31 -0700 Subject: [PATCH] feat: apply SuperchainWETH contracts to forked networks --- anvil/anvil.go | 5 ++++ cmd/main.go | 7 +++++ config/chain.go | 2 ++ contracts/lib/optimism | 2 +- go.mod | 1 + go.sum | 2 ++ interop/applier.go | 22 +++++++++++++++ orchestrator/fork.go | 4 +-- supersim_test.go | 62 ++++++++++++++++++++++++++++++++++++++++-- testutils/mockchain.go | 5 ++++ 10 files changed, 106 insertions(+), 6 deletions(-) diff --git a/anvil/anvil.go b/anvil/anvil.go index 682eccf4..e86a23ec 100644 --- a/anvil/anvil.go +++ b/anvil/anvil.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "math/big" "os" "os/exec" "strconv" @@ -248,6 +249,10 @@ func (a *Anvil) SetStorageAt(ctx context.Context, result interface{}, address co return a.rpcClient.CallContext(ctx, result, "anvil_setStorageAt", address.Hex(), storageSlot, storageValue) } +func (a *Anvil) SetBalance(ctx context.Context, result interface{}, address common.Address, value *big.Int) error { + return a.rpcClient.CallContext(ctx, result, "anvil_setBalance", address.Hex(), hexutil.EncodeBig(value)) +} + func (a *Anvil) SetIntervalMining(ctx context.Context, result interface{}, interval int64) error { return a.rpcClient.CallContext(ctx, result, "evm_setIntervalMining", interval) } diff --git a/cmd/main.go b/cmd/main.go index 9777ea9b..b11eaf04 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,6 +19,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/joho/godotenv" "github.com/urfave/cli/v2" ) @@ -34,6 +35,12 @@ const ( ) func main() { + // Load the .env file + err := godotenv.Load() + if err != nil { + log.Crit("Error loading .env file", "err", err) + } + oplog.SetupDefaults() logFlags := oplog.CLIFlags(envVarPrefix) diff --git a/config/chain.go b/config/chain.go index caab94ed..227ac7c4 100644 --- a/config/chain.go +++ b/config/chain.go @@ -3,6 +3,7 @@ package config import ( "context" "fmt" + "math/big" "strings" registry "github.com/ethereum-optimism/superchain-registry/superchain" @@ -81,6 +82,7 @@ type Chain interface { SimulatedLogs(ctx context.Context, tx *types.Transaction) ([]types.Log, error) SetCode(ctx context.Context, result interface{}, address common.Address, code string) error SetStorageAt(ctx context.Context, result interface{}, address common.Address, storageSlot string, storageValue string) error + SetBalance(ctx context.Context, result interface{}, address common.Address, value *big.Int) error SetIntervalMining(ctx context.Context, result interface{}, interval int64) error // Lifecycle diff --git a/contracts/lib/optimism b/contracts/lib/optimism index ac443ef0..f70248a0 160000 --- a/contracts/lib/optimism +++ b/contracts/lib/optimism @@ -1 +1 @@ -Subproject commit ac443ef0146b6c71d3460d3aba2f67cddd8c04c4 +Subproject commit f70248a0ace5375d578e99697df7a5a1bd2d20ee diff --git a/go.mod b/go.mod index 217088f3..2d5ce3c7 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/ethereum-optimism/optimism v1.9.1-0.20240808190618-0c8d7c8c5186 github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240803025447-c92ef420eec2 github.com/ethereum/go-ethereum v1.13.15 + github.com/joho/godotenv v1.5.1 github.com/stretchr/testify v1.9.0 github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.27.3 diff --git a/go.sum b/go.sum index 0c5f212c..667f2285 100644 --- a/go.sum +++ b/go.sum @@ -182,6 +182,8 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0 github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= diff --git a/interop/applier.go b/interop/applier.go index 180aaeb2..7d2478ed 100644 --- a/interop/applier.go +++ b/interop/applier.go @@ -28,6 +28,8 @@ var interopPredeploys = []common.Address{ predeploys.CrossL2InboxAddr, predeploys.L2toL2CrossDomainMessengerAddr, predeploys.L1BlockAddr, + common.HexToAddress("0x4200000000000000000000000000000000000024"), + common.HexToAddress("0x4200000000000000000000000000000000000025"), } type predeploy struct { @@ -114,6 +116,14 @@ func applyAllocToAddress(ctx context.Context, chain config.Chain, alloc *genesis } } } + + balance := hexStringToBigInt(alloc.Balance) + if balance.Cmp(big.NewInt(0)) > 0 { + if err := chain.SetBalance(ctx, nil, address, balance); err != nil { + return fmt.Errorf("failed to set balance for %s: %w", address, err) + } + } + return nil } @@ -177,3 +187,15 @@ func waitMinedWithTicker(ctx context.Context, b bind.DeployBackend, tx *types.Tr } } } + +func hexStringToBigInt(hexString string) *big.Int { + // Remove the "0x" prefix if it's present + if len(hexString) > 1 && hexString[:2] == "0x" { + hexString = hexString[2:] + } + + bigInt := new(big.Int) + bigInt.SetString(hexString, 16) + + return bigInt +} diff --git a/orchestrator/fork.go b/orchestrator/fork.go index 32062e1f..13f31920 100644 --- a/orchestrator/fork.go +++ b/orchestrator/fork.go @@ -24,7 +24,7 @@ func NetworkConfigFromForkCLIConfig(log log.Logger, envPrefix string, forkConfig // L1 l1RpcUrl := superchain.Config.L1.PublicRPC if url, ok := os.LookupEnv(fmt.Sprintf("%s_RPC_URL_%s", envPrefix, strings.ToUpper(forkConfig.Network))); ok { - log.Info("detected rpc override", "name", forkConfig.Network, "url", url) + log.Info("detected rpc override", "name", forkConfig.Network) l1RpcUrl = url } @@ -69,7 +69,7 @@ func NetworkConfigFromForkCLIConfig(log log.Logger, envPrefix string, forkConfig l2RpcUrl := chainCfg.PublicRPC if url, ok := os.LookupEnv(fmt.Sprintf("%s_RPC_URL_%s", envPrefix, strings.ToUpper(chainCfg.Chain))); ok { - log.Info("detected rpc override", "name", chainCfg.Chain, "url", url) + log.Info("detected rpc override", "name", chainCfg.Chain) l2RpcUrl = url } diff --git a/supersim_test.go b/supersim_test.go index 76824c82..75647d8b 100644 --- a/supersim_test.go +++ b/supersim_test.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum-optimism/supersim/bindings" "github.com/ethereum-optimism/supersim/config" "github.com/ethereum-optimism/supersim/hdaccount" + "github.com/joho/godotenv" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi" @@ -79,6 +80,11 @@ type InteropTestSuite struct { } func createTestSuite(t *testing.T, cliConfig *config.CLIConfig) *TestSuite { + // Load the .env file + err := godotenv.Load() + if err != nil { + log.Crit("Error loading .env file", "err", err) + } testlog := testlog.Logger(t, log.LevelInfo) hdAccountStore, err := hdaccount.NewHdAccountStore(defaultTestMnemonic, defaultTestMnemonicDerivationPath) if err != nil { @@ -87,7 +93,7 @@ func createTestSuite(t *testing.T, cliConfig *config.CLIConfig) *TestSuite { } ctx, closeApp := context.WithCancelCause(context.Background()) - supersim, _ := NewSupersim(testlog, "", closeApp, cliConfig) + supersim, _ := NewSupersim(testlog, "SUPERSIM", closeApp, cliConfig) t.Cleanup(func() { closeApp(nil) if err := supersim.Stop(context.Background()); err != nil { @@ -108,7 +114,11 @@ func createTestSuite(t *testing.T, cliConfig *config.CLIConfig) *TestSuite { } } -func createForkedInteropTestSuite(t *testing.T) *InteropTestSuite { +type ForkInteropTestSuiteOptions struct { + interopAutoRelay bool +} + +func createForkedInteropTestSuite(t *testing.T, testOptions ForkInteropTestSuiteOptions) *InteropTestSuite { srcChain := "op" destChain := "base" cliConfig := &config.CLIConfig{ @@ -117,6 +127,7 @@ func createForkedInteropTestSuite(t *testing.T) *InteropTestSuite { Network: "mainnet", InteropEnabled: true, }, + InteropAutoRelay: testOptions.interopAutoRelay, } superchain := registry.Superchains[cliConfig.ForkConfig.Network] srcChainCfg := config.OPChainByName(superchain, srcChain) @@ -667,7 +678,7 @@ func TestInteropInvariantCheckBadBlockTimestamp(t *testing.T) { } func TestForkedInteropInvariantCheckSucceeds(t *testing.T) { - testSuite := createForkedInteropTestSuite(t) + testSuite := createForkedInteropTestSuite(t, ForkInteropTestSuiteOptions{interopAutoRelay: false}) privateKey, err := testSuite.HdAccountStore.DerivePrivateKeyAt(uint32(0)) require.NoError(t, err) @@ -820,3 +831,48 @@ func TestAutoRelaySuperchainWETHTransferSucceeds(t *testing.T) { diff := new(big.Int).Sub(destEndingBalance, destStartingBalance) require.Equal(t, valueToTransfer, diff) } + +func TestForkAutoRelaySuperchainWETHTransferSucceeds(t *testing.T) { + testSuite := createForkedInteropTestSuite(t, ForkInteropTestSuiteOptions{interopAutoRelay: true}) + + privateKey, err := testSuite.HdAccountStore.DerivePrivateKeyAt(uint32(0)) + require.NoError(t, err) + + sourceTransactor, err := bind.NewKeyedTransactorWithChainID(privateKey, testSuite.SourceChainID) + require.NoError(t, err) + + sourceSuperchainWETH, err := bindings.NewSuperchainWETH(common.HexToAddress(superchainWETHAddr), testSuite.SourceEthClient) + require.NoError(t, err) + + destSuperchainWETH, err := bindings.NewSuperchainWETH(common.HexToAddress(superchainWETHAddr), testSuite.DestEthClient) + require.NoError(t, err) + valueToTransfer := big.NewInt(10_000_000) + + sourceTransactor.Value = valueToTransfer + depositTx, err := sourceSuperchainWETH.Deposit(sourceTransactor) + require.NoError(t, err) + depositTxReceipt, err := bind.WaitMined(context.Background(), testSuite.SourceEthClient, depositTx) + require.NoError(t, err) + require.True(t, depositTxReceipt.Status == 1, "weth deposit transaction failed") + sourceTransactor.Value = nil + + destStartingBalance, err := destSuperchainWETH.BalanceOf(&bind.CallOpts{}, sourceTransactor.From) + require.NoError(t, err) + + _, err = sourceSuperchainWETH.BalanceOf(&bind.CallOpts{}, sourceTransactor.From) + require.NoError(t, err) + + tx, err := sourceSuperchainWETH.SendERC20(sourceTransactor, sourceTransactor.From, valueToTransfer, testSuite.DestChainID) + require.NoError(t, err) + + initiatingMessageTxReceipt, err := bind.WaitMined(context.Background(), testSuite.SourceEthClient, tx) + require.NoError(t, err) + require.True(t, initiatingMessageTxReceipt.Status == 1, "initiating message transaction failed") + + time.Sleep(time.Second * 4) + + destEndingBalance, err := destSuperchainWETH.BalanceOf(&bind.CallOpts{}, sourceTransactor.From) + require.NoError(t, err) + diff := new(big.Int).Sub(destEndingBalance, destStartingBalance) + require.Equal(t, valueToTransfer, diff) +} diff --git a/testutils/mockchain.go b/testutils/mockchain.go index cea4623f..2554d9fb 100644 --- a/testutils/mockchain.go +++ b/testutils/mockchain.go @@ -2,6 +2,7 @@ package testutils import ( "context" + "math/big" "github.com/ethereum-optimism/supersim/config" @@ -66,6 +67,10 @@ func (c *MockChain) SetCode(ctx context.Context, result interface{}, address com return nil } +func (c *MockChain) SetBalance(ctx context.Context, result interface{}, address common.Address, value *big.Int) error { + return nil +} + func (c *MockChain) SetStorageAt(ctx context.Context, result interface{}, address common.Address, storageSlot string, storageValue string) error { return nil }