diff --git a/bindings/L2ToL1MessagePasserExecuter.go b/bindings/L2ToL1MessagePasserExecuter.go index 2abee78b..5fe456dc 100644 --- a/bindings/L2ToL1MessagePasserExecuter.go +++ b/bindings/L2ToL1MessagePasserExecuter.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -45,7 +46,12 @@ func (e *L2ToL1MessagePasserExecuter) InitiateWithdrawal( return fmt.Errorf("create initiateWithdrawal data: %v", err) } - senderEthAddress := common.HexToAddress(sender) + // TODO: separate PR for withdrawal bug fix + senderCosmosAddress, err := sdk.AccAddressFromBech32(sender) + if err != nil { + return fmt.Errorf("convert sender to cosmos address: %v", err) + } + senderEthAddress := common.Address(senderCosmosAddress.Bytes()) _, err = e.Call(&monomerevm.CallParams{ Sender: &senderEthAddress, diff --git a/e2e/stack.go b/e2e/stack.go index be035de2..49ee6b8f 100644 --- a/e2e/stack.go +++ b/e2e/stack.go @@ -45,16 +45,17 @@ type EventListener interface { } type StackConfig struct { - Ctx context.Context - Operator L1User - Users []L1User - L1Client *L1Client - L1Portal *bindings.OptimismPortal - L2Client *bftclient.HTTP - MonomerClient *MonomerClient + Ctx context.Context + Operator L1User + Users []L1User + L1Client *L1Client + L1Portal *bindings.OptimismPortal + L2Client *bftclient.HTTP + L2OutputOracleCaller *bindings.L2OutputOracleCaller + MonomerClient *MonomerClient RollupConfig *rollup.Config - WaitL1 func(numBlocks int) error - WaitL2 func(numBlocks int) error + WaitL1 func(numBlocks int) error + WaitL2 func(numBlocks int) error } type stack struct { @@ -238,6 +239,11 @@ func (s *stack) run(ctx context.Context, env *environment.Env) (*StackConfig, er return nil, fmt.Errorf("new optimism portal: %v", err) } + l2OutputOracleCaller, err := bindings.NewL2OutputOracleCaller(l1Deployments.L2OutputOracleProxy, l1Client) + if err != nil { + return nil, fmt.Errorf("new l2 output oracle caller: %v", err) + } + opStack := NewOPStack( l1url, s.monomerEngineURL, @@ -291,13 +297,14 @@ func (s *stack) run(ctx context.Context, env *environment.Env) (*StackConfig, er } return &StackConfig{ - Ctx: ctx, - L1Client: l1Client, - L1Portal: opPortal, - L2Client: l2Client, - MonomerClient: monomerClient, - Operator: l1users[0], - Users: l1users[1:], + Ctx: ctx, + L1Client: l1Client, + L1Portal: opPortal, + L2Client: l2Client, + L2OutputOracleCaller: l2OutputOracleCaller, + MonomerClient: monomerClient, + Operator: l1users[0], + Users: l1users[1:], RollupConfig: rollupConfig, WaitL1: func(numBlocks int) error { return wait(numBlocks, 1) diff --git a/e2e/stack_test.go b/e2e/stack_test.go index 10f22095..6e920e52 100644 --- a/e2e/stack_test.go +++ b/e2e/stack_test.go @@ -9,11 +9,14 @@ import ( "path/filepath" "sync" "testing" + "time" + "cosmossdk.io/math" abcitypes "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/config" bftclient "github.com/cometbft/cometbft/rpc/client/http" bfttypes "github.com/cometbft/cometbft/types" + indexerbindings "github.com/ethereum-optimism/optimism/indexer/bindings" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -25,6 +28,7 @@ import ( "github.com/polymerdao/monomer/environment" "github.com/polymerdao/monomer/node" "github.com/polymerdao/monomer/testapp" + "github.com/polymerdao/monomer/utils" rolluptypes "github.com/polymerdao/monomer/x/rollup/types" "github.com/stretchr/testify/require" "golang.org/x/exp/slog" @@ -48,8 +52,8 @@ var e2eTests = []struct { run func(t *testing.T, stack *e2e.StackConfig) }{ { - name: "L1 Deposits", - run: depositE2E, + name: "L1 Deposits and L2 Withdrawals", + run: rollupFlow, }, { name: "CometBFT Txs", @@ -222,7 +226,7 @@ func cometBFTtx(t *testing.T, stack *e2e.StackConfig) { require.Len(t, txBlock.Transactions(), 2) // 1 deposit tx + 1 cometbft tx } -func depositE2E(t *testing.T, stack *e2e.StackConfig) { +func rollupFlow(t *testing.T, stack *e2e.StackConfig) { l1Client := stack.L1Client monomerClient := stack.MonomerClient @@ -237,16 +241,23 @@ func depositE2E(t *testing.T, stack *e2e.StackConfig) { user := stack.Users[0] l1signer := types.NewEIP155Signer(l1ChainID) - // send user Deposit Tx + ////////////////////// + ////// DEPOSITS ////// + ////////////////////// + + // TODO: helper func for getting latest user nonce and suggested gas price? nonce, err := l1Client.Client.NonceAt(stack.Ctx, user.Address, nil) require.NoError(t, err) - gasPrice, err := l1Client.Client.SuggestGasPrice(context.Background()) + gasPrice, err := l1Client.Client.SuggestGasPrice(stack.Ctx) require.NoError(t, err) l2GasLimit := l2blockGasLimit / 10 - l1GasLimit := l2GasLimit * 2 // must be higher than l2Gaslimit, because of l1 gas burn (cross-chain gas accounting) + //l1GasLimit := l2GasLimit * 2 // must be higher than l2Gaslimit, because of l1 gas burn (cross-chain gas accounting) + l1GasLimit := uint64(5_000_000) + // send user Deposit Tx + depositAmount := big.NewInt(oneEth / 2) depositTx, err := stack.L1Portal.DepositTransaction( &bind.TransactOpts{ From: user.Address, @@ -265,7 +276,7 @@ func depositE2E(t *testing.T, stack *e2e.StackConfig) { NoSend: false, }, user.Address, - big.NewInt(oneEth/2), // the "minting order" for L2 + depositAmount, // the "minting order" for L2 l2GasLimit, false, // _isCreation []byte{}, // no data @@ -282,7 +293,7 @@ func depositE2E(t *testing.T, stack *e2e.StackConfig) { receipt, err := l1Client.Client.TransactionReceipt(stack.Ctx, depositTx.Hash()) require.NoError(t, err, "deposit tx receipt") require.NotNil(t, receipt, "deposit tx receipt") - require.NotZero(t, receipt.Status, "deposit tx reverted") // receipt.Status == 0 -> reverted tx + require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "deposit tx reverted") depositLogs, err := stack.L1Portal.FilterTransactionDeposited( &bind.FilterOpts{ @@ -290,17 +301,227 @@ func depositE2E(t *testing.T, stack *e2e.StackConfig) { End: nil, Context: stack.Ctx, }, - nil, // from any address - nil, // to any address - nil, // any event version + []common.Address{user.Address}, + []common.Address{user.Address}, + []*big.Int{big.NewInt(0)}, ) require.NoError(t, err, "configuring 'TransactionDeposited' event listener") if !depositLogs.Next() { - require.FailNowf(t, "finding deposit event", "err: %w", depositLogs.Error()) + require.FailNowf(t, "finding deposit event", "err: %v", depositLogs.Error()) } - require.Equal(t, depositLogs.Event.From, user.Address) // user deposit has emitted L1 event1 + t.Log("Monomer can send user deposit txs on L1") + + err = depositLogs.Close() + require.NoError(t, err) requireEthIsMinted(t, stack.L2Client) + + ///////////////////////// + ////// WITHDRAWALS ////// + ///////////////////////// + + withdrawalTx := e2e.NewWithdrawalTx(0, user.Address, user.Address, depositAmount) + require.NoError(t, err) + withdrawalTxHash, err := withdrawalTx.Hash() + require.NoError(t, err) + + // initiate the withdrawal of the deposited amount on L2 + withdrawalTxResult, err := stack.L2Client.BroadcastTxAsync( + stack.Ctx, + testapp.ToWithdrawalTx(t, utils.EvmToCosmosAddress(*withdrawalTx.Sender).String(), withdrawalTx.Target.String(), math.NewIntFromBigInt(withdrawalTx.Value)), + ) + require.NoError(t, err) + require.Equal(t, abcitypes.CodeTypeOK, withdrawalTxResult.Code) + + // wait for tx to be processed + require.NoError(t, stack.WaitL2(1)) + + // TODO: rename requireEthIsBurned + l2BlockNumber := requireEthIsBurned(t, stack.L2Client) + + // TODO: should we listen for events here instead? + // TODO: helper func? + // wait for the L2 output containing the withdrawal tx to be proposed on L1 + l2OutputBlockNr, err := stack.L2OutputOracleCaller.LatestBlockNumber(&bind.CallOpts{}) + require.NoError(t, err) + // TODO: use channels instead for a timeout? + for l2OutputBlockNr.Cmp(l2BlockNumber) < 0 { + l2OutputBlockNr, err = stack.L2OutputOracleCaller.LatestBlockNumber(&bind.CallOpts{}) + require.NoError(t, err) + + time.Sleep(250 * time.Millisecond) + } + + nonce, err = l1Client.Client.NonceAt(stack.Ctx, user.Address, nil) + require.NoError(t, err) + + provenWithdrawalParams, err := e2e.ProveWithdrawalParameters(stack.Ctx, stack, *withdrawalTx, l2OutputBlockNr, stack.L2OutputOracleCaller) + require.NoError(t, err) + outputRootProof := provenWithdrawalParams.OutputRootProof + + // TODO: remove temp testing code + //stateRoot := string(outputRootProof.StateRoot[:]) + //fmt.Printf("stateRoot: %s\n", stateRoot) + //messagePasserStorageRoot := string(outputRootProof.MessagePasserStorageRoot[:]) + //fmt.Printf("messagePasserStorageRoot: %s\n", messagePasserStorageRoot) + //blockHash := string(outputRootProof.LatestBlockhash[:]) + //fmt.Printf("blockHash: %s\n", blockHash) + + proveWithdrawalTx, err := stack.L1Portal.ProveWithdrawalTransaction( + // TODO: make helper func for TransactOpts. maybe include nonce generation and gas price calculation too? + &bind.TransactOpts{ + From: user.Address, + Signer: func(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { + signed, err := types.SignTx(tx, l1signer, user.PrivateKey) + if err != nil { + return nil, err + } + return signed, nil + }, + Nonce: big.NewInt(int64(nonce)), + GasPrice: big.NewInt(gasPrice.Int64() * 2), + GasLimit: l1GasLimit, + Context: stack.Ctx, + NoSend: false, + }, + // TODO: add helper func for indexerbindings cast since it's used in multiple places + indexerbindings.TypesWithdrawalTransaction{ + Nonce: withdrawalTx.Nonce, + Sender: *withdrawalTx.Sender, + Target: *withdrawalTx.Target, + Value: withdrawalTx.Value, + GasLimit: withdrawalTx.GasLimit, + Data: withdrawalTx.Data, + }, + provenWithdrawalParams.L2OutputIndex, + indexerbindings.TypesOutputRootProof{ + Version: outputRootProof.Version, + StateRoot: outputRootProof.StateRoot, + MessagePasserStorageRoot: outputRootProof.MessagePasserStorageRoot, + LatestBlockhash: outputRootProof.LatestBlockhash, + }, + provenWithdrawalParams.WithdrawalProof, + ) + require.NoError(t, err, "prove withdrawal tx") + + // wait for withdrawal proving tx to be processed + require.NoError(t, stack.WaitL1(1)) + + // inspect L1 for withdrawal proving tx receipt and emitted WithdrawalProven event + receipt, err = l1Client.Client.TransactionReceipt(stack.Ctx, proveWithdrawalTx.Hash()) + require.NoError(t, err, "withdrawal proving tx receipt") + require.NotNil(t, receipt, "withdrawal proving tx receipt") + // TODO: remove! temp debugging to figure out why contract call is reverting + //l1portalAddress := common.HexToAddress("0x9A676e781A523b5d0C0e43731313A708CB607508") + //msg := ethereum.CallMsg{ + // To: &l1portalAddress, + // Data: proveWithdrawalTx.Data(), + //} + //_, err = stack.L1Client.CallContract(stack.Ctx, msg, receipt.BlockNumber) + //require.NoError(t, err, "call contract") + require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "withdrawal proving tx failed") + + proveWithdrawalLogs, err := stack.L1Portal.FilterWithdrawalProven( + // TODO: helper func for FilterOpts? maybe unnecessary since it's small + &bind.FilterOpts{ + Start: 0, + End: nil, + Context: stack.Ctx, + }, + [][32]byte{[32]byte(withdrawalTxHash.Bytes())}, + []common.Address{user.Address}, + []common.Address{*withdrawalTx.Target}, + ) + require.NoError(t, err, "configuring 'WithdrawalProven' event listener") + if !proveWithdrawalLogs.Next() { + require.FailNowf(t, "finding WithdrawalProven event", "err: %v", proveWithdrawalLogs.Error()) + } + t.Log("Monomer can prove withdrawals on L1") + + err = proveWithdrawalLogs.Close() + require.NoError(t, err) + + //l1Block, err := stack.L1Client.BlockByNumber(stack.Ctx, receipt.BlockNumber) + //require.NoError(t, err) + //fmt.Printf("l1Block time (proving): %v\n", l1Block.Time()) + //finalizationPeriod, err := l2OutputOracleCaller.FinalizationPeriodSeconds(&bind.CallOpts{}) + //fmt.Printf("finalizationPeriod: %v\n", finalizationPeriod) + + // wait for the withdrawal finalization period before sending the withdrawal finalizing tx + // TODO: maybe call isOutputFinalized func in OPPortal instead to see if output is finalized? + finalizationPeriod, err := stack.L2OutputOracleCaller.FinalizationPeriodSeconds(&bind.CallOpts{}) + require.NoError(t, err) + time.Sleep(time.Duration(finalizationPeriod.Uint64()) * time.Second) + + nonce, err = l1Client.Client.NonceAt(stack.Ctx, user.Address, nil) + require.NoError(t, err) + + finalizeWithdrawalTx, err := stack.L1Portal.FinalizeWithdrawalTransaction( + &bind.TransactOpts{ + From: user.Address, + Signer: func(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { + signed, err := types.SignTx(tx, l1signer, user.PrivateKey) + if err != nil { + return nil, err + } + return signed, nil + }, + Nonce: big.NewInt(int64(nonce)), + GasPrice: big.NewInt(gasPrice.Int64() * 2), + GasLimit: l1GasLimit, + Context: stack.Ctx, + NoSend: false, + }, indexerbindings.TypesWithdrawalTransaction{ + Nonce: withdrawalTx.Nonce, + Sender: *withdrawalTx.Sender, + Target: *withdrawalTx.Target, + Value: withdrawalTx.Value, + GasLimit: withdrawalTx.GasLimit, + Data: withdrawalTx.Data, + }) + require.Nil(t, err) + + // wait for withdrawal finalizing tx to be processed + require.NoError(t, stack.WaitL1(1)) + + // inspect L1 for withdrawal finalizing tx receipt and emitted WithdrawalFinalized event + receipt, err = l1Client.Client.TransactionReceipt(stack.Ctx, finalizeWithdrawalTx.Hash()) + require.NoError(t, err, "finalize withdrawal tx receipt") + require.NotNil(t, receipt, "finalize withdrawal tx receipt") + + // TODO: remove! temp debugging to figure out why contract call is reverting + //l1Block, err = stack.L1Client.BlockByNumber(stack.Ctx, nil) + //require.NoError(t, err) + //fmt.Printf("l1Block time (finalizing): %v\n", l1Block.Time()) + //l1portalAddress := common.HexToAddress("0x9A676e781A523b5d0C0e43731313A708CB607508") + //msg := ethereum.CallMsg{ + // To: &l1portalAddress, + // Data: finalizeWithdrawalTx.Data(), + //} + //callResult, err := stack.L1Client.CallContract(stack.Ctx, msg, receipt.BlockNumber) + //require.NoError(t, err, "call contract") + //fmt.Printf("call result: %v\n", callResult) + + require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "finalize withdrawal tx failed") + + finalizeWithdrawalLogs, err := stack.L1Portal.FilterWithdrawalFinalized( + // TODO: helper func for FilterOpts? maybe unnecessary since it's small + &bind.FilterOpts{ + Start: 0, + End: nil, + Context: stack.Ctx, + }, + [][32]byte{[32]byte(withdrawalTxHash.Bytes())}, + ) + require.NoError(t, err, "configuring 'WithdrawalFinalized' event listener") + if !finalizeWithdrawalLogs.Next() { + require.FailNowf(t, "finding WithdrawalFinalized event", "err: %v", finalizeWithdrawalLogs.Error()) + } + require.True(t, finalizeWithdrawalLogs.Event.Success, "withdrawal finalization failed") + t.Log("Monomer can finalize withdrawals on L1") + + err = finalizeWithdrawalLogs.Close() + require.NoError(t, err) } func requireEthIsMinted(t *testing.T, appchainClient *bftclient.HTTP) { @@ -325,5 +546,35 @@ func requireEthIsMinted(t *testing.T, appchainClient *bftclient.HTTP) { require.NoError(t, err, "search transactions") require.NotNil(t, result) require.NotEmpty(t, result.Txs, "mint_eth event not found") - t.Log("Monomer can mint_eth from L1 user deposits") + t.Log("Monomer can mint ETH for L1 user deposits") +} + +// TODO: refactor shared code with requireEthIsMinted +// TODO: rename func with returning block height? +func requireEthIsBurned(t *testing.T, appchainClient *bftclient.HTTP) *big.Int { + query := fmt.Sprintf( + "%s.%s='%s'", + rolluptypes.EventTypeBurnETH, + rolluptypes.AttributeKeyL2WithdrawalTx, + rolluptypes.EventTypeWithdrawalInitiated, + ) + page := 1 + perPage := 100 + orderBy := "desc" + + result, err := appchainClient.TxSearch( + // TODO: use stack.Ctx here and for mint func? + context.Background(), + query, + false, + &page, + &perPage, + orderBy, + ) + require.NoError(t, err, "search transactions") + require.NotNil(t, result) + require.NotEmpty(t, result.Txs, "burn_eth event not found") + t.Log("Monomer can burn ETH for L2 user withdrawals") + + return big.NewInt(result.Txs[0].Height) } diff --git a/e2e/withdrawal_helper.go b/e2e/withdrawal_helper.go new file mode 100644 index 00000000..6895d529 --- /dev/null +++ b/e2e/withdrawal_helper.go @@ -0,0 +1,110 @@ +package e2e + +import ( + "context" + "errors" + "fmt" + "math/big" + + "github.com/ethereum-optimism/optimism/indexer/bindings" + "github.com/ethereum-optimism/optimism/op-bindings/predeploys" + "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" + "github.com/ethereum-optimism/optimism/op-node/withdrawals" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +// ProvenWithdrawalParameters is the set of parameters to pass to the ProveWithdrawalTransaction +// and FinalizeWithdrawalTransaction functions +type ProvenWithdrawalParameters struct { + Nonce *big.Int + Sender common.Address + Target common.Address + Value *big.Int + GasLimit *big.Int + L2OutputIndex *big.Int + Data []byte + OutputRootProof bindings.TypesOutputRootProof + WithdrawalProof [][]byte // List of trie nodes to prove L2 storage +} + +// TODO: add documentation +// TODO: add note and link to the code that inspired this function +func ProveWithdrawalParameters(ctx context.Context, stack *StackConfig, withdrawalTx crossdomain.Withdrawal, l2BlockNumber *big.Int, l2OutputOracleContract *bindings.L2OutputOracleCaller) (ProvenWithdrawalParameters, error) { + l2OutputIndex, err := l2OutputOracleContract.GetL2OutputIndexAfter(&bind.CallOpts{}, l2BlockNumber) + if err != nil { + return ProvenWithdrawalParameters{}, fmt.Errorf("failed to get l2OutputIndex: %w", err) + } + + // Generate then verify the withdrawal proof + withdrawalHash, err := withdrawalTx.Hash() + if err != nil { + return ProvenWithdrawalParameters{}, err + } + + // Fetch the block from the monomer client + l2Block, err := stack.MonomerClient.BlockByNumber(ctx, l2BlockNumber) + if err != nil { + return ProvenWithdrawalParameters{}, fmt.Errorf("failed to fetch block %v from the monomer client: %w", l2BlockNumber, err) + } + + proof, err := stack.MonomerClient.GetProof(ctx, predeploys.L2ToL1MessagePasserAddr, []string{storageSlotOfWithdrawalHash(withdrawalHash).String()}, l2Block.Number()) + if err != nil { + return ProvenWithdrawalParameters{}, err + } + if len(proof.StorageProof) != 1 { + return ProvenWithdrawalParameters{}, errors.New("invalid amount of storage proofs") + } + + err = withdrawals.VerifyProof(l2Block.Root(), proof) + if err != nil { + return ProvenWithdrawalParameters{}, err + } + + // Encode it as expected by the contract + trieNodes := make([][]byte, len(proof.StorageProof[0].Proof)) + for i, s := range proof.StorageProof[0].Proof { + trieNodes[i] = common.FromHex(s) + } + + return ProvenWithdrawalParameters{ + Nonce: withdrawalTx.Nonce, + Sender: *withdrawalTx.Sender, + Target: *withdrawalTx.Target, + Value: withdrawalTx.Value, + GasLimit: withdrawalTx.GasLimit, + L2OutputIndex: l2OutputIndex, + Data: withdrawalTx.Data, + OutputRootProof: bindings.TypesOutputRootProof{ + Version: [32]byte{}, // Empty for version 1 + StateRoot: l2Block.Root(), + MessagePasserStorageRoot: proof.StorageHash, + LatestBlockhash: l2Block.Hash(), + }, + WithdrawalProof: trieNodes, + }, nil +} + +func NewWithdrawalTx(nonce int64, sender, target common.Address, value *big.Int) *crossdomain.Withdrawal { + return &crossdomain.Withdrawal{ + Nonce: crossdomain.EncodeVersionedNonce(big.NewInt(nonce), big.NewInt(1)), + Sender: &sender, + Target: &target, + Value: value, + // TODO: make gas limit configurable? + GasLimit: big.NewInt(100_000), + Data: []byte{}, + } +} + +// storageSlotOfWithdrawalHash determines the storage slot of the L2ToL1MessagePasser contract to look at +// given a WithdrawalHash +func storageSlotOfWithdrawalHash(hash common.Hash) common.Hash { + // The withdrawals mapping is the 0th storage slot in the L2ToL1MessagePasser contract. + // To determine the storage slot, use keccak256(withdrawalHash ++ p) + // Where p is the 32 byte value of the storage slot and ++ is concatenation + buf := make([]byte, 64) + copy(buf, hash[:]) + return crypto.Keccak256Hash(buf) +} diff --git a/evm/executer_test.go b/evm/executer_test.go index 021fa5d7..0edd0fa4 100644 --- a/evm/executer_test.go +++ b/evm/executer_test.go @@ -4,6 +4,7 @@ import ( "math/big" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" @@ -37,12 +38,15 @@ func TestL2ApplicationStateRootProviderExecuter(t *testing.T) { require.Equal(t, newStateRoot, gotStateRoot) } +// TODO: separate PR for withdrawal bug fix func TestL2ToL1MessagePasserExecuter(t *testing.T) { executer, err := bindings.NewL2ToL1MessagePasserExecuter(setupEVM(t)) require.NoError(t, err) - cosmosSenderAddr := "abcdef12345" - ethSenderAddr := common.HexToAddress(cosmosSenderAddr) + cosmosSenderAddr, err := sdk.AccAddressFromBech32("cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh") + require.NoError(t, err) + + ethSenderAddr := common.BytesToAddress(cosmosSenderAddr.Bytes()) amount := big.NewInt(500) l1TargetAddress := common.HexToAddress("0x12345abcdef") gasLimit := big.NewInt(100_000) @@ -70,7 +74,7 @@ func TestL2ToL1MessagePasserExecuter(t *testing.T) { require.Equal(t, nonce, initialMessageNonce) // Initiate a withdrawal - err = executer.InitiateWithdrawal(cosmosSenderAddr, amount, l1TargetAddress, gasLimit, data) + err = executer.InitiateWithdrawal(cosmosSenderAddr.String(), amount, l1TargetAddress, gasLimit, data) require.NoError(t, err) // Check that the withdrawal hash is in the sentMessages mapping diff --git a/testapp/helpers.go b/testapp/helpers.go index a25a2852..afe34ccb 100644 --- a/testapp/helpers.go +++ b/testapp/helpers.go @@ -3,6 +3,7 @@ package testapp import ( "context" "encoding/json" + "math/big" "slices" "testing" @@ -64,10 +65,12 @@ func ToTestTx(t *testing.T, k, v string) []byte { func ToWithdrawalTx(t *testing.T, cosmosAddr string, ethAddr string, amount math.Int) []byte { return toTx(t, &rolluptypes.MsgInitiateWithdrawal{ - Sender: cosmosAddr, - Target: ethAddr, - Value: amount, - GasLimit: []byte{0xff, 0xff, 0xff, 0xff, 0xff}, + Sender: cosmosAddr, + Target: ethAddr, + Value: amount, + // TODO: make gas limit configurable? + //GasLimit: []byte{0xff, 0xff, 0xff, 0xff, 0xff}, + GasLimit: big.NewInt(100_000).Bytes(), Data: []byte{}, }) }