From d6ed9aa5ce5862f9ff90cb34669cdf1e5b228826 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Wed, 13 Nov 2024 11:38:11 -0800 Subject: [PATCH 01/15] test: fix evm signer instability (#3133) * test: fix evm signer instability * fix * coderabbit feedback --- zetaclient/chains/evm/signer/sign_test.go | 33 +++++++--------- .../chains/evm/signer/signer_admin_test.go | 39 ++++++++----------- zetaclient/chains/evm/signer/signer_test.go | 17 ++++---- zetaclient/testutils/mocks/tss_signer.go | 10 +++++ 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/zetaclient/chains/evm/signer/sign_test.go b/zetaclient/chains/evm/signer/sign_test.go index 5123968573..c3d64ebabc 100644 --- a/zetaclient/chains/evm/signer/sign_test.go +++ b/zetaclient/chains/evm/signer/sign_test.go @@ -8,6 +8,7 @@ import ( "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/zetaclient/testutils/mocks" ) @@ -15,7 +16,7 @@ func TestSigner_SignConnectorOnReceive(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -33,8 +34,7 @@ func TestSigner_SignConnectorOnReceive(t *testing.T) { require.NoError(t, err) // Verify Signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) }) t.Run("SignConnectorOnReceive - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail @@ -53,8 +53,7 @@ func TestSigner_SignConnectorOnReceive(t *testing.T) { require.NoError(t, err) // Verify Signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // check that by default tx type is legacy tx assert.Equal(t, ethtypes.LegacyTxType, int(tx.Type())) @@ -86,7 +85,7 @@ func TestSigner_SignConnectorOnReceive(t *testing.T) { require.NoError(t, err) // ASSERT - verifyTxSignature(t, tx, mocks.NewTSSMainnet().Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // check that by default tx type is a dynamic fee tx assert.Equal(t, ethtypes.DynamicFeeTxType, int(tx.Type())) @@ -101,7 +100,7 @@ func TestSigner_SignConnectorOnRevert(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -118,8 +117,7 @@ func TestSigner_SignConnectorOnRevert(t *testing.T) { require.NoError(t, err) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Revert tx calls connector contract with 0 gas token @@ -140,7 +138,7 @@ func TestSigner_SignCancel(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -157,12 +155,11 @@ func TestSigner_SignCancel(t *testing.T) { require.NoError(t, err) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Cancel tx sends 0 gas token to TSS self address - verifyTxBodyBasics(t, tx, evmSigner.TSS().EVMAddress(), txData.nonce, big.NewInt(0)) + verifyTxBodyBasics(t, tx, tss.EVMAddress(), txData.nonce, big.NewInt(0)) }) t.Run("SignCancel - should fail if keysign fails", func(t *testing.T) { // Pause tss to make keysign fail @@ -179,7 +176,7 @@ func TestSigner_SignGasWithdraw(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -196,8 +193,7 @@ func TestSigner_SignGasWithdraw(t *testing.T) { require.NoError(t, err) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, txData.amount) @@ -217,7 +213,7 @@ func TestSigner_SignERC20Withdraw(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -233,8 +229,7 @@ func TestSigner_SignERC20Withdraw(t *testing.T) { require.NoError(t, err) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Withdraw tx calls erc20 custody contract with 0 gas token diff --git a/zetaclient/chains/evm/signer/signer_admin_test.go b/zetaclient/chains/evm/signer/signer_admin_test.go index 6b43653ffb..e5896edcc2 100644 --- a/zetaclient/chains/evm/signer/signer_admin_test.go +++ b/zetaclient/chains/evm/signer/signer_admin_test.go @@ -7,6 +7,7 @@ import ( "github.com/rs/zerolog" "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/constant" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/zetaclient/testutils/mocks" @@ -16,7 +17,8 @@ func TestSigner_SignAdminTx(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - evmSigner, err := getNewEvmSigner(nil) + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) + evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) // Setup txData struct @@ -36,8 +38,7 @@ func TestSigner_SignAdminTx(t *testing.T) { require.NoError(t, err) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Revert tx calls erc20 custody contract with 0 gas token @@ -57,8 +58,7 @@ func TestSigner_SignAdminTx(t *testing.T) { require.NoError(t, err) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Revert tx calls erc20 custody contract with 0 gas token @@ -73,8 +73,7 @@ func TestSigner_SignAdminTx(t *testing.T) { require.NoError(t, err) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics // Note: Revert tx calls erc20 custody contract with 0 gas token @@ -88,8 +87,7 @@ func TestSigner_SignAdminTx(t *testing.T) { require.NoError(t, err) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, txData.amount) @@ -100,7 +98,7 @@ func TestSigner_SignWhitelistERC20Cmd(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -121,8 +119,7 @@ func TestSigner_SignWhitelistERC20Cmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, zeroValue) @@ -149,7 +146,7 @@ func TestSigner_SignMigrateERC20CustodyFundsCmd(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -178,8 +175,7 @@ func TestSigner_SignMigrateERC20CustodyFundsCmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, zeroValue) @@ -215,7 +211,7 @@ func TestSigner_SignUpdateERC20CustodyPauseStatusCmd(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -238,8 +234,7 @@ func TestSigner_SignUpdateERC20CustodyPauseStatusCmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, zeroValue) @@ -255,8 +250,7 @@ func TestSigner_SignUpdateERC20CustodyPauseStatusCmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, zeroValue) @@ -293,7 +287,7 @@ func TestSigner_SignMigrateTssFundsCmd(t *testing.T) { ctx := makeCtx(t) // Setup evm signer - tss := mocks.NewTSSMainnet() + tss := mocks.NewDerivedTSS(chains.BitcoinMainnet) evmSigner, err := getNewEvmSigner(tss) require.NoError(t, err) @@ -313,8 +307,7 @@ func TestSigner_SignMigrateTssFundsCmd(t *testing.T) { require.NotNil(t, tx) // Verify tx signature - tss := mocks.NewTSSMainnet() - verifyTxSignature(t, tx, tss.Pubkey(), evmSigner.EvmSigner()) + verifyTxSender(t, tx, tss.EVMAddress(), evmSigner.EvmSigner()) // Verify tx body basics verifyTxBodyBasics(t, tx, txData.to, txData.nonce, txData.amount) diff --git a/zetaclient/chains/evm/signer/signer_test.go b/zetaclient/chains/evm/signer/signer_test.go index b2c266b438..43577b475d 100644 --- a/zetaclient/chains/evm/signer/signer_test.go +++ b/zetaclient/chains/evm/signer/signer_test.go @@ -8,7 +8,6 @@ import ( sdktypes "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/rs/zerolog" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -113,14 +112,14 @@ func getInvalidCCTX(t *testing.T) *crosschaintypes.CrossChainTx { return cctx } -// verifyTxSignature is a helper function to verify the signature of a transaction -func verifyTxSignature(t *testing.T, tx *ethtypes.Transaction, tssPubkey []byte, signer ethtypes.Signer) { - _, r, s := tx.RawSignatureValues() - signature := append(r.Bytes(), s.Bytes()...) - hash := signer.Hash(tx) - - verified := crypto.VerifySignature(tssPubkey, hash.Bytes(), signature) - require.True(t, verified) +// verifyTxSender is a helper function to verify the signature of a transaction +// +// signer.Sender() will ecrecover the public key of the transaction internally +// and will fail if the transaction is not valid or has been tampered with +func verifyTxSender(t *testing.T, tx *ethtypes.Transaction, expectedSender ethcommon.Address, signer ethtypes.Signer) { + senderAddr, err := signer.Sender(tx) + require.NoError(t, err) + require.Equal(t, expectedSender.String(), senderAddr.String()) } // verifyTxBodyBasics is a helper function to verify 'to', 'nonce' and 'amount' of a transaction diff --git a/zetaclient/testutils/mocks/tss_signer.go b/zetaclient/testutils/mocks/tss_signer.go index 78ce36649a..3fa003a3c0 100644 --- a/zetaclient/testutils/mocks/tss_signer.go +++ b/zetaclient/testutils/mocks/tss_signer.go @@ -63,6 +63,16 @@ func NewTSSAthens3() *TSS { return NewMockTSS(chains.BscTestnet, testutils.TSSAddressEVMAthens3, testutils.TSSAddressBTCAthens3) } +// NewDerivedTSS creates a TSS where evmAddress and btcAdresses are always derived from the test +// private key +func NewDerivedTSS(chain chains.Chain) *TSS { + return &TSS{ + paused: false, + chain: chain, + PrivKey: TestPrivateKey, + } +} + func NewGeneratedTSS(t *testing.T, chain chains.Chain) *TSS { pk, err := crypto.GenerateKey() require.NoError(t, err) From 07120f14f6403e2f6b651eef576598e61d76f187 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:30:03 -0600 Subject: [PATCH 02/15] test: configure Solana gateway program id for E2E tests (#3154) * configure Solana gateway program id in E2E test * add changelog entry --- changelog.md | 1 + cmd/zetae2e/config/config.go | 2 +- cmd/zetae2e/config/contracts.go | 3 +-- cmd/zetae2e/config/local.yml | 5 ++++- cmd/zetae2e/config/localnet.yml | 6 +++++- cmd/zetae2e/local/local.go | 5 ++++- e2e/config/config.go | 2 +- e2e/runner/setup_solana.go | 6 +++--- e2e/runner/solana.go | 6 ++---- pkg/contracts/solana/gateway.go | 9 ++++++--- pkg/contracts/solana/inbound_test.go | 4 ++-- zetaclient/chains/solana/observer/inbound_test.go | 2 +- zetaclient/orchestrator/orchestrator_test.go | 5 ++--- zetaclient/testutils/constant.go | 10 ++++++---- 14 files changed, 39 insertions(+), 27 deletions(-) diff --git a/changelog.md b/changelog.md index 244bc9d08d..07b7d10bc5 100644 --- a/changelog.md +++ b/changelog.md @@ -12,6 +12,7 @@ * [3075](https://github.com/zeta-chain/node/pull/3075) - ton: withdraw concurrent, deposit & revert. * [3105](https://github.com/zeta-chain/node/pull/3105) - split Bitcoin E2E tests into two runners for deposit and withdraw +* [3154](https://github.com/zeta-chain/node/pull/3154) - configure Solana gateway program id for E2E tests ### Refactor * [3118](https://github.com/zeta-chain/node/pull/3118) - zetaclient: remove hsm signer diff --git a/cmd/zetae2e/config/config.go b/cmd/zetae2e/config/config.go index 65e5418f53..cffee5943b 100644 --- a/cmd/zetae2e/config/config.go +++ b/cmd/zetae2e/config/config.go @@ -55,7 +55,7 @@ func RunnerFromConfig( // ExportContractsFromRunner export contracts from the runner to config using a source config func ExportContractsFromRunner(r *runner.E2ERunner, conf config.Config) config.Config { // copy contracts from deployer runner - conf.Contracts.Solana.GatewayProgramID = r.GatewayProgram.String() + conf.Contracts.Solana.GatewayProgramID = config.DoubleQuotedString(r.GatewayProgram.String()) conf.Contracts.Solana.SPLAddr = config.DoubleQuotedString(r.SPLAddr.String()) conf.Contracts.EVM.ZetaEthAddr = config.DoubleQuotedString(r.ZetaEthAddr.Hex()) diff --git a/cmd/zetae2e/config/contracts.go b/cmd/zetae2e/config/contracts.go index 5c46cdc047..6b508096b5 100644 --- a/cmd/zetae2e/config/contracts.go +++ b/cmd/zetae2e/config/contracts.go @@ -31,7 +31,7 @@ func setContractsFromConfig(r *runner.E2ERunner, conf config.Config) error { // set Solana contracts if c := conf.Contracts.Solana.GatewayProgramID; c != "" { - r.GatewayProgram = solana.MustPublicKeyFromBase58(c) + r.GatewayProgram = solana.MustPublicKeyFromBase58(c.String()) } if c := conf.Contracts.Solana.SPLAddr; c != "" { @@ -242,7 +242,6 @@ func setContractsFromConfig(r *runner.E2ERunner, conf config.Config) error { } // v2 contracts - if c := conf.Contracts.EVM.Gateway; c != "" { r.GatewayEVMAddr, err = c.AsEVMAddress() if err != nil { diff --git a/cmd/zetae2e/config/local.yml b/cmd/zetae2e/config/local.yml index 5cc87be394..e4ec147e49 100644 --- a/cmd/zetae2e/config/local.yml +++ b/cmd/zetae2e/config/local.yml @@ -116,4 +116,7 @@ contracts: custody: "0xff3135df4F2775f4091b81f4c7B6359CfA07862a" erc20: "0xbD1e64A22B9F92D9Ce81aA9B4b0fFacd80215564" test_dapp: "0xBFF76e77D56B3C1202107f059425D56f0AEF87Ed" - gateway: "0xF0deebCB0E9C829519C4baa794c5445171973826" \ No newline at end of file + gateway: "0xF0deebCB0E9C829519C4baa794c5445171973826" + solana: + gateway_program_id: "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d" + spl: "" \ No newline at end of file diff --git a/cmd/zetae2e/config/localnet.yml b/cmd/zetae2e/config/localnet.yml index 24e51223ef..15f1e332f6 100644 --- a/cmd/zetae2e/config/localnet.yml +++ b/cmd/zetae2e/config/localnet.yml @@ -98,4 +98,8 @@ rpcs: ton_sidecar_url: "http://ton:8000" zetacore_grpc: "zetacore0:9090" zetacore_rpc: "http://zetacore0:26657" -# contracts will be populated on first run +contracts: +# configure localnet solana gateway program id + solana: + gateway_program_id: "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d" + spl: "" \ No newline at end of file diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 5507d95014..6dc466cef8 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -224,7 +224,10 @@ func localE2ETest(cmd *cobra.Command, _ []string) { deployerRunner.SetupEVMV2() if testSolana { - deployerRunner.SetupSolana(conf.AdditionalAccounts.UserSolana.SolanaPrivateKey.String()) + deployerRunner.SetupSolana( + conf.Contracts.Solana.GatewayProgramID.String(), + conf.AdditionalAccounts.UserSolana.SolanaPrivateKey.String(), + ) } deployerRunner.SetZEVMSystemContracts() diff --git a/e2e/config/config.go b/e2e/config/config.go index 33a8c2bea8..22382c1fa1 100644 --- a/e2e/config/config.go +++ b/e2e/config/config.go @@ -120,7 +120,7 @@ type Contracts struct { // Solana contains the addresses of predeployed contracts and accounts on the Solana chain type Solana struct { - GatewayProgramID string `yaml:"gateway_program_id"` + GatewayProgramID DoubleQuotedString `yaml:"gateway_program_id"` SPLAddr DoubleQuotedString `yaml:"spl"` } diff --git a/e2e/runner/setup_solana.go b/e2e/runner/setup_solana.go index 1a46326d02..28a4fb65fa 100644 --- a/e2e/runner/setup_solana.go +++ b/e2e/runner/setup_solana.go @@ -27,11 +27,11 @@ func (r *E2ERunner) SetupSolanaAccount() { } // SetupSolana sets Solana contracts and params -func (r *E2ERunner) SetupSolana(deployerPrivateKey string) { +func (r *E2ERunner) SetupSolana(gatewayID, deployerPrivateKey string) { r.Logger.Print("⚙️ initializing gateway program on Solana") // set Solana contracts - r.GatewayProgram = solana.MustPublicKeyFromBase58(solanacontracts.SolanaGatewayProgramID) + r.GatewayProgram = solana.MustPublicKeyFromBase58(gatewayID) // get deployer account balance privkey, err := solana.PrivateKeyFromBase58(deployerPrivateKey) @@ -141,7 +141,7 @@ func (r *E2ERunner) ensureSolanaChainParams() error { BallotThreshold: observertypes.DefaultBallotThreshold, MinObserverDelegation: observertypes.DefaultMinObserverDelegation, IsSupported: true, - GatewayAddress: solanacontracts.SolanaGatewayProgramID, + GatewayAddress: r.GatewayProgram.String(), } updateMsg := observertypes.NewMsgUpdateChainParams(creator, chainParams) diff --git a/e2e/runner/solana.go b/e2e/runner/solana.go index d395c60d76..380219dee4 100644 --- a/e2e/runner/solana.go +++ b/e2e/runner/solana.go @@ -21,8 +21,7 @@ import ( // ComputePdaAddress computes the PDA address for the gateway program func (r *E2ERunner) ComputePdaAddress() solana.PublicKey { seed := []byte(solanacontract.PDASeed) - GatewayProgramID := solana.MustPublicKeyFromBase58(solanacontract.SolanaGatewayProgramID) - pdaComputed, bump, err := solana.FindProgramAddress([][]byte{seed}, GatewayProgramID) + pdaComputed, bump, err := solana.FindProgramAddress([][]byte{seed}, r.GatewayProgram) require.NoError(r, err) r.Logger.Info("computed pda: %s, bump %d\n", pdaComputed, bump) @@ -33,8 +32,7 @@ func (r *E2ERunner) ComputePdaAddress() solana.PublicKey { // SolanaRentPayerPDA computes the rent payer PDA (Program Derived Address) address for the gateway program func (r *E2ERunner) SolanaRentPayerPDA() solana.PublicKey { seed := []byte(solanacontract.RentPayerPDASeed) - GatewayProgramID := solana.MustPublicKeyFromBase58(solanacontract.SolanaGatewayProgramID) - pdaComputed, bump, err := solana.FindProgramAddress([][]byte{seed}, GatewayProgramID) + pdaComputed, bump, err := solana.FindProgramAddress([][]byte{seed}, r.GatewayProgram) require.NoError(r, err) r.Logger.Info("computed rent payer pda: %s, bump %d\n", pdaComputed, bump) diff --git a/pkg/contracts/solana/gateway.go b/pkg/contracts/solana/gateway.go index bf674aa081..7465893149 100644 --- a/pkg/contracts/solana/gateway.go +++ b/pkg/contracts/solana/gateway.go @@ -8,9 +8,6 @@ import ( ) const ( - // SolanaGatewayProgramID is the program ID of the Solana gateway program - SolanaGatewayProgramID = "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d" - // PDASeed is the seed for the Solana gateway program derived address PDASeed = "meta" @@ -29,16 +26,22 @@ const ( var ( // DiscriminatorInitialize returns the discriminator for Solana gateway 'initialize' instruction DiscriminatorInitialize = idlgateway.IDLGateway.GetDiscriminator("initialize") + // DiscriminatorInitializeRentPayer returns the discriminator for Solana gateway 'initialize_rent_payer' instruction DiscriminatorInitializeRentPayer = idlgateway.IDLGateway.GetDiscriminator("initialize_rent_payer") + // DiscriminatorDeposit returns the discriminator for Solana gateway 'deposit' instruction DiscriminatorDeposit = idlgateway.IDLGateway.GetDiscriminator("deposit") + // DiscriminatorDepositSPL returns the discriminator for Solana gateway 'deposit_spl_token' instruction DiscriminatorDepositSPL = idlgateway.IDLGateway.GetDiscriminator("deposit_spl_token") + // DiscriminatorWithdraw returns the discriminator for Solana gateway 'withdraw' instruction DiscriminatorWithdraw = idlgateway.IDLGateway.GetDiscriminator("withdraw") + // DiscriminatorWithdrawSPL returns the discriminator for Solana gateway 'withdraw_spl_token' instruction DiscriminatorWithdrawSPL = idlgateway.IDLGateway.GetDiscriminator("withdraw_spl_token") + // DiscriminatorWhitelist returns the discriminator for Solana gateway 'whitelist_spl_mint' instruction DiscriminatorWhitelistSplMint = idlgateway.IDLGateway.GetDiscriminator("whitelist_spl_mint") ) diff --git a/pkg/contracts/solana/inbound_test.go b/pkg/contracts/solana/inbound_test.go index 00bb17f994..7b19badf7a 100644 --- a/pkg/contracts/solana/inbound_test.go +++ b/pkg/contracts/solana/inbound_test.go @@ -47,7 +47,7 @@ func Test_ParseInboundAsDeposit(t *testing.T) { // create observer chainParams := sample.ChainParams(chain.ChainId) - chainParams.GatewayAddress = testutils.GatewayAddresses[chain.ChainId] + chainParams.GatewayAddress = testutils.OldSolanaGatewayAddressDevnet require.NoError(t, err) // expected result @@ -79,7 +79,7 @@ func Test_ParseInboundAsDepositSPL(t *testing.T) { // create observer chainParams := sample.ChainParams(chain.ChainId) - chainParams.GatewayAddress = testutils.GatewayAddresses[chain.ChainId] + chainParams.GatewayAddress = testutils.OldSolanaGatewayAddressDevnet // expected result // solana e2e deployer account diff --git a/zetaclient/chains/solana/observer/inbound_test.go b/zetaclient/chains/solana/observer/inbound_test.go index c38d3ae281..28c31f04db 100644 --- a/zetaclient/chains/solana/observer/inbound_test.go +++ b/zetaclient/chains/solana/observer/inbound_test.go @@ -71,7 +71,7 @@ func Test_FilterInboundEvents(t *testing.T) { // create observer chainParams := sample.ChainParams(chain.ChainId) - chainParams.GatewayAddress = testutils.GatewayAddresses[chain.ChainId] + chainParams.GatewayAddress = testutils.OldSolanaGatewayAddressDevnet ob, err := observer.NewObserver(chain, nil, *chainParams, nil, nil, 60, database, base.DefaultLogger(), nil) require.NoError(t, err) diff --git a/zetaclient/orchestrator/orchestrator_test.go b/zetaclient/orchestrator/orchestrator_test.go index b86e85cc15..4b85ccbb03 100644 --- a/zetaclient/orchestrator/orchestrator_test.go +++ b/zetaclient/orchestrator/orchestrator_test.go @@ -14,7 +14,6 @@ import ( "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" - solanacontracts "github.com/zeta-chain/node/pkg/contracts/solana" "github.com/zeta-chain/node/testutil/sample" crosschainkeeper "github.com/zeta-chain/node/x/crosschain/keeper" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" @@ -41,7 +40,7 @@ func Test_GetUpdatedSigner(t *testing.T) { tonChainParams = mocks.MockChainParams(tonChain.ChainId, 100) ) - solChainParams.GatewayAddress = solanacontracts.SolanaGatewayProgramID + solChainParams.GatewayAddress = testutils.GatewayAddresses[solChain.ChainId] // new chain params in AppContext evmChainParamsNew := mocks.MockChainParams(evmChainParams.ChainId, 100) @@ -126,7 +125,7 @@ func Test_GetUpdatedChainObserver(t *testing.T) { tonChainParams = mocks.MockChainParams(tonChain.ChainId, 100) ) - solChainParams.GatewayAddress = solanacontracts.SolanaGatewayProgramID + solChainParams.GatewayAddress = testutils.GatewayAddresses[solChain.ChainId] tonChainParams.GatewayAddress = sample.GenerateTONAccountID().ToRaw() // new chain params in AppContext diff --git a/zetaclient/testutils/constant.go b/zetaclient/testutils/constant.go index f776c7019f..304cd859c3 100644 --- a/zetaclient/testutils/constant.go +++ b/zetaclient/testutils/constant.go @@ -39,12 +39,14 @@ const ( EventERC20Withdraw = "Withdrawn" ) +// OldSolanaGatewayAddressDevnet is the old gateway address deployed on Solana devnet +const OldSolanaGatewayAddressDevnet = "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d" + // GatewayAddresses contains constants gateway addresses for testing var GatewayAddresses = map[int64]string{ - // Gateway address on Solana devnet - // NOTE: currently different deployer key pair is used for development compared to live networks - // as live networks key pair is sensitive information at this point, can be unified once we have deployments completed - chains.SolanaDevnet.ChainId: "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d", + // Solana gateway addresses + chains.SolanaDevnet.ChainId: "ZETAjseVjuFsxdRxo6MmTCvqFwb3ZHUx56Co3vCmGis", + chains.SolanaMainnet.ChainId: "ZETAjseVjuFsxdRxo6MmTCvqFwb3ZHUx56Co3vCmGis", } // ConnectorAddresses contains constants ERC20 connector addresses for testing From 420f83a25ff17eafd573aab32844fc28f5487d99 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:35:24 -0600 Subject: [PATCH 03/15] fix: abort cctx on dust amount in revert outbound (Bitcoin and Solana) (#3149) * fix dust amount for revert case in Bitcoin and Solana * add changelog entry for the fix * verify dust amount in the CCTX revert outbound * add error message check for aborted CCTX caused by dust amount * Update changelog.md Co-authored-by: Tanmay --------- Co-authored-by: Tanmay --- changelog.md | 1 + cmd/zetae2e/local/local.go | 3 +- e2e/e2etests/e2etests.go | 33 +++++++++++------- ...tcoin_deposit_and_call_revert_with_dust.go | 18 +++++----- ...olana_deposit_and_call_revert_with_dust.go | 34 +++++++++++++++++++ e2e/e2etests/test_solana_deposit_refund.go | 4 +-- e2e/utils/zetacore.go | 14 ++++++++ .../cctx_orchestrator_validate_outbound.go | 13 +++++++ 8 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 e2e/e2etests/test_solana_deposit_and_call_revert_with_dust.go diff --git a/changelog.md b/changelog.md index 07b7d10bc5..4facc05f04 100644 --- a/changelog.md +++ b/changelog.md @@ -26,6 +26,7 @@ * [3041](https://github.com/zeta-chain/node/pull/3041) - replace libp2p public DHT with private gossip peer discovery and connection gater for inbound connections * [3106](https://github.com/zeta-chain/node/pull/3106) - prevent blocked CCTX on out of gas during omnichain calls * [3139](https://github.com/zeta-chain/node/pull/3139) - fix config resolution in orchestrator +* [3149](https://github.com/zeta-chain/node/pull/3149) - abort the cctx if dust amount is detected in the revert outbound ## v21.0.0 diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 6dc466cef8..a752c0e388 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -436,7 +436,8 @@ func localE2ETest(cmd *cobra.Command, _ []string) { e2etests.TestSolanaDepositName, e2etests.TestSolanaWithdrawName, e2etests.TestSolanaDepositAndCallName, - e2etests.TestSolanaDepositAndCallRefundName, + e2etests.TestSolanaDepositAndCallRevertName, + e2etests.TestSolanaDepositAndCallRevertWithDustName, e2etests.TestSolanaDepositRestrictedName, e2etests.TestSolanaWithdrawRestrictedName, // TODO move under admin tests diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index ee4b8d92ce..52c7022be5 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -55,16 +55,17 @@ const ( /* * Solana tests */ - TestSolanaDepositName = "solana_deposit" - TestSolanaWithdrawName = "solana_withdraw" - TestSolanaDepositAndCallName = "solana_deposit_and_call" - TestSolanaDepositAndCallRefundName = "solana_deposit_and_call_refund" - TestSolanaDepositRestrictedName = "solana_deposit_restricted" - TestSolanaWithdrawRestrictedName = "solana_withdraw_restricted" - TestSPLDepositName = "spl_deposit" - TestSPLDepositAndCallName = "spl_deposit_and_call" - TestSPLWithdrawName = "spl_withdraw" - TestSPLWithdrawAndCreateReceiverAtaName = "spl_withdraw_and_create_receiver_ata" + TestSolanaDepositName = "solana_deposit" + TestSolanaWithdrawName = "solana_withdraw" + TestSolanaDepositAndCallName = "solana_deposit_and_call" + TestSolanaDepositAndCallRevertName = "solana_deposit_and_call_revert" + TestSolanaDepositAndCallRevertWithDustName = "solana_deposit_and_call_revert_with_dust" + TestSolanaDepositRestrictedName = "solana_deposit_restricted" + TestSolanaWithdrawRestrictedName = "solana_withdraw_restricted" + TestSPLDepositName = "spl_deposit" + TestSPLDepositAndCallName = "spl_deposit_and_call" + TestSPLWithdrawName = "spl_withdraw" + TestSPLWithdrawAndCreateReceiverAtaName = "spl_withdraw_and_create_receiver_ata" /** * TON tests @@ -453,12 +454,18 @@ var AllE2ETests = []runner.E2ETest{ TestSPLWithdrawAndCreateReceiverAta, ), runner.NewE2ETest( - TestSolanaDepositAndCallRefundName, - "deposit SOL into ZEVM and call a contract that reverts; should refund", + TestSolanaDepositAndCallRevertName, + "deposit SOL into ZEVM and call a contract that reverts", []runner.ArgDefinition{ {Description: "amount in lamport", DefaultValue: "1200000"}, }, - TestSolanaDepositAndCallRefund, + TestSolanaDepositAndCallRevert, + ), + runner.NewE2ETest( + TestSolanaDepositAndCallRevertWithDustName, + "deposit SOL into ZEVM; revert with dust amount that aborts the CCTX", + []runner.ArgDefinition{}, + TestSolanaDepositAndCallRevertWithDust, ), runner.NewE2ETest( TestSolanaDepositRestrictedName, diff --git a/e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go b/e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go index 1dec399a9b..cc5f5451dc 100644 --- a/e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go +++ b/e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go @@ -1,6 +1,8 @@ package e2etests import ( + "strings" + "github.com/stretchr/testify/require" "github.com/zeta-chain/node/e2e/runner" @@ -38,16 +40,14 @@ func TestBitcoinDepositAndCallRevertWithDust(r *runner.E2ERunner, args []string) // Send BTC to TSS address with a dummy memo // zetacore should revert cctx if call is made on a non-existing address nonExistReceiver := sample.EthAddress() - badMemo := append(nonExistReceiver.Bytes(), []byte("gibberish-memo")...) - txHash, err := r.SendToTSSFromDeployerWithMemo(amount, utxos, badMemo) + anyMemo := append(nonExistReceiver.Bytes(), []byte("gibberish-memo")...) + txHash, err := r.SendToTSSFromDeployerWithMemo(amount, utxos, anyMemo) require.NoError(r, err) require.NotEmpty(r, txHash) - // wait for the cctx to be mined - cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.String(), r.CctxClient, r.Logger, r.CctxTimeout) - r.Logger.CCTX(*cctx, "deposit_and_revert") - utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_Reverted) - - // check the test was effective: the revert outbound amount is less than the dust amount - require.Less(r, cctx.GetCurrentOutboundParam().Amount.Uint64(), uint64(constant.BTCWithdrawalDustAmount)) + // ASSERT + // Now we want to make sure the cctx is aborted with expected error message + cctx := utils.WaitCctxAbortedByInboundHash(r.Ctx, r, txHash.String(), r.CctxClient) + require.True(r, cctx.GetCurrentOutboundParam().Amount.Uint64() < constant.BTCWithdrawalDustAmount) + require.True(r, strings.Contains(cctx.CctxStatus.ErrorMessage, crosschaintypes.ErrInvalidWithdrawalAmount.Error())) } diff --git a/e2e/e2etests/test_solana_deposit_and_call_revert_with_dust.go b/e2e/e2etests/test_solana_deposit_and_call_revert_with_dust.go new file mode 100644 index 0000000000..2ffe5ce9c6 --- /dev/null +++ b/e2e/e2etests/test_solana_deposit_and_call_revert_with_dust.go @@ -0,0 +1,34 @@ +package e2etests + +import ( + "math/big" + "strings" + + "github.com/stretchr/testify/require" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/utils" + "github.com/zeta-chain/node/pkg/constant" + "github.com/zeta-chain/node/testutil/sample" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +// TestSolanaDepositAndCallRevertWithDust tests Solana deposit and call that reverts with a dust amount in the revert outbound. +func TestSolanaDepositAndCallRevertWithDust(r *runner.E2ERunner, args []string) { + require.Len(r, args, 0) + + // deposit the rent exempt amount which will result in a dust amount (after fee deduction) in the revert outbound + depositAmount := big.NewInt(constant.SolanaWalletRentExempt) + + // ACT + // execute the deposit and call transaction + nonExistReceiver := sample.EthAddress() + data := []byte("dust lamports should abort cctx") + sig := r.SOLDepositAndCall(nil, nonExistReceiver, depositAmount, data) + + // ASSERT + // Now we want to make sure cctx is aborted. + cctx := utils.WaitCctxAbortedByInboundHash(r.Ctx, r, sig.String(), r.CctxClient) + require.True(r, cctx.GetCurrentOutboundParam().Amount.Uint64() < constant.SolanaWalletRentExempt) + require.True(r, strings.Contains(cctx.CctxStatus.ErrorMessage, crosschaintypes.ErrInvalidWithdrawalAmount.Error())) +} diff --git a/e2e/e2etests/test_solana_deposit_refund.go b/e2e/e2etests/test_solana_deposit_refund.go index 0a62b70ac6..c8724e72f8 100644 --- a/e2e/e2etests/test_solana_deposit_refund.go +++ b/e2e/e2etests/test_solana_deposit_refund.go @@ -9,8 +9,8 @@ import ( crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" ) -// TestSolanaDepositAndCallRefund tests deposit of lamports calling a example contract -func TestSolanaDepositAndCallRefund(r *runner.E2ERunner, args []string) { +// TestSolanaDepositAndCallRevert tests deposit of lamports calling a example contract that reverts. +func TestSolanaDepositAndCallRevert(r *runner.E2ERunner, args []string) { require.Len(r, args, 1) // parse deposit amount (in lamports) diff --git a/e2e/utils/zetacore.go b/e2e/utils/zetacore.go index 0b4d5217ed..34e53e61b0 100644 --- a/e2e/utils/zetacore.go +++ b/e2e/utils/zetacore.go @@ -227,6 +227,20 @@ func WaitCctxRevertedByInboundHash( return cctxs[0] } +// WaitCctxAbortedByInboundHash waits until cctx is aborted by inbound hash. +func WaitCctxAbortedByInboundHash( + ctx context.Context, + t require.TestingT, + hash string, + c CCTXClient, +) crosschaintypes.CrossChainTx { + // wait for cctx to be aborted + cctxs := WaitCctxByInboundHash(ctx, t, hash, c, MatchStatus(crosschaintypes.CctxStatus_Aborted)) + require.Len(t, cctxs, 1) + + return cctxs[0] +} + // WaitCctxByInboundHash waits until cctx appears by inbound hash. func WaitCctxByInboundHash( ctx context.Context, diff --git a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go index 2f3acdd744..52c8c1e10d 100644 --- a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go +++ b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go @@ -182,6 +182,7 @@ func (k Keeper) processFailedOutboundOnExternalChain( return cosmoserrors.Wrap(err, "AddRevertOutbound") } + // pay revert outbound gas fee err = k.PayGasAndUpdateCctx( ctx, cctx.InboundParams.SenderChainId, @@ -192,6 +193,18 @@ func (k Keeper) processFailedOutboundOnExternalChain( if err != nil { return err } + + // validate data of the revert outbound + err = k.validateZRC20Withdrawal( + ctx, + cctx.GetCurrentOutboundParam().ReceiverChainId, + cctx.GetCurrentOutboundParam().Amount.BigInt(), + []byte(cctx.GetCurrentOutboundParam().Receiver), + ) + if err != nil { + return err + } + err = k.SetObserverOutboundInfo(ctx, cctx.InboundParams.SenderChainId, cctx) if err != nil { return err From 0b6addd2effd03c87d4edfd6b223ddbc8d199114 Mon Sep 17 00:00:00 2001 From: Christopher Fuka <97121270+CryptoFewka@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:25:00 -0600 Subject: [PATCH 04/15] Bump download-artifact to v4 (#3104) --- .github/actions/upgrade-testing/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/upgrade-testing/action.yml b/.github/actions/upgrade-testing/action.yml index 55ba9f8524..9c3eeaf58d 100644 --- a/.github/actions/upgrade-testing/action.yml +++ b/.github/actions/upgrade-testing/action.yml @@ -14,7 +14,7 @@ runs: with: python-version: 'pypy3.9' - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 #v3 reaches deprecation on November 30, 2024 with: name: binaries-${{ github.sha }} path: ./ From 6fb64cafa758d8b3a1b0df9fb2625b8fefcefb99 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Thu, 14 Nov 2024 11:59:19 -0800 Subject: [PATCH 05/15] refactor: use major version in release upgrade handlers (#3159) * refactor: use major version in release upgrade handlers * use + rather than - for semver compliance * fmt * docs * fix lint * more semver 2.0 compliance * remove check-upgrade-handler-updated --- .github/workflows/publish-release.yml | 33 ------------------- app/setup_handlers.go | 26 +++++++++++++-- cmd/zetacored/root.go | 1 + cmd/zetacored/version.go | 19 +++++++++++ .../scripts/start-upgrade-orchestrator.sh | 2 +- docs/cli/zetacored/cli.md | 29 ++++++++++++++++ version.sh | 4 +-- 7 files changed, 75 insertions(+), 39 deletions(-) create mode 100644 cmd/zetacored/version.go diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index a8b324de6b..924706af29 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -94,38 +94,6 @@ jobs: run: | echo "continue" - check-upgrade-handler-updated: - needs: - - check-branch - runs-on: ubuntu-22.04 - timeout-minutes: 10 - steps: - - - uses: actions/checkout@v4 - if: inputs.skip_checks != true - with: - fetch-depth: 0 - - - name: Major Version in Upgrade Handler Must Match Tag - if: inputs.skip_checks != true - run: | - UPGRADE_HANDLER_MAJOR_VERSION=$(cat app/setup_handlers.go | grep "const releaseVersion" | cut -d ' ' -f4 | tr -d '"' | cut -d '.' -f 1 | tr -d '\n') - USER_INPUT_VERSION=$(echo "${{ inputs.version }}" | cut -d '.' -f 1 | tr -d '\n') - echo "Upgrade Handler Major Version: ${UPGRADE_HANDLER_MAJOR_VERSION}" - echo "User Inputted Release Version: ${USER_INPUT_VERSION}" - if [ ${USER_INPUT_VERSION} != $UPGRADE_HANDLER_MAJOR_VERSION ]; then - echo "ERROR: The input version doesn't match the release handler for the branch selected. Please ensure the upgrade handler of the branch you selected when you ran the pipeline matches the input version." - echo "Did you forget to update the 'releaseVersion' in app/setup_handlers.go?" - exit 1 - fi - echo "The major version found in 'releaseVersion' in app/setup_handlers.go matches this tagged release - Moving Forward!" - - - name: Mark Job Complete Skipped - if: inputs.skip_checks == true - shell: bash - run: | - echo "continue" - publish-release: permissions: id-token: write @@ -134,7 +102,6 @@ jobs: if: inputs.skip_release != true needs: - check-changelog - - check-upgrade-handler-updated - check-branch - check-goreleaser runs-on: ${{ vars.RELEASE_RUNNER }} diff --git a/app/setup_handlers.go b/app/setup_handlers.go index 04a94da668..1468f83fe2 100644 --- a/app/setup_handlers.go +++ b/app/setup_handlers.go @@ -7,10 +7,28 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "golang.org/x/mod/semver" "github.com/zeta-chain/node/pkg/constant" ) +// GetDefaultUpgradeHandlerVersion prints the default upgrade handler version +// +// There may be multiple upgrade handlers configured on some releases if different +// migrations needto be run in different environment +func GetDefaultUpgradeHandlerVersion() string { + // semver must have v prefix, but we store without prefix + vVersion := "v" + constant.Version + + // development builds always use the full version in the release handlers + if semver.Build(vVersion) != "" || semver.Prerelease(vVersion) != "" { + return constant.Version + } + + // release builds use just the major version (v22.0.0 -> v22) + return semver.Major(vVersion) +} + func SetupHandlers(app *App) { allUpgrades := upgradeTracker{ upgrades: []upgradeTrackerItem{ @@ -50,10 +68,12 @@ func SetupHandlers(app *App) { upgradeHandlerFns, storeUpgrades = allUpgrades.mergeAllUpgrades() } + upgradeHandlerVersion := GetDefaultUpgradeHandlerVersion() + app.UpgradeKeeper.SetUpgradeHandler( - constant.Version, + upgradeHandlerVersion, func(ctx sdk.Context, _ types.Plan, vm module.VersionMap) (module.VersionMap, error) { - app.Logger().Info("Running upgrade handler for " + constant.Version) + app.Logger().Info("Running upgrade handler for " + upgradeHandlerVersion) var err error for _, upgradeHandler := range upgradeHandlerFns { @@ -71,7 +91,7 @@ func SetupHandlers(app *App) { if err != nil { panic(err) } - if upgradeInfo.Name == constant.Version && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + if upgradeInfo.Name == upgradeHandlerVersion && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { // Use upgrade store loader for the initial loading of all stores when app starts, // it checks if version == upgradeHeight and applies store upgrades before loading the stores, // so that new stores start with the correct version (the current height of chain), diff --git a/cmd/zetacored/root.go b/cmd/zetacored/root.go index 93ae4ba469..1f7115e57a 100644 --- a/cmd/zetacored/root.go +++ b/cmd/zetacored/root.go @@ -145,6 +145,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig types.EncodingConfig) { GetPubKeyCmd(), CollectObserverInfoCmd(), AddrConversionCmd(), + UpgradeHandlerVersionCmd(), tmcli.NewCompletionCmd(rootCmd, true), ethermintclient.NewTestnetCmd(app.ModuleBasics, banktypes.GenesisBalancesIterator{}), diff --git a/cmd/zetacored/version.go b/cmd/zetacored/version.go new file mode 100644 index 0000000000..d9da8ac484 --- /dev/null +++ b/cmd/zetacored/version.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/zeta-chain/node/app" +) + +func UpgradeHandlerVersionCmd() *cobra.Command { + return &cobra.Command{ + Use: "upgrade-handler-version", + Short: "Print the default upgrade handler version", + Run: func(_ *cobra.Command, _ []string) { + fmt.Println(app.GetDefaultUpgradeHandlerVersion()) + }, + } +} diff --git a/contrib/localnet/scripts/start-upgrade-orchestrator.sh b/contrib/localnet/scripts/start-upgrade-orchestrator.sh index 1f8089bc3d..13d09a447f 100755 --- a/contrib/localnet/scripts/start-upgrade-orchestrator.sh +++ b/contrib/localnet/scripts/start-upgrade-orchestrator.sh @@ -39,7 +39,7 @@ fi # get new zetacored version curl -L -o /tmp/zetacored.new "${ZETACORED_URL}" chmod +x /tmp/zetacored.new -UPGRADE_NAME=$(/tmp/zetacored.new version) +UPGRADE_NAME=$(/tmp/zetacored.new upgrade-handler-version) # if explicit upgrade height not provided, use dumb estimator if [[ -z $UPGRADE_HEIGHT ]]; then diff --git a/docs/cli/zetacored/cli.md b/docs/cli/zetacored/cli.md index d7a594d94f..96c6e71510 100644 --- a/docs/cli/zetacored/cli.md +++ b/docs/cli/zetacored/cli.md @@ -39,6 +39,7 @@ Zetacore Daemon (server) * [zetacored tendermint](#zetacored-tendermint) - Tendermint subcommands * [zetacored testnet](#zetacored-testnet) - subcommands for starting or configuring local testnets * [zetacored tx](#zetacored-tx) - Transactions subcommands +* [zetacored upgrade-handler-version](#zetacored-upgrade-handler-version) - Print the default upgrade handler version * [zetacored validate-genesis](#zetacored-validate-genesis) - validates the genesis file at the default location or at the location passed as an arg * [zetacored version](#zetacored-version) - Print the application binary version information @@ -14346,6 +14347,34 @@ zetacored tx vesting create-vesting-account [to_address] [amount] [end_time] [fl * [zetacored tx vesting](#zetacored-tx-vesting) - Vesting transaction subcommands +## zetacored upgrade-handler-version + +Print the default upgrade handler version + +``` +zetacored upgrade-handler-version [flags] +``` + +### Options + +``` + -h, --help help for upgrade-handler-version +``` + +### Options inherited from parent commands + +``` + --home string directory for config and data + --log_format string The logging format (json|plain) + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) + --log_no_color Disable colored logs + --trace print out full stack trace on errors +``` + +### SEE ALSO + +* [zetacored](#zetacored) - Zetacore Daemon (server) + ## zetacored validate-genesis validates the genesis file at the default location or at the location passed as an arg diff --git a/version.sh b/version.sh index aedbfa5eeb..002f5cc990 100755 --- a/version.sh +++ b/version.sh @@ -22,8 +22,8 @@ short_commit=$(git rev-parse --short HEAD) # append -dirty for dirty builds if ! git diff --no-ext-diff --quiet --exit-code ; then - echo "0.0.${commit_timestamp}-${short_commit}-dirty" + echo "0.0.${commit_timestamp}+${short_commit}.dirty" exit fi -echo "0.0.${commit_timestamp}-${short_commit}" \ No newline at end of file +echo "0.0.${commit_timestamp}+${short_commit}" \ No newline at end of file From 46f3d4472c9c2a61eda408550db666f1a81c9843 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Thu, 14 Nov 2024 16:54:38 -0600 Subject: [PATCH 06/15] fix: skip depositor fee calculation on irrelevant transactions (#3162) * skip depositor fee calculation on irrelevant txs * add changelog entry * correct PR number in changelog --- changelog.md | 1 + zetaclient/chains/bitcoin/fee.go | 3 + zetaclient/chains/bitcoin/observer/inbound.go | 40 ++++++----- .../chains/bitcoin/observer/inbound_test.go | 68 ++++++++++++++----- zetaclient/chains/bitcoin/observer/witness.go | 8 ++- .../chains/bitcoin/observer/witness_test.go | 34 ++++++++-- 6 files changed, 107 insertions(+), 47 deletions(-) diff --git a/changelog.md b/changelog.md index 4facc05f04..2ac17bbc71 100644 --- a/changelog.md +++ b/changelog.md @@ -27,6 +27,7 @@ * [3106](https://github.com/zeta-chain/node/pull/3106) - prevent blocked CCTX on out of gas during omnichain calls * [3139](https://github.com/zeta-chain/node/pull/3139) - fix config resolution in orchestrator * [3149](https://github.com/zeta-chain/node/pull/3149) - abort the cctx if dust amount is detected in the revert outbound +* [3162](https://github.com/zeta-chain/node/pull/3162) - skip depositor fee calculation if transaction does not involve TSS address ## v21.0.0 diff --git a/zetaclient/chains/bitcoin/fee.go b/zetaclient/chains/bitcoin/fee.go index f56a479364..7ce483a5bf 100644 --- a/zetaclient/chains/bitcoin/fee.go +++ b/zetaclient/chains/bitcoin/fee.go @@ -56,6 +56,9 @@ var ( DefaultDepositorFee = DepositorFee(defaultDepositorFeeRate) ) +// DepositorFeeCalculator is a function type to calculate the Bitcoin depositor fee +type DepositorFeeCalculator func(interfaces.BTCRPCClient, *btcjson.TxRawResult, *chaincfg.Params) (float64, error) + // FeeRateToSatPerByte converts a fee rate in BTC/KB to sat/byte. func FeeRateToSatPerByte(rate float64) *big.Int { // #nosec G115 always in range diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index 3cd1ab3945..aa4f5667ad 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -255,12 +255,6 @@ func (ob *Observer) CheckReceiptForBtcTxHash(ctx context.Context, txHash string, return "", fmt.Errorf("block %d is not confirmed yet", blockVb.Height) } - // calculate depositor fee - depositorFee, err := bitcoin.CalcDepositorFee(ob.btcClient, tx, ob.netParams) - if err != nil { - return "", errors.Wrapf(err, "error calculating depositor fee for inbound %s", tx.Txid) - } - // #nosec G115 always positive event, err := GetBtcEvent( ob.btcClient, @@ -269,7 +263,7 @@ func (ob *Observer) CheckReceiptForBtcTxHash(ctx context.Context, txHash string, uint64(blockVb.Height), ob.logger.Inbound, ob.netParams, - depositorFee, + bitcoin.CalcDepositorFee, ) if err != nil { return "", err @@ -323,13 +317,7 @@ func FilterAndParseIncomingTx( continue // the first tx is coinbase; we do not process coinbase tx } - // calculate depositor fee - depositorFee, err := bitcoin.CalcDepositorFee(rpcClient, &txs[idx], netParams) - if err != nil { - return nil, errors.Wrapf(err, "error calculating depositor fee for inbound %s", tx.Txid) - } - - event, err := GetBtcEvent(rpcClient, tx, tssAddress, blockNumber, logger, netParams, depositorFee) + event, err := GetBtcEvent(rpcClient, tx, tssAddress, blockNumber, logger, netParams, bitcoin.CalcDepositorFee) if err != nil { // unable to parse the tx, the caller should retry return nil, errors.Wrapf(err, "error getting btc event for tx %s in block %d", tx.Txid, blockNumber) @@ -391,12 +379,12 @@ func GetBtcEvent( blockNumber uint64, logger zerolog.Logger, netParams *chaincfg.Params, - depositorFee float64, + feeCalculator bitcoin.DepositorFeeCalculator, ) (*BTCInboundEvent, error) { if netParams.Name == chaincfg.MainNetParams.Name { - return GetBtcEventWithoutWitness(rpcClient, tx, tssAddress, blockNumber, logger, netParams, depositorFee) + return GetBtcEventWithoutWitness(rpcClient, tx, tssAddress, blockNumber, logger, netParams, feeCalculator) } - return GetBtcEventWithWitness(rpcClient, tx, tssAddress, blockNumber, logger, netParams, depositorFee) + return GetBtcEventWithWitness(rpcClient, tx, tssAddress, blockNumber, logger, netParams, feeCalculator) } // GetBtcEventWithoutWitness either returns a valid BTCInboundEvent or nil @@ -409,11 +397,15 @@ func GetBtcEventWithoutWitness( blockNumber uint64, logger zerolog.Logger, netParams *chaincfg.Params, - depositorFee float64, + feeCalculator bitcoin.DepositorFeeCalculator, ) (*BTCInboundEvent, error) { - found := false - var value float64 - var memo []byte + var ( + found bool + value float64 + depositorFee float64 + memo []byte + ) + if len(tx.Vout) >= 2 { // 1st vout must have tss address as receiver with p2wpkh scriptPubKey vout0 := tx.Vout[0] @@ -430,6 +422,12 @@ func GetBtcEventWithoutWitness( return nil, nil } + // calculate depositor fee + depositorFee, err = feeCalculator(rpcClient, &tx, netParams) + if err != nil { + return nil, errors.Wrapf(err, "error calculating depositor fee for inbound %s", tx.Txid) + } + // deposit amount has to be no less than the minimum depositor fee if vout0.Value < depositorFee { logger.Info(). diff --git a/zetaclient/chains/bitcoin/observer/inbound_test.go b/zetaclient/chains/bitcoin/observer/inbound_test.go index 838315b7b8..7ec938aab0 100644 --- a/zetaclient/chains/bitcoin/observer/inbound_test.go +++ b/zetaclient/chains/bitcoin/observer/inbound_test.go @@ -23,6 +23,7 @@ import ( "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/zetaclient/chains/bitcoin" "github.com/zeta-chain/node/zetaclient/chains/bitcoin/observer" + "github.com/zeta-chain/node/zetaclient/chains/interfaces" clientcommon "github.com/zeta-chain/node/zetaclient/common" "github.com/zeta-chain/node/zetaclient/keys" "github.com/zeta-chain/node/zetaclient/testutils" @@ -30,6 +31,13 @@ import ( "github.com/zeta-chain/node/zetaclient/testutils/testrpc" ) +// mockDepositFeeCalculator returns a mock depositor fee calculator that returns the given fee and error. +func mockDepositFeeCalculator(fee float64, err error) bitcoin.DepositorFeeCalculator { + return func(interfaces.BTCRPCClient, *btcjson.TxRawResult, *chaincfg.Params) (float64, error) { + return fee, err + } +} + func TestAvgFeeRateBlock828440(t *testing.T) { // load archived block 828440 var blockVb btcjson.GetBlockVerboseTxResult @@ -278,6 +286,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { // fee rate of above tx is 28 sat/vB depositorFee := bitcoin.DepositorFee(28 * clientcommon.BTCOutboundGasPriceMultiplier) + feeCalculator := mockDepositFeeCalculator(depositorFee, nil) // expected result memo, err := hex.DecodeString(tx.Vout[1].ScriptPubKey.Hex[4:]) @@ -309,7 +318,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, eventExpected, event) @@ -333,7 +342,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, eventExpected, event) @@ -357,7 +366,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, eventExpected, event) @@ -381,7 +390,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, eventExpected, event) @@ -405,7 +414,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, eventExpected, event) @@ -425,7 +434,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) @@ -445,7 +454,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) @@ -459,7 +468,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) @@ -479,12 +488,31 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) }) + t.Run("should return error if RPC failed to calculate depositor fee", func(t *testing.T) { + // load tx + tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash, false) + + // get BTC event + rpcClient := mocks.NewBTCRPCClient(t) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + mockDepositFeeCalculator(0.0, errors.New("rpc error")), + ) + require.ErrorContains(t, err, "rpc error") + require.Nil(t, event) + }) + t.Run("should skip tx if amount is less than depositor fee", func(t *testing.T) { // load tx and modify amount to less than depositor fee tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash, false) @@ -499,7 +527,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) @@ -519,7 +547,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) @@ -539,7 +567,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) @@ -570,7 +598,7 @@ func TestGetBtcEventWithoutWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) @@ -588,6 +616,7 @@ func TestGetBtcEventErrors(t *testing.T) { // fee rate of above tx is 28 sat/vB depositorFee := bitcoin.DepositorFee(28 * clientcommon.BTCOutboundGasPriceMultiplier) + feeCalculator := mockDepositFeeCalculator(depositorFee, nil) t.Run("should return error on invalid Vout[0] script", func(t *testing.T) { // load tx and modify Vout[0] script to invalid script @@ -603,7 +632,7 @@ func TestGetBtcEventErrors(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.Error(t, err) require.Nil(t, event) @@ -623,7 +652,7 @@ func TestGetBtcEventErrors(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.ErrorContains(t, err, "no input found") require.Nil(t, event) @@ -645,7 +674,7 @@ func TestGetBtcEventErrors(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.ErrorContains(t, err, "error getting sender address") require.Nil(t, event) @@ -662,6 +691,8 @@ func TestGetBtcEvent(t *testing.T) { net := &chaincfg.MainNetParams // 2.992e-05, see avgFeeRate https://mempool.space/api/v1/blocks/835640 depositorFee := bitcoin.DepositorFee(22 * clientcommon.BTCOutboundGasPriceMultiplier) + feeCalculator := mockDepositFeeCalculator(depositorFee, nil) + txHash2 := "37777defed8717c581b4c0509329550e344bdc14ac38f71fc050096887e535c8" tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash2, false) rpcClient := mocks.NewBTCRPCClient(t) @@ -673,7 +704,7 @@ func TestGetBtcEvent(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, (*observer.BTCInboundEvent)(nil), event) @@ -693,6 +724,7 @@ func TestGetBtcEvent(t *testing.T) { // fee rate of above tx is 28 sat/vB depositorFee := bitcoin.DepositorFee(28 * clientcommon.BTCOutboundGasPriceMultiplier) + feeCalculator := mockDepositFeeCalculator(depositorFee, nil) // expected result memo, err := hex.DecodeString(tx.Vout[1].ScriptPubKey.Hex[4:]) @@ -723,7 +755,7 @@ func TestGetBtcEvent(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, eventExpected, event) diff --git a/zetaclient/chains/bitcoin/observer/witness.go b/zetaclient/chains/bitcoin/observer/witness.go index 9625ad3caa..bb85bdc47b 100644 --- a/zetaclient/chains/bitcoin/observer/witness.go +++ b/zetaclient/chains/bitcoin/observer/witness.go @@ -24,7 +24,7 @@ func GetBtcEventWithWitness( blockNumber uint64, logger zerolog.Logger, netParams *chaincfg.Params, - depositorFee float64, + feeCalculator bitcoin.DepositorFeeCalculator, ) (*BTCInboundEvent, error) { if len(tx.Vout) < 1 { logger.Debug().Msgf("no output %s", tx.Txid) @@ -40,6 +40,12 @@ func GetBtcEventWithWitness( return nil, nil } + // calculate depositor fee + depositorFee, err := feeCalculator(client, &tx, netParams) + if err != nil { + return nil, errors.Wrapf(err, "error calculating depositor fee for inbound %s", tx.Txid) + } + isAmountValid, amount := isValidAmount(tx.Vout[0].Value, depositorFee) if !isAmountValid { logger.Info(). diff --git a/zetaclient/chains/bitcoin/observer/witness_test.go b/zetaclient/chains/bitcoin/observer/witness_test.go index af14427c6e..745f2003a9 100644 --- a/zetaclient/chains/bitcoin/observer/witness_test.go +++ b/zetaclient/chains/bitcoin/observer/witness_test.go @@ -61,6 +61,7 @@ func TestGetBtcEventWithWitness(t *testing.T) { // fee rate of above tx is 28 sat/vB depositorFee := bitcoin.DepositorFee(28 * clientcommon.BTCOutboundGasPriceMultiplier) + feeCalculator := mockDepositFeeCalculator(depositorFee, nil) t.Run("decode OP_RETURN ok", func(t *testing.T) { tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash, false) @@ -93,7 +94,7 @@ func TestGetBtcEventWithWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, eventExpected, event) @@ -131,7 +132,7 @@ func TestGetBtcEventWithWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, eventExpected, event) @@ -172,7 +173,7 @@ func TestGetBtcEventWithWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Equal(t, event, eventExpected) @@ -192,12 +193,31 @@ func TestGetBtcEventWithWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) }) + t.Run("should return error if RPC failed to calculate depositor fee", func(t *testing.T) { + // load tx + tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash, false) + + // get BTC event + rpcClient := mocks.NewBTCRPCClient(t) + event, err := observer.GetBtcEventWithWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + mockDepositFeeCalculator(0.0, errors.New("rpc error")), + ) + require.ErrorContains(t, err, "rpc error") + require.Nil(t, event) + }) + t.Run("should skip tx if amount is less than depositor fee", func(t *testing.T) { // load tx and modify amount to less than depositor fee tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash, false) @@ -212,7 +232,7 @@ func TestGetBtcEventWithWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) @@ -234,7 +254,7 @@ func TestGetBtcEventWithWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.ErrorContains(t, err, "rpc error") require.Nil(t, event) @@ -268,7 +288,7 @@ func TestGetBtcEventWithWitness(t *testing.T) { blockNumber, log.Logger, net, - depositorFee, + feeCalculator, ) require.NoError(t, err) require.Nil(t, event) From 9c9b808ea8a85befc4d5bbfd96dff28f68ac9063 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Fri, 15 Nov 2024 02:39:35 -0600 Subject: [PATCH 07/15] fix: avoid panic in inscription parsing (#3155) * fix potential panic during inscription parsing * add changelog entry * append opcode decoding err, if any, to log print --- changelog.md | 1 + zetaclient/chains/bitcoin/tx_script.go | 4 +-- zetaclient/chains/bitcoin/tx_script_test.go | 40 +++++++++++++++------ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 2ac17bbc71..184790d68f 100644 --- a/changelog.md +++ b/changelog.md @@ -27,6 +27,7 @@ * [3106](https://github.com/zeta-chain/node/pull/3106) - prevent blocked CCTX on out of gas during omnichain calls * [3139](https://github.com/zeta-chain/node/pull/3139) - fix config resolution in orchestrator * [3149](https://github.com/zeta-chain/node/pull/3149) - abort the cctx if dust amount is detected in the revert outbound +* [3155](https://github.com/zeta-chain/node/pull/3155) - fix potential panic in the Bitcoin inscription parsing * [3162](https://github.com/zeta-chain/node/pull/3162) - skip depositor fee calculation if transaction does not involve TSS address ## v21.0.0 diff --git a/zetaclient/chains/bitcoin/tx_script.go b/zetaclient/chains/bitcoin/tx_script.go index 816251024a..e15268a868 100644 --- a/zetaclient/chains/bitcoin/tx_script.go +++ b/zetaclient/chains/bitcoin/tx_script.go @@ -337,11 +337,11 @@ func decodeInscriptionPayload(t *txscript.ScriptTokenizer) ([]byte, error) { // OP_PUSHBYTES_32 <32 bytes> OP_CHECKSIG func checkInscriptionEnvelope(t *txscript.ScriptTokenizer) error { if !t.Next() || t.Opcode() != txscript.OP_DATA_32 { - return fmt.Errorf("cannot obtain public key bytes op %d or err %s", t.Opcode(), t.Err()) + return fmt.Errorf("public key not found: %v", t.Err()) } if !t.Next() || t.Opcode() != txscript.OP_CHECKSIG { - return fmt.Errorf("cannot parse OP_CHECKSIG, op %d or err %s", t.Opcode(), t.Err()) + return fmt.Errorf("OP_CHECKSIG not found: %v", t.Err()) } return nil diff --git a/zetaclient/chains/bitcoin/tx_script_test.go b/zetaclient/chains/bitcoin/tx_script_test.go index 6c4724eb9a..0d4b96bd63 100644 --- a/zetaclient/chains/bitcoin/tx_script_test.go +++ b/zetaclient/chains/bitcoin/tx_script_test.go @@ -622,7 +622,7 @@ func TestDecodeScript(t *testing.T) { t.Run("should decode longer data ok", func(t *testing.T) { // 600 bytes of random data generated offline data := "2001a7bae79bd61c2368fe41a565061d6cf22b4f509fbc1652caea06d98b8fd0c7ac00634d0802c7faa771dd05f27993d22c42988758882d20080241074462884c8774e1cdf4b04e5b3b74b6568bd1769722708306c66270b6b2a7f68baced83627eeeb2d494e8a1749277b92a4c5a90b1b4f6038e5f704405515109d4d0021612ad298b8dad6e12245f8f0020e11a7a319652ba6abe261958201ce5e83131cd81302c0ecec60d4afa9f72540fc84b6b9c1f3d903ab25686df263b192a403a4aa22b799ba24369c49ff4042012589a07d4211e05f80f18a1262de5a1577ce0ec9e1fa9283cfa25d98d7d0b4217951dfcb8868570318c63f1e1424cfdb7d7a33c6b9e3ced4b2ffa0178b3a5fac8bace2991e382a402f56a2c6a9191463740910056483e4fd0f5ac729ffac66bf1b3ec4570c4e75c116f7d9fd65718ec3ed6c7647bf335b77e7d6a4e2011276dc8031b78403a1ad82c92fb339ec916c263b6dd0f003ba4381ad5410e90e88effbfa7f961b8e8a6011c525643a434f7abe2c1928a892cc57d6291831216c4e70cb80a39a79a3889211070e767c23db396af9b4c2093c3743d8cbcbfcb73d29361ecd3857e94ab3c800be1299fd36a5685ec60607a60d8c2e0f99ff0b8b9e86354d39a43041f7d552e95fe2d33b6fc0f540715da0e7e1b344c778afe73f82d00881352207b719f67dcb00b4ff645974d4fd7711363d26400e2852890cb6ea9cbfe63ac43080870049b1023be984331560c6350bb64da52b4b81bc8910934915f0a96701f4c50646d5386146596443bee9b2d116706e1687697fb42542196c1d764419c23a914896f9212946518ac59e1ba5d1fc37e503313133ebdf2ced5785e0eaa9738fe3f9ad73646e733931ebb7cff26e96106fe68" - script, _ := hex.DecodeString(data) + script := testutil.HexToBytes(t, data) memo, isFound, err := bitcoin.DecodeScript(script) require.Nil(t, err) @@ -636,7 +636,7 @@ func TestDecodeScript(t *testing.T) { t.Run("should decode shorter data ok", func(t *testing.T) { // 81 bytes of random data generated offline data := "20d6f59371037bf30115d9fd6016f0e3ef552cdfc0367ee20aa9df3158f74aaeb4ac00634c51bdd33073d76f6b4ae6510d69218100575eafabadd16e5faf9f42bd2fbbae402078bdcaa4c0413ce96d053e3c0bbd4d5944d6857107d640c248bdaaa7de959d9c1e6b9962b51428e5a554c28c397160881668" - script, _ := hex.DecodeString(data) + script := testutil.HexToBytes(t, data) memo, isFound, err := bitcoin.DecodeScript(script) require.Nil(t, err) @@ -650,7 +650,7 @@ func TestDecodeScript(t *testing.T) { t.Run("decode error due to missing data byte", func(t *testing.T) { // missing OP_ENDIF at the end data := "20cabd6ecc0245c40f27ca6299dcd3732287c317f3946734f04e27568fc5334218ac00634d0802000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000068" - script, _ := hex.DecodeString(data) + script := testutil.HexToBytes(t, data) memo, isFound, err := bitcoin.DecodeScript(script) require.ErrorContains(t, err, "should contain more data, but script ended") @@ -658,24 +658,44 @@ func TestDecodeScript(t *testing.T) { require.Nil(t, memo) }) - t.Run("decode error due to missing data for public key", func(t *testing.T) { + t.Run("opcode OP_DATA_32 for public key not found", func(t *testing.T) { // require OP_DATA_32 but OP_DATA_31 is given data := "1f01a7bae79bd61c2368fe41a565061d6cf22b4f509fbc1652caea06d98b8fd0" - script, _ := hex.DecodeString(data) + script := testutil.HexToBytes(t, data) memo, isFound, err := bitcoin.DecodeScript(script) - require.ErrorContains(t, err, "cannot obtain public key bytes") + require.ErrorContains(t, err, "public key not found") require.False(t, isFound) require.Nil(t, memo) }) - t.Run("decode error due to missing OP_CHECKSIG", func(t *testing.T) { - // missing OP_ENDIF at the end + t.Run("opcode OP_CHECKSIG not found", func(t *testing.T) { + // require OP_CHECKSIG (0xac) but OP_CODESEPARATOR (0xac) is found data := "2001a7bae79bd61c2368fe41a565061d6cf22b4f509fbc1652caea06d98b8fd0c7ab" - script, _ := hex.DecodeString(data) + script := testutil.HexToBytes(t, data) memo, isFound, err := bitcoin.DecodeScript(script) - require.ErrorContains(t, err, "cannot parse OP_CHECKSIG") + require.ErrorContains(t, err, "OP_CHECKSIG not found") + require.False(t, isFound) + require.Nil(t, memo) + }) + + t.Run("parsing opcode OP_DATA_32 failed", func(t *testing.T) { + data := "01" + script := testutil.HexToBytes(t, data) + memo, isFound, err := bitcoin.DecodeScript(script) + + require.ErrorContains(t, err, "public key not found") + require.False(t, isFound) + require.Nil(t, memo) + }) + + t.Run("parsing opcode OP_CHECKSIG failed", func(t *testing.T) { + data := "2001a7bae79bd61c2368fe41a565061d6cf22b4f509fbc1652caea06d98b8fd0c701" + script := testutil.HexToBytes(t, data) + memo, isFound, err := bitcoin.DecodeScript(script) + + require.ErrorContains(t, err, "OP_CHECKSIG not found") require.False(t, isFound) require.Nil(t, memo) }) From 3c22fbbb6070b0aa6d963237f22e6415fdd74951 Mon Sep 17 00:00:00 2001 From: skosito Date: Fri, 15 Nov 2024 09:06:33 +0000 Subject: [PATCH 08/15] test: extend solana unit tests (#3158) * improve inbound tests * fix terminology * add outbound tests for withdraw spl * PR comments * PR comment --- e2e/runner/setup_solana.go | 4 +- e2e/runner/solana.go | 36 ++--- pkg/contracts/solana/gateway.go | 2 +- pkg/contracts/solana/gateway_message.go | 14 +- pkg/contracts/solana/gateway_message_test.go | 49 ++++-- pkg/contracts/solana/inbound.go | 43 +++-- pkg/contracts/solana/inbound_test.go | 146 ++++++++++++++++- pkg/contracts/solana/instruction.go | 1 + .../chains/solana/observer/outbound_test.go | 149 ++++++++++++++++++ .../chains/solana/signer/withdraw_spl.go | 20 +-- ...DMZndhZn7hQ1i4RhTyHXRWxtR5ZNVHmmjAUSF.json | 78 +++++++++ 11 files changed, 478 insertions(+), 64 deletions(-) create mode 100644 zetaclient/testdata/solana/chain_901_outbound_tx_result_3NgoR4K9FJq7UunorPRGW9wpqMV8oNvZERejutd7bKmqh3CKEV5DMZndhZn7hQ1i4RhTyHXRWxtR5ZNVHmmjAUSF.json diff --git a/e2e/runner/setup_solana.go b/e2e/runner/setup_solana.go index 28a4fb65fa..46155c8386 100644 --- a/e2e/runner/setup_solana.go +++ b/e2e/runner/setup_solana.go @@ -113,8 +113,8 @@ func (r *E2ERunner) SetupSolana(gatewayID, deployerPrivateKey string) { require.NoError(r, err) // deploy test spl - tokenAccount := r.DeploySPL(&privkey, true) - r.SPLAddr = tokenAccount.PublicKey() + mintAccount := r.DeploySPL(&privkey, true) + r.SPLAddr = mintAccount.PublicKey() } func (r *E2ERunner) ensureSolanaChainParams() error { diff --git a/e2e/runner/solana.go b/e2e/runner/solana.go index 380219dee4..37407c67e1 100644 --- a/e2e/runner/solana.go +++ b/e2e/runner/solana.go @@ -161,9 +161,9 @@ func (r *E2ERunner) CreateSignedTransaction( func (r *E2ERunner) ResolveSolanaATA( payer solana.PrivateKey, owner solana.PublicKey, - tokenAccount solana.PublicKey, + mintAccount solana.PublicKey, ) solana.PublicKey { - pdaAta, _, err := solana.FindAssociatedTokenAddress(owner, tokenAccount) + pdaAta, _, err := solana.FindAssociatedTokenAddress(owner, mintAccount) require.NoError(r, err) info, _ := r.SolanaClient.GetAccountInfo(r.Ctx, pdaAta) @@ -172,7 +172,7 @@ func (r *E2ERunner) ResolveSolanaATA( return pdaAta } // doesn't exist, create it - ataInstruction := associatedtokenaccount.NewCreateInstruction(payer.PublicKey(), owner, tokenAccount).Build() + ataInstruction := associatedtokenaccount.NewCreateInstruction(payer.PublicKey(), owner, mintAccount).Build() signedTx := r.CreateSignedTransaction( []solana.Instruction{ataInstruction}, payer, @@ -188,19 +188,19 @@ func (r *E2ERunner) ResolveSolanaATA( func (r *E2ERunner) SPLDepositAndCall( privateKey *solana.PrivateKey, amount uint64, - tokenAccount solana.PublicKey, + mintAccount solana.PublicKey, receiver ethcommon.Address, data []byte, ) solana.Signature { // ata for pda pda := r.ComputePdaAddress() - pdaAta := r.ResolveSolanaATA(*privateKey, pda, tokenAccount) + pdaAta := r.ResolveSolanaATA(*privateKey, pda, mintAccount) // deployer ata - ata := r.ResolveSolanaATA(*privateKey, privateKey.PublicKey(), tokenAccount) + ata := r.ResolveSolanaATA(*privateKey, privateKey.PublicKey(), mintAccount) // deposit spl - seed := [][]byte{[]byte("whitelist"), tokenAccount.Bytes()} + seed := [][]byte{[]byte("whitelist"), mintAccount.Bytes()} whitelistEntryPDA, _, err := solana.FindProgramAddress(seed, r.GatewayProgram) require.NoError(r, err) @@ -208,7 +208,7 @@ func (r *E2ERunner) SPLDepositAndCall( amount, privateKey.PublicKey(), whitelistEntryPDA, - tokenAccount, + mintAccount, ata, pdaAta, receiver, @@ -231,26 +231,26 @@ func (r *E2ERunner) DeploySPL(privateKey *solana.PrivateKey, whitelist bool) *so require.NoError(r, err) // to deploy new spl token, create account instruction and initialize mint instruction have to be in the same transaction - tokenAccount := solana.NewWallet() + mintAccount := solana.NewWallet() createAccountInstruction := system.NewCreateAccountInstruction( lamport, token.MINT_SIZE, solana.TokenProgramID, privateKey.PublicKey(), - tokenAccount.PublicKey(), + mintAccount.PublicKey(), ).Build() initializeMintInstruction := token.NewInitializeMint2Instruction( 6, privateKey.PublicKey(), privateKey.PublicKey(), - tokenAccount.PublicKey(), + mintAccount.PublicKey(), ).Build() signedTx := r.CreateSignedTransaction( []solana.Instruction{createAccountInstruction, initializeMintInstruction}, *privateKey, - []solana.PrivateKey{tokenAccount.PrivateKey}, + []solana.PrivateKey{mintAccount.PrivateKey}, ) // broadcast the transaction and wait for finalization @@ -258,9 +258,9 @@ func (r *E2ERunner) DeploySPL(privateKey *solana.PrivateKey, whitelist bool) *so r.Logger.Info("create spl logs: %v", out.Meta.LogMessages) // minting some tokens to deployer for testing - ata := r.ResolveSolanaATA(*privateKey, privateKey.PublicKey(), tokenAccount.PublicKey()) + ata := r.ResolveSolanaATA(*privateKey, privateKey.PublicKey(), mintAccount.PublicKey()) - mintToInstruction := token.NewMintToInstruction(uint64(1_000_000_000), tokenAccount.PublicKey(), ata, privateKey.PublicKey(), []solana.PublicKey{}). + mintToInstruction := token.NewMintToInstruction(uint64(1_000_000_000), mintAccount.PublicKey(), ata, privateKey.PublicKey(), []solana.PublicKey{}). Build() signedTx = r.CreateSignedTransaction( []solana.Instruction{mintToInstruction}, @@ -274,7 +274,7 @@ func (r *E2ERunner) DeploySPL(privateKey *solana.PrivateKey, whitelist bool) *so // optionally whitelist spl token in gateway if whitelist { - seed := [][]byte{[]byte("whitelist"), tokenAccount.PublicKey().Bytes()} + seed := [][]byte{[]byte("whitelist"), mintAccount.PublicKey().Bytes()} whitelistEntryPDA, _, err := solana.FindProgramAddress(seed, r.GatewayProgram) require.NoError(r, err) @@ -283,14 +283,14 @@ func (r *E2ERunner) DeploySPL(privateKey *solana.PrivateKey, whitelist bool) *so // already whitelisted if whitelistEntryInfo != nil { - return tokenAccount + return mintAccount } // create 'whitelist_spl_mint' instruction instruction := r.CreateWhitelistSPLMintInstruction( privateKey.PublicKey(), whitelistEntryPDA, - tokenAccount.PublicKey(), + mintAccount.PublicKey(), ) // create and sign the transaction signedTx := r.CreateSignedTransaction([]solana.Instruction{instruction}, *privateKey, []solana.PrivateKey{}) @@ -304,7 +304,7 @@ func (r *E2ERunner) DeploySPL(privateKey *solana.PrivateKey, whitelist bool) *so require.NotNil(r, whitelistEntryInfo) } - return tokenAccount + return mintAccount } // BroadcastTxSync broadcasts a transaction and waits for it to be finalized diff --git a/pkg/contracts/solana/gateway.go b/pkg/contracts/solana/gateway.go index 7465893149..9ff1d5361f 100644 --- a/pkg/contracts/solana/gateway.go +++ b/pkg/contracts/solana/gateway.go @@ -63,7 +63,7 @@ func ParseGatewayWithPDA(gatewayAddress string) (solana.PublicKey, solana.Public return gatewayID, pda, err } -// ParseRentPayerPda parses the rent payer program derived address from the given string +// ParseRentPayerPDA parses the rent payer program derived address from the given string func RentPayerPDA(gateway solana.PublicKey) (solana.PublicKey, error) { var rentPayerPda solana.PublicKey seed := []byte(RentPayerPDASeed) diff --git a/pkg/contracts/solana/gateway_message.go b/pkg/contracts/solana/gateway_message.go index bd8cbb51af..1ab7e64ae4 100644 --- a/pkg/contracts/solana/gateway_message.go +++ b/pkg/contracts/solana/gateway_message.go @@ -119,8 +119,8 @@ type MsgWithdrawSPL struct { // amount is the lamports amount for the withdraw_spl amount uint64 - // tokenAccount is the address for the spl token - tokenAccount solana.PublicKey + // mintAccount is the address for the spl token + mintAccount solana.PublicKey // decimals of spl token decimals uint8 @@ -139,7 +139,7 @@ type MsgWithdrawSPL struct { func NewMsgWithdrawSPL( chainID, nonce, amount uint64, decimals uint8, - tokenAccount, to, toAta solana.PublicKey, + mintAccount, to, toAta solana.PublicKey, ) *MsgWithdrawSPL { return &MsgWithdrawSPL{ chainID: chainID, @@ -147,7 +147,7 @@ func NewMsgWithdrawSPL( amount: amount, to: to, recipientAta: toAta, - tokenAccount: tokenAccount, + mintAccount: mintAccount, decimals: decimals, } } @@ -176,8 +176,8 @@ func (msg *MsgWithdrawSPL) RecipientAta() solana.PublicKey { return msg.recipientAta } -func (msg *MsgWithdrawSPL) TokenAccount() solana.PublicKey { - return msg.tokenAccount +func (msg *MsgWithdrawSPL) MintAccount() solana.PublicKey { + return msg.mintAccount } func (msg *MsgWithdrawSPL) Decimals() uint8 { @@ -200,7 +200,7 @@ func (msg *MsgWithdrawSPL) Hash() [32]byte { binary.BigEndian.PutUint64(buff, msg.amount) message = append(message, buff...) - message = append(message, msg.tokenAccount.Bytes()...) + message = append(message, msg.mintAccount.Bytes()...) message = append(message, msg.recipientAta.Bytes()...) diff --git a/pkg/contracts/solana/gateway_message_test.go b/pkg/contracts/solana/gateway_message_test.go index 68af93e859..f291a408cf 100644 --- a/pkg/contracts/solana/gateway_message_test.go +++ b/pkg/contracts/solana/gateway_message_test.go @@ -1,8 +1,6 @@ package solana_test import ( - "bytes" - "encoding/hex" "testing" "github.com/stretchr/testify/require" @@ -10,10 +8,12 @@ import ( "github.com/gagliardetto/solana-go" "github.com/zeta-chain/node/pkg/chains" contracts "github.com/zeta-chain/node/pkg/contracts/solana" + "github.com/zeta-chain/node/testutil" ) func Test_MsgWithdrawHash(t *testing.T) { - t.Run("should pass for archived inbound, receipt and cctx", func(t *testing.T) { + t.Run("should calculate expected hash", func(t *testing.T) { + // ARRANGE // #nosec G115 always positive chainID := uint64(chains.SolanaLocalnet.ChainId) nonce := uint64(0) @@ -21,17 +21,20 @@ func Test_MsgWithdrawHash(t *testing.T) { to := solana.MustPublicKeyFromBase58("37yGiHAnLvWZUNVwu9esp74YQFqxU1qHCbABkDvRddUQ") wantHash := "aa609ef9480303e8d743f6e36fe1bea0cc56b8d27dcbd8220846125c1181b681" - wantHashBytes, err := hex.DecodeString(wantHash) - require.NoError(t, err) + wantHashBytes := testutil.HexToBytes(t, wantHash) + // ACT // create new withdraw message hash := contracts.NewMsgWithdraw(chainID, nonce, amount, to).Hash() - require.True(t, bytes.Equal(hash[:], wantHashBytes)) + + // ASSERT + require.EqualValues(t, hash[:], wantHashBytes) }) } func Test_MsgWhitelistHash(t *testing.T) { - t.Run("should pass for archived inbound, receipt and cctx", func(t *testing.T) { + t.Run("should calculate expected hash", func(t *testing.T) { + // ARRANGE // #nosec G115 always positive chainID := uint64(chains.SolanaLocalnet.ChainId) nonce := uint64(0) @@ -39,11 +42,37 @@ func Test_MsgWhitelistHash(t *testing.T) { whitelistEntry := solana.MustPublicKeyFromBase58("2kJndCL9NBR36ySiQ4bmArs4YgWQu67LmCDfLzk5Gb7s") wantHash := "cde8fa3ab24b50320db1c47f30492e789177d28e76208176f0a52b8ed54ce2dd" - wantHashBytes, err := hex.DecodeString(wantHash) - require.NoError(t, err) + wantHashBytes := testutil.HexToBytes(t, wantHash) + // ACT // create new withdraw message hash := contracts.NewMsgWhitelist(whitelistCandidate, whitelistEntry, chainID, nonce).Hash() - require.True(t, bytes.Equal(hash[:], wantHashBytes)) + + // ASSERT + require.EqualValues(t, hash[:], wantHashBytes) + }) +} + +func Test_MsgWithdrawSPLHash(t *testing.T) { + t.Run("should calculate expected hash", func(t *testing.T) { + // ARRANGE + // #nosec G115 always positive + chainID := uint64(chains.SolanaLocalnet.ChainId) + nonce := uint64(0) + amount := uint64(1336000) + mintAccount := solana.MustPublicKeyFromBase58("AS48jKNQsDGkEdDvfwu1QpqjtqbCadrAq9nGXjFmdX3Z") + to := solana.MustPublicKeyFromBase58("37yGiHAnLvWZUNVwu9esp74YQFqxU1qHCbABkDvRddUQ") + toAta, _, err := solana.FindAssociatedTokenAddress(to, mintAccount) + require.NoError(t, err) + + wantHash := "87fa5c0ed757c6e1ea9d8976537eaf7868bc1f1bbf55ab198a01645d664fe0ae" + wantHashBytes := testutil.HexToBytes(t, wantHash) + + // ACT + // create new withdraw message + hash := contracts.NewMsgWithdrawSPL(chainID, nonce, amount, 8, mintAccount, to, toAta).Hash() + + // ASSERT + require.EqualValues(t, hash[:], wantHashBytes) }) } diff --git a/pkg/contracts/solana/inbound.go b/pkg/contracts/solana/inbound.go index 766f84aa58..3b2e153606 100644 --- a/pkg/contracts/solana/inbound.go +++ b/pkg/contracts/solana/inbound.go @@ -94,34 +94,53 @@ func ParseInboundAsDepositSPL( }, nil } -// GetSignerDeposit returns the signer address of the deposit instruction -// Note: solana-go is not able to parse the AccountMeta 'is_signer' ATM. This is a workaround. +// getSignerDeposit returns the signer address of the deposit instruction func getSignerDeposit(tx *solana.Transaction, inst *solana.CompiledInstruction) (string, error) { + instructionAccounts, err := inst.ResolveInstructionAccounts(&tx.Message) + if err != nil { + return "", err + } + // there should be 3 accounts for a deposit instruction - if len(inst.Accounts) != accountsNumDeposit { - return "", fmt.Errorf("want %d accounts, got %d", accountsNumDeposit, len(inst.Accounts)) + if len(instructionAccounts) != accountsNumDeposit { + return "", fmt.Errorf("want %d accounts, got %d", accountsNumDeposit, len(instructionAccounts)) } - // sender is the signer account - return tx.Message.AccountKeys[0].String(), nil + // the accounts are [signer, pda, system_program] + // check if first account is signer + if !instructionAccounts[0].IsSigner { + return "", fmt.Errorf("not signer %s", instructionAccounts[0].PublicKey.String()) + } + + return instructionAccounts[0].PublicKey.String(), nil } +// getSignerAndSPLFromDepositSPLAccounts returns the signer and spl address of the deposit_spl instruction func getSignerAndSPLFromDepositSPLAccounts( tx *solana.Transaction, inst *solana.CompiledInstruction, ) (string, string, error) { + instructionAccounts, err := inst.ResolveInstructionAccounts(&tx.Message) + if err != nil { + return "", "", err + } + // there should be 7 accounts for a deposit spl instruction - if len(inst.Accounts) != accountsNumberDepositSPL { + if len(instructionAccounts) != accountsNumberDepositSPL { return "", "", fmt.Errorf( "want %d accounts, got %d", accountsNumberDepositSPL, - len(inst.Accounts), + len(instructionAccounts), ) } - // the accounts are [signer, pda, whitelist_entry, mint_account, token_program, from, to] - signer := tx.Message.AccountKeys[0] - spl := tx.Message.AccountKeys[inst.Accounts[3]] + // check if first account is signer + if !instructionAccounts[0].IsSigner { + return "", "", fmt.Errorf("not signer %s", instructionAccounts[0].PublicKey.String()) + } + + signer := instructionAccounts[0].PublicKey.String() + spl := instructionAccounts[3].PublicKey.String() - return signer.String(), spl.String(), nil + return signer, spl, nil } diff --git a/pkg/contracts/solana/inbound_test.go b/pkg/contracts/solana/inbound_test.go index 7b19badf7a..b6550d99fd 100644 --- a/pkg/contracts/solana/inbound_test.go +++ b/pkg/contracts/solana/inbound_test.go @@ -8,7 +8,9 @@ import ( "path/filepath" "testing" + "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" + "github.com/near/borsh-go" "github.com/stretchr/testify/require" "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/testutil/sample" @@ -36,6 +38,7 @@ func LoadSolanaInboundTxResult( } func Test_ParseInboundAsDeposit(t *testing.T) { + // ARRANGE txHash := "MS3MPLN7hkbyCZFwKqXcg8fmEvQMD74fN6Ps2LSWXJoRxPW5ehaxBorK9q1JFVbqnAvu9jXm6ertj7kT7HpYw1j" chain := chains.SolanaDevnet @@ -43,8 +46,6 @@ func Test_ParseInboundAsDeposit(t *testing.T) { tx, err := txResult.Transaction.GetTransaction() require.NoError(t, err) - require.NoError(t, err) - // create observer chainParams := sample.ChainParams(chain.ChainId) chainParams.GatewayAddress = testutils.OldSolanaGatewayAddressDevnet @@ -61,15 +62,84 @@ func Test_ParseInboundAsDeposit(t *testing.T) { } t.Run("should parse inbound event deposit SOL", func(t *testing.T) { + // ACT deposit, err := ParseInboundAsDeposit(tx, 0, txResult.Slot) require.NoError(t, err) - // check result + // ASSERT require.EqualValues(t, expectedDeposit, deposit) }) + + t.Run("should skip parsing if wrong discriminator", func(t *testing.T) { + // ARRANGE + txResult := LoadSolanaInboundTxResult(t, txHash) + tx, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + instruction := tx.Message.Instructions[0] + + // try deserializing instruction as a 'deposit' + var inst DepositInstructionParams + err = borsh.Deserialize(&inst, instruction.Data) + require.NoError(t, err) + + // serialize it back with wrong discriminator + data, err := borsh.Serialize(DepositInstructionParams{ + Amount: inst.Amount, + Discriminator: DiscriminatorDepositSPL, + Memo: inst.Memo, + }) + require.NoError(t, err) + + tx.Message.Instructions[0].Data = data + + // ACT + deposit, err := ParseInboundAsDeposit(tx, 0, txResult.Slot) + + // ASSERT + require.NoError(t, err) + require.Nil(t, deposit) + }) + + t.Run("should fail if wrong accounts count", func(t *testing.T) { + // ARRANGE + txResult := LoadSolanaInboundTxResult(t, txHash) + tx, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + // append one more account to instruction + tx.Message.AccountKeys = append(tx.Message.AccountKeys, solana.MustPublicKeyFromBase58(sample.SolanaAddress(t))) + tx.Message.Instructions[0].Accounts = append(tx.Message.Instructions[0].Accounts, 4) + + // ACT + deposit, err := ParseInboundAsDeposit(tx, 0, txResult.Slot) + + // ASSERT + require.Error(t, err) + require.Nil(t, deposit) + }) + + t.Run("should fail if first account is not signer", func(t *testing.T) { + // ARRANGE + txResult := LoadSolanaInboundTxResult(t, txHash) + tx, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + // switch account places + tx.Message.Instructions[0].Accounts[0] = 1 + tx.Message.Instructions[0].Accounts[1] = 0 + + // ACT + deposit, err := ParseInboundAsDeposit(tx, 0, txResult.Slot) + + // ASSERT + require.Error(t, err) + require.Nil(t, deposit) + }) } func Test_ParseInboundAsDepositSPL(t *testing.T) { + // ARRANGE txHash := "aY8yLDze6nHSRi7L5REozKAZY1aAyPJ6TfibiqQL5JGwgSBkYux5z5JfXs5ed8LZqpXUy4VijoU3x15mBd66ZGE" chain := chains.SolanaDevnet @@ -96,10 +166,78 @@ func Test_ParseInboundAsDepositSPL(t *testing.T) { } t.Run("should parse inbound event deposit SPL", func(t *testing.T) { + // ACT deposit, err := ParseInboundAsDepositSPL(tx, 0, txResult.Slot) require.NoError(t, err) - // check result + // ASSERT require.EqualValues(t, expectedDeposit, deposit) }) + + t.Run("should skip parsing if wrong discriminator", func(t *testing.T) { + // ARRANGE + txResult := LoadSolanaInboundTxResult(t, txHash) + tx, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + instruction := tx.Message.Instructions[0] + + // try deserializing instruction as a 'deposit_spl' + var inst DepositSPLInstructionParams + err = borsh.Deserialize(&inst, instruction.Data) + require.NoError(t, err) + + // serialize it back with wrong discriminator + data, err := borsh.Serialize(DepositInstructionParams{ + Amount: inst.Amount, + Discriminator: DiscriminatorDeposit, + Memo: inst.Memo, + }) + require.NoError(t, err) + + tx.Message.Instructions[0].Data = data + + // ACT + deposit, err := ParseInboundAsDepositSPL(tx, 0, txResult.Slot) + + // ASSERT + require.NoError(t, err) + require.Nil(t, deposit) + }) + + t.Run("should fail if wrong accounts count", func(t *testing.T) { + // ARRANGE + txResult := LoadSolanaInboundTxResult(t, txHash) + tx, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + // append one more account to instruction + tx.Message.AccountKeys = append(tx.Message.AccountKeys, solana.MustPublicKeyFromBase58(sample.SolanaAddress(t))) + tx.Message.Instructions[0].Accounts = append(tx.Message.Instructions[0].Accounts, 4) + + // ACT + deposit, err := ParseInboundAsDepositSPL(tx, 0, txResult.Slot) + + // ASSERT + require.Error(t, err) + require.Nil(t, deposit) + }) + + t.Run("should fail if first account is not signer", func(t *testing.T) { + // ARRANGE + txResult := LoadSolanaInboundTxResult(t, txHash) + tx, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + // switch account places + tx.Message.Instructions[0].Accounts[0] = 1 + tx.Message.Instructions[0].Accounts[1] = 0 + + // ACT + deposit, err := ParseInboundAsDepositSPL(tx, 0, txResult.Slot) + + // ASSERT + require.Error(t, err) + require.Nil(t, deposit) + }) } diff --git a/pkg/contracts/solana/instruction.go b/pkg/contracts/solana/instruction.go index 44aa80c16b..9bd216d338 100644 --- a/pkg/contracts/solana/instruction.go +++ b/pkg/contracts/solana/instruction.go @@ -128,6 +128,7 @@ type WithdrawSPLInstructionParams struct { // Discriminator is the unique identifier for the withdraw instruction Discriminator [8]byte + // Decimals is decimals for spl token Decimals uint8 // Amount is the lamports amount for the withdraw diff --git a/zetaclient/chains/solana/observer/outbound_test.go b/zetaclient/chains/solana/observer/outbound_test.go index bdda96c451..020c781b3a 100644 --- a/zetaclient/chains/solana/observer/outbound_test.go +++ b/zetaclient/chains/solana/observer/outbound_test.go @@ -38,6 +38,9 @@ const ( // whitelistTxTest is local devnet tx result for testing whitelistTxTest = "phM9bESbiqojmpkkUxgjed8EABkxvPGNau9q31B8Yk1sXUtsxJvd6G9VbZZQPsEyn6RiTH4YBtqJ89omqfbbNNY" + + // withdrawSPLTxTest is local devnet tx result for testing + withdrawSPLTxTest = "3NgoR4K9FJq7UunorPRGW9wpqMV8oNvZERejutd7bKmqh3CKEV5DMZndhZn7hQ1i4RhTyHXRWxtR5ZNVHmmjAUSF" ) // createTestObserver creates a test observer for testing @@ -60,6 +63,7 @@ func createTestObserver( } func Test_CheckFinalizedTx(t *testing.T) { + // ARRANGE // the test chain and transaction hash chain := chains.SolanaDevnet txHash := withdrawTxTest @@ -83,18 +87,25 @@ func Test_CheckFinalizedTx(t *testing.T) { ctx := context.Background() t.Run("should successfully check finalized tx", func(t *testing.T) { + // ACT tx, finalized := ob.CheckFinalizedTx(ctx, txHash, nonce, coinType) + + // ASSERT require.True(t, finalized) require.NotNil(t, tx) }) t.Run("should return error on invalid tx hash", func(t *testing.T) { + // ACT tx, finalized := ob.CheckFinalizedTx(ctx, "invalid_hash_1234", nonce, coinType) + + // ASSERT require.False(t, finalized) require.Nil(t, tx) }) t.Run("should return error on GetTransaction error", func(t *testing.T) { + // ARRANGE // mock GetTransaction error client := mocks.NewSolanaRPCClient(t) client.On("GetTransaction", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("error")) @@ -102,12 +113,16 @@ func Test_CheckFinalizedTx(t *testing.T) { // create observer ob := createTestObserver(t, chain, client, tss) + // ACT tx, finalized := ob.CheckFinalizedTx(ctx, txHash, nonce, coinType) + + // ASSERT require.False(t, finalized) require.Nil(t, tx) }) t.Run("should return error on if transaction is failed", func(t *testing.T) { + // ARRANGE // load archived outbound tx result which is failed due to nonce mismatch failedResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHashFailed) @@ -118,31 +133,44 @@ func Test_CheckFinalizedTx(t *testing.T) { // create observer ob := createTestObserver(t, chain, client, tss) + // ACT tx, finalized := ob.CheckFinalizedTx(ctx, txHash, nonce, coinType) + + // ASSERT require.False(t, finalized) require.Nil(t, tx) }) t.Run("should return error on ParseGatewayInstruction error", func(t *testing.T) { + // ACT // use CoinType_Zeta to cause ParseGatewayInstruction error tx, finalized := ob.CheckFinalizedTx(ctx, txHash, nonce, coin.CoinType_Zeta) + + // ASSERT require.False(t, finalized) require.Nil(t, tx) }) t.Run("should return error on ECDSA signer mismatch", func(t *testing.T) { + // ARRANGE // create observer with other TSS address tssOther := mocks.NewMockTSS(chain, sample.EthAddress().String(), "") ob := createTestObserver(t, chain, solClient, tssOther) + // ACT tx, finalized := ob.CheckFinalizedTx(ctx, txHash, nonce, coinType) + + // ASSERT require.False(t, finalized) require.Nil(t, tx) }) t.Run("should return error on nonce mismatch", func(t *testing.T) { + // ACT // use different nonce tx, finalized := ob.CheckFinalizedTx(ctx, txHash, nonce+1, coinType) + + // ASSERT require.False(t, finalized) require.Nil(t, tx) }) @@ -159,13 +187,16 @@ func Test_ParseGatewayInstruction(t *testing.T) { require.NoError(t, err) t.Run("should parse gateway instruction", func(t *testing.T) { + // ARRANGE // load archived outbound tx result txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) + // ACT // parse gateway instruction inst, err := observer.ParseGatewayInstruction(txResult, gatewayID, coin.CoinType_Gas) require.NoError(t, err) + // ASSERT // check sender, nonce and amount sender, err := inst.Signer() require.NoError(t, err) @@ -175,6 +206,7 @@ func Test_ParseGatewayInstruction(t *testing.T) { }) t.Run("should return error on invalid number of instructions", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) tx, err := txResult.Transaction.GetTransaction() @@ -183,12 +215,16 @@ func Test_ParseGatewayInstruction(t *testing.T) { // remove all instructions tx.Message.Instructions = nil + // ACT inst, err := observer.ParseGatewayInstruction(txResult, gatewayID, coin.CoinType_Gas) + + // ASSERT require.ErrorContains(t, err, "want 1 instruction, got 0") require.Nil(t, inst) }) t.Run("should return error on invalid program id index", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) tx, err := txResult.Transaction.GetTransaction() @@ -197,12 +233,16 @@ func Test_ParseGatewayInstruction(t *testing.T) { // set invalid program id index (out of range) tx.Message.Instructions[0].ProgramIDIndex = 4 + // ACT inst, err := observer.ParseGatewayInstruction(txResult, gatewayID, coin.CoinType_Gas) + + // ASSERT require.ErrorContains(t, err, "error getting program ID") require.Nil(t, inst) }) t.Run("should return error when invoked program is not gateway", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) tx, err := txResult.Transaction.GetTransaction() @@ -211,12 +251,16 @@ func Test_ParseGatewayInstruction(t *testing.T) { // set invalid program id index (pda account index) tx.Message.Instructions[0].ProgramIDIndex = 1 + // ACT inst, err := observer.ParseGatewayInstruction(txResult, gatewayID, coin.CoinType_Gas) + + // ASSERT require.ErrorContains(t, err, "not matching gatewayID") require.Nil(t, inst) }) t.Run("should return error when instruction parsing fails", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) tx, err := txResult.Transaction.GetTransaction() @@ -225,16 +269,23 @@ func Test_ParseGatewayInstruction(t *testing.T) { // set invalid instruction data to cause parsing error tx.Message.Instructions[0].Data = []byte("invalid instruction data") + // ACT inst, err := observer.ParseGatewayInstruction(txResult, gatewayID, coin.CoinType_Gas) + + // ASSERT require.Error(t, err) require.Nil(t, inst) }) t.Run("should return error on unsupported coin type", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) + // ACT inst, err := observer.ParseGatewayInstruction(txResult, gatewayID, coin.CoinType_Zeta) + + // ASSERT require.ErrorContains(t, err, "unsupported outbound coin type") require.Nil(t, inst) }) @@ -247,15 +298,19 @@ func Test_ParseInstructionWithdraw(t *testing.T) { txAmount := uint64(890880) t.Run("should parse instruction withdraw", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) tx, err := txResult.Transaction.GetTransaction() require.NoError(t, err) instruction := tx.Message.Instructions[0] + + // ACT inst, err := contracts.ParseInstructionWithdraw(instruction) require.NoError(t, err) + // ASSERT // check sender, nonce and amount sender, err := inst.Signer() require.NoError(t, err) @@ -265,6 +320,7 @@ func Test_ParseInstructionWithdraw(t *testing.T) { }) t.Run("should return error on invalid instruction data", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) txFake, err := txResult.Transaction.GetTransaction() @@ -274,12 +330,16 @@ func Test_ParseInstructionWithdraw(t *testing.T) { instruction := txFake.Message.Instructions[0] instruction.Data = []byte("invalid instruction data") + // ACT inst, err := contracts.ParseInstructionWithdraw(instruction) + + // ASSERT require.ErrorContains(t, err, "error deserializing instruction") require.Nil(t, inst) }) t.Run("should return error on discriminator mismatch", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) txFake, err := txResult.Transaction.GetTransaction() @@ -292,7 +352,10 @@ func Test_ParseInstructionWithdraw(t *testing.T) { require.NoError(t, err) copy(instruction.Data, fakeDiscriminatorBytes) + // ACT inst, err := contracts.ParseInstructionWithdraw(instruction) + + // ASSERT require.ErrorContains(t, err, "not a withdraw instruction") require.Nil(t, inst) }) @@ -305,6 +368,7 @@ func Test_ParseInstructionWhitelist(t *testing.T) { txAmount := uint64(0) t.Run("should parse instruction whitelist", func(t *testing.T) { + // ARRANGE // tss address used in local devnet tssAddress := "0x7E8c7bAcd3c6220DDC35A4EA1141BE14F2e1dFEB" // load and unmarshal archived transaction @@ -313,9 +377,12 @@ func Test_ParseInstructionWhitelist(t *testing.T) { require.NoError(t, err) instruction := tx.Message.Instructions[0] + + // ACT inst, err := contracts.ParseInstructionWhitelist(instruction) require.NoError(t, err) + // ASSERT // check sender, nonce and amount sender, err := inst.Signer() require.NoError(t, err) @@ -325,6 +392,7 @@ func Test_ParseInstructionWhitelist(t *testing.T) { }) t.Run("should return error on invalid instruction data", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) txFake, err := txResult.Transaction.GetTransaction() @@ -334,12 +402,16 @@ func Test_ParseInstructionWhitelist(t *testing.T) { instruction := txFake.Message.Instructions[0] instruction.Data = []byte("invalid instruction data") + // ACT inst, err := contracts.ParseInstructionWhitelist(instruction) + + // ASSERT require.ErrorContains(t, err, "error deserializing instruction") require.Nil(t, inst) }) t.Run("should return error on discriminator mismatch", func(t *testing.T) { + // ARRANGE // load and unmarshal archived transaction txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) txFake, err := txResult.Transaction.GetTransaction() @@ -352,8 +424,85 @@ func Test_ParseInstructionWhitelist(t *testing.T) { require.NoError(t, err) copy(instruction.Data, fakeDiscriminatorBytes) + // ACT inst, err := contracts.ParseInstructionWhitelist(instruction) + + // ASSERT require.ErrorContains(t, err, "not a whitelist_spl_mint instruction") require.Nil(t, inst) }) } + +func Test_ParseInstructionWithdrawSPL(t *testing.T) { + // the test chain and transaction hash + chain := chains.SolanaDevnet + txHash := withdrawSPLTxTest + txAmount := uint64(1000000) + + t.Run("should parse instruction withdraw spl", func(t *testing.T) { + // ARRANGE + // tss address used in local devnet + tssAddress := "0x9c427Bc95cC11dE0D3Fb7603A99833e8f781Cfba" + // load and unmarshal archived transaction + txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) + tx, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + instruction := tx.Message.Instructions[0] + + // ACT + inst, err := contracts.ParseInstructionWithdrawSPL(instruction) + require.NoError(t, err) + + // ASSERT + // check sender, nonce and amount + sender, err := inst.Signer() + require.NoError(t, err) + require.Equal(t, tssAddress, sender.String()) + require.EqualValues(t, 3, inst.GatewayNonce()) + require.EqualValues(t, txAmount, inst.TokenAmount()) + require.EqualValues(t, 6, inst.Decimals) + require.EqualValues(t, contracts.DiscriminatorWithdrawSPL, inst.Discriminator) + }) + + t.Run("should return error on invalid instruction data", func(t *testing.T) { + // ARRANGE + // load and unmarshal archived transaction + txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) + txFake, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + // set invalid instruction data + instruction := txFake.Message.Instructions[0] + instruction.Data = []byte("invalid instruction data") + + // ACT + inst, err := contracts.ParseInstructionWithdrawSPL(instruction) + + // ASSERT + require.ErrorContains(t, err, "error deserializing instruction") + require.Nil(t, inst) + }) + + t.Run("should return error on discriminator mismatch", func(t *testing.T) { + // ARRANGE + // load and unmarshal archived transaction + txResult := testutils.LoadSolanaOutboundTxResult(t, TestDataDir, chain.ChainId, txHash) + txFake, err := txResult.Transaction.GetTransaction() + require.NoError(t, err) + + // overwrite discriminator (first 8 bytes) + instruction := txFake.Message.Instructions[0] + fakeDiscriminator := "b712469c946da12100980d0000000000" + fakeDiscriminatorBytes, err := hex.DecodeString(fakeDiscriminator) + require.NoError(t, err) + copy(instruction.Data, fakeDiscriminatorBytes) + + // ACT + inst, err := contracts.ParseInstructionWithdrawSPL(instruction) + + // ASSERT + require.ErrorContains(t, err, "not a withdraw instruction") + require.Nil(t, inst) + }) +} diff --git a/zetaclient/chains/solana/signer/withdraw_spl.go b/zetaclient/chains/solana/signer/withdraw_spl.go index bf03260eca..aaeae17f38 100644 --- a/zetaclient/chains/solana/signer/withdraw_spl.go +++ b/zetaclient/chains/solana/signer/withdraw_spl.go @@ -39,20 +39,20 @@ func (signer *Signer) createAndSignMsgWithdrawSPL( return nil, errors.Wrapf(err, "cannot decode receiver address %s", params.Receiver) } - // parse token account - tokenAccount, err := solana.PublicKeyFromBase58(asset) + // parse mint account + mintAccount, err := solana.PublicKeyFromBase58(asset) if err != nil { return nil, errors.Wrapf(err, "cannot parse asset public key %s", asset) } // get recipient ata - recipientAta, _, err := solana.FindAssociatedTokenAddress(to, tokenAccount) + recipientAta, _, err := solana.FindAssociatedTokenAddress(to, mintAccount) if err != nil { - return nil, errors.Wrapf(err, "cannot find ATA for %s and token account %s", to, tokenAccount) + return nil, errors.Wrapf(err, "cannot find ATA for %s and mint account %s", to, mintAccount) } // prepare withdraw spl msg and compute hash - msg := contracts.NewMsgWithdrawSPL(chainID, nonce, amount, decimals, tokenAccount, to, recipientAta) + msg := contracts.NewMsgWithdrawSPL(chainID, nonce, amount, decimals, mintAccount, to, recipientAta) msgHash := msg.Hash() // sign the message with TSS to get an ECDSA signature. @@ -85,14 +85,14 @@ func (signer *Signer) signWithdrawSPLTx( return nil, errors.Wrap(err, "cannot serialize withdraw instruction") } - pdaAta, _, err := solana.FindAssociatedTokenAddress(signer.pda, msg.TokenAccount()) + pdaAta, _, err := solana.FindAssociatedTokenAddress(signer.pda, msg.MintAccount()) if err != nil { - return nil, errors.Wrapf(err, "cannot find ATA for %s and token account %s", signer.pda, msg.TokenAccount()) + return nil, errors.Wrapf(err, "cannot find ATA for %s and mint account %s", signer.pda, msg.MintAccount()) } - recipientAta, _, err := solana.FindAssociatedTokenAddress(msg.To(), msg.TokenAccount()) + recipientAta, _, err := solana.FindAssociatedTokenAddress(msg.To(), msg.MintAccount()) if err != nil { - return nil, errors.Wrapf(err, "cannot find ATA for %s and token account %s", msg.To(), msg.TokenAccount()) + return nil, errors.Wrapf(err, "cannot find ATA for %s and mint account %s", msg.To(), msg.MintAccount()) } inst := solana.GenericInstruction{ @@ -102,7 +102,7 @@ func (signer *Signer) signWithdrawSPLTx( solana.Meta(signer.relayerKey.PublicKey()).WRITE().SIGNER(), solana.Meta(signer.pda).WRITE(), solana.Meta(pdaAta).WRITE(), - solana.Meta(msg.TokenAccount()), + solana.Meta(msg.MintAccount()), solana.Meta(msg.To()), solana.Meta(recipientAta).WRITE(), solana.Meta(signer.rentPayerPda).WRITE(), diff --git a/zetaclient/testdata/solana/chain_901_outbound_tx_result_3NgoR4K9FJq7UunorPRGW9wpqMV8oNvZERejutd7bKmqh3CKEV5DMZndhZn7hQ1i4RhTyHXRWxtR5ZNVHmmjAUSF.json b/zetaclient/testdata/solana/chain_901_outbound_tx_result_3NgoR4K9FJq7UunorPRGW9wpqMV8oNvZERejutd7bKmqh3CKEV5DMZndhZn7hQ1i4RhTyHXRWxtR5ZNVHmmjAUSF.json new file mode 100644 index 0000000000..d45b665270 --- /dev/null +++ b/zetaclient/testdata/solana/chain_901_outbound_tx_result_3NgoR4K9FJq7UunorPRGW9wpqMV8oNvZERejutd7bKmqh3CKEV5DMZndhZn7hQ1i4RhTyHXRWxtR5ZNVHmmjAUSF.json @@ -0,0 +1,78 @@ +{ + "slot": 1124, + "blockTime": 1731595541, + "transaction": { + "signatures": [ + "3NgoR4K9FJq7UunorPRGW9wpqMV8oNvZERejutd7bKmqh3CKEV5DMZndhZn7hQ1i4RhTyHXRWxtR5ZNVHmmjAUSF" + ], + "message": { + "accountKeys": [ + "4kkCV8H38xirwQTkE5kL6FHNtYGHnMQQ7SkCjAxibHFK", + "9dcAyYG4bawApZocwZSyJBi9Mynf5EuKAJfifXdfkqik", + "E4hYMd283QGuJu6Gr427Ef6w2Vx538YjesKRM9pENn6a", + "A3aMngDG1mxpRcvjhY1L91x5XU11EmJEbecm7PaVojd9", + "C6KPvGDYfNusoE4yfRP21F8wK35bxCBMT69xk4xo3X79", + "EZtz4FdHsiTZN9ApRzFrCZMDKniD4RFGf5tLkWyxb6vr", + "37yGiHAnLvWZUNVwu9esp74YQFqxU1qHCbABkDvRddUQ", + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", + "11111111111111111111111111111111", + "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d" + ], + "header": { + "numRequiredSignatures": 1, + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 6 + }, + "recentBlockhash": "7ArdgHXwbb2KmpkpYguJt4wUW17gtWjB2RA4Zx26Y3k6", + "instructions": [ + { + "programIdIndex": 10, + "accounts": [ + 0, + 1, + 2, + 5, + 6, + 3, + 4, + 7, + 8, + 9 + ], + "data": "BE2bNcnGtjP96vc9ByEzi6BT8v8rm5qYr8bBZ7GutCZ3RyDXzqTJumgvBxtGVZV4BMXEF4ZSD9YnwQBfTGS7dSAZG6EwBs58tVJp44Mo4TQAQUmZXytiKREBpE8zpT948qaciT1ispFPNuyxqXQNzxN5qZi7533zm5VYP2P" + } + ] + } + }, + "meta": { + "err": null, + "fee": 5000, + "preBalances": [99999985000, 14947680, 2039280, 2039280, 100000000000, 1461600, 99978495600, 929020800, 731913600, 1, 1141440], + "postBalances": [99999980000, 14947680, 2039280, 2039280, 100000000000, 1461600, 99978495600, 929020800, 731913600, 1, 1141440], + "innerInstructions": [], + "preTokenBalances": [], + "postTokenBalances": [], + "logMessages": [ + "Program 94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d invoke [1]", + "Program log: Instruction: WithdrawSplToken Program log: recovered address [156, 66, 123, 201, 92, 193, 29, 224, 211, 251, 118, 3, 169, 152, 51, 232, 247, 129, 207, 186]", + "Program log: recovered address [156, 66, 123, 201, 92, 193, 29, 224, 211, 251, 118, 3, 169, 152, 51, 232, 247, 129, 207, 186]", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", + "Program log: Instruction: TransferChecked Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6201 of 141039 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program log: withdraw spl token successfully", + "Program 94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d consumed 66232 of 200000 compute units", + "Program 94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d success" + ], + "status": { + "Ok": null + }, + "rewards": [], + "loadedAddresses": { + "readonly": [], + "writable": [] + }, + "computeUnitsConsumed": 274892589760 + }, + "version": 0 +} \ No newline at end of file From 470ba7d8cbf373a998ecbf0d8d1212b59c872bff Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Fri, 15 Nov 2024 17:15:19 +0100 Subject: [PATCH 09/15] fix(crosschain): do not check zetachain sender for failed revert outbound (#3166) * fix(crosschain): do not check zetachain sender for failed revert outbound * fix fix newline * fix comment --- .../cctx_orchestrator_validate_outbound.go | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go index 52c8c1e10d..ffc8e9aa7d 100644 --- a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go +++ b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go @@ -320,26 +320,25 @@ func (k Keeper) processFailedZETAOutboundOnZEVM(ctx sdk.Context, cctx *types.Cro // processFailedOutboundV2 processes a failed outbound transaction for protocol version 2 // for revert, in V2 we have some assumption simplifying the logic -// - sender chain is always ZetaChain +// - sender chain is ZetaChain for regular outbound (not revert outbound) // - all coin type use the same workflow // TODO: consolidate logic with above function // https://github.com/zeta-chain/node/issues/2627 func (k Keeper) processFailedOutboundV2(ctx sdk.Context, cctx *types.CrossChainTx) error { - // check the sender is ZetaChain - zetaChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) - if err != nil { - return errors.Wrap(err, "failed to get ZetaChain chainID") - } - if cctx.InboundParams.SenderChainId != zetaChain.ChainId { - return fmt.Errorf( - "sender chain for withdraw cctx is not ZetaChain expected %d got %d", - zetaChain.ChainId, - cctx.InboundParams.SenderChainId, - ) - } - switch cctx.CctxStatus.Status { case types.CctxStatus_PendingOutbound: + // check the sender is ZetaChain + zetaChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) + if err != nil { + return errors.Wrap(err, "failed to get ZetaChain chainID") + } + if cctx.InboundParams.SenderChainId != zetaChain.ChainId { + return fmt.Errorf( + "sender chain for withdraw cctx is not ZetaChain expected %d got %d", + zetaChain.ChainId, + cctx.InboundParams.SenderChainId, + ) + } // get the chain ID of the connected chain chainID := cctx.GetCurrentOutboundParam().ReceiverChainId From 6e03cc66813857dd88fa4285f5167d60de2fd752 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Fri, 15 Nov 2024 09:44:16 -0800 Subject: [PATCH 10/15] fix(zetaclient): infinite discovery address leak (#3171) --- go.mod | 6 +++--- go.sum | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 494398e08c..34a5ace653 100644 --- a/go.mod +++ b/go.mod @@ -139,7 +139,7 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gagliardetto/binary v0.8.0 // indirect + github.com/gagliardetto/binary v0.8.0 github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/getsentry/sentry-go v0.23.0 // indirect @@ -295,7 +295,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/mod v0.17.0 golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.20.0 // indirect @@ -371,5 +371,5 @@ replace ( github.com/bnb-chain/tss-lib => github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901 github.com/ethereum/go-ethereum => github.com/zeta-chain/go-ethereum v1.13.16-0.20241022183758-422c6ef93ccc github.com/libp2p/go-libp2p => github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4 - gitlab.com/thorchain/tss/go-tss => github.com/zeta-chain/go-tss v0.0.0-20241031223543-18765295f992 + gitlab.com/thorchain/tss/go-tss => github.com/zeta-chain/go-tss v0.0.0-20241115165301-8535262eb16f ) diff --git a/go.sum b/go.sum index 97df1129f4..f55f4033cf 100644 --- a/go.sum +++ b/go.sum @@ -1527,8 +1527,8 @@ github.com/zeta-chain/go-ethereum v1.13.16-0.20241022183758-422c6ef93ccc h1:FVOt github.com/zeta-chain/go-ethereum v1.13.16-0.20241022183758-422c6ef93ccc/go.mod h1:MgO2/CmxFnj6W7v/5hrz3ypco3kHkb8856pRnFkY4xQ= github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4 h1:FmO3HfVdZ7LzxBUfg6sVzV7ilKElQU2DZm8PxJ7KcYI= github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4/go.mod h1:TBv5NY/CqWYIfUstXO1fDWrt4bDoqgCw79yihqBspg8= -github.com/zeta-chain/go-tss v0.0.0-20241031223543-18765295f992 h1:jpfOoQGHQo29CKZaAPLCjguj35ikpV4UHFI99nL3fVA= -github.com/zeta-chain/go-tss v0.0.0-20241031223543-18765295f992/go.mod h1:nqelgf4HKkqlXaVg8X38a61WfyYB+ivCt6nnjoTIgCc= +github.com/zeta-chain/go-tss v0.0.0-20241115165301-8535262eb16f h1:zKBTanf2jf/oyr3f27GgvibSdVThmCdcV9sc5/6uOyQ= +github.com/zeta-chain/go-tss v0.0.0-20241115165301-8535262eb16f/go.mod h1:nqelgf4HKkqlXaVg8X38a61WfyYB+ivCt6nnjoTIgCc= github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241021075719-d40d2e28467c h1:ZoFxMMZtivRLquXVq1sEVlT45UnTPMO1MSXtc88nDv4= github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241021075719-d40d2e28467c/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= github.com/zeta-chain/protocol-contracts-solana/go-idl v0.0.0-20241108171442-e48d82f94892 h1:oI5qCrw2SXDf2a2UYAn0tpaKHbKpJcR+XDtceyY00wE= From b5c3e0301840b90f8d55dd892963acd3908d7e79 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Mon, 18 Nov 2024 09:51:39 -0800 Subject: [PATCH 11/15] fix(zetaclient): lock pingRTT for writing (#3181) --- cmd/zetaclientd/start.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/zetaclientd/start.go b/cmd/zetaclientd/start.go index 46d204fa34..b9722c9213 100644 --- a/cmd/zetaclientd/start.go +++ b/cmd/zetaclientd/start.go @@ -231,6 +231,7 @@ func Start(_ *cobra.Command, _ []string) error { go func() { host := tssServer.GetP2PHost() pingRTT := make(map[peer.ID]int64) + pingRTTLock := sync.Mutex{} for { var wg sync.WaitGroup for _, p := range whitelistedPeers { @@ -240,6 +241,8 @@ func Start(_ *cobra.Command, _ []string) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() result := <-ping.Ping(ctx, host, p) + pingRTTLock.Lock() + defer pingRTTLock.Unlock() if result.Error != nil { masterLogger.Error().Err(result.Error).Msg("ping error") pingRTT[p] = -1 // RTT -1 indicate ping error From 9d299f05c94e9b3d781f6385578cd474cb7bb411 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Mon, 18 Nov 2024 13:07:19 -0800 Subject: [PATCH 12/15] fix(ci): move skip_checks to step (#3163) --- .github/workflows/publish-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 924706af29..02977127ff 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -44,11 +44,11 @@ jobs: echo "${{ github.ref }}" check-goreleaser: - if: inputs.skip_checks != true runs-on: ${{ vars.RELEASE_RUNNER }} steps: - uses: actions/checkout@v4 - name: Build release snapshot + if: inputs.skip_checks != true run: | make release-snapshot From 85d508a89a5bdd8a28f3561f246cf2c552b6e7da Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Wed, 20 Nov 2024 13:09:33 +0100 Subject: [PATCH 13/15] fix: support tracker processing for v2 inbounds (#3179) * add tracker processing for v2 inbound * fmt * add inbound tracker e2e test * successful test * changelgo * add comment to PR * fix tests * add back ton sidecar config * comments --- changelog.md | 4 + cmd/zetae2e/config/local.yml | 4 +- cmd/zetae2e/run.go | 26 ++++++ e2e/e2etests/e2etests.go | 13 ++- e2e/e2etests/test_inbound_trackers.go | 87 ++++++++++++++++++ e2e/runner/zeta.go | 18 ++++ zetaclient/chains/base/observer.go | 2 +- zetaclient/chains/evm/observer/inbound.go | 52 +++++++---- .../chains/evm/observer/v2_inbound_tracker.go | 88 +++++++++++++++++++ 9 files changed, 272 insertions(+), 22 deletions(-) create mode 100644 e2e/e2etests/test_inbound_trackers.go create mode 100644 zetaclient/chains/evm/observer/v2_inbound_tracker.go diff --git a/changelog.md b/changelog.md index 184790d68f..2d1b39ead5 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ ## Unreleased ### Features + * [2984](https://github.com/zeta-chain/node/pull/2984) - add Whitelist message ability to whitelist SPL tokens on Solana * [3091](https://github.com/zeta-chain/node/pull/3091) - improve build reproducability. `make release{,-build-only}` checksums should now be stable. * [3124](https://github.com/zeta-chain/node/pull/3124) - integrate SPL deposits @@ -15,6 +16,7 @@ * [3154](https://github.com/zeta-chain/node/pull/3154) - configure Solana gateway program id for E2E tests ### Refactor + * [3118](https://github.com/zeta-chain/node/pull/3118) - zetaclient: remove hsm signer * [3122](https://github.com/zeta-chain/node/pull/3122) - improve & refactor zetaclientd cli * [3125](https://github.com/zeta-chain/node/pull/3125) - drop support for header proofs @@ -22,6 +24,7 @@ * [3137](https://github.com/zeta-chain/node/pull/3137) - remove chain.Chain from zetaclientd config ### Fixes + * [3117](https://github.com/zeta-chain/node/pull/3117) - register messages for emissions module to legacy amino codec. * [3041](https://github.com/zeta-chain/node/pull/3041) - replace libp2p public DHT with private gossip peer discovery and connection gater for inbound connections * [3106](https://github.com/zeta-chain/node/pull/3106) - prevent blocked CCTX on out of gas during omnichain calls @@ -29,6 +32,7 @@ * [3149](https://github.com/zeta-chain/node/pull/3149) - abort the cctx if dust amount is detected in the revert outbound * [3155](https://github.com/zeta-chain/node/pull/3155) - fix potential panic in the Bitcoin inscription parsing * [3162](https://github.com/zeta-chain/node/pull/3162) - skip depositor fee calculation if transaction does not involve TSS address +* [3179](https://github.com/zeta-chain/node/pull/3179) - support inbound trackers for v2 cctx ## v21.0.0 diff --git a/cmd/zetae2e/config/local.yml b/cmd/zetae2e/config/local.yml index e4ec147e49..aed44fc155 100644 --- a/cmd/zetae2e/config/local.yml +++ b/cmd/zetae2e/config/local.yml @@ -110,13 +110,15 @@ contracts: wzeta: "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf" test_dapp: "0xA8D5060feb6B456e886F023709A2795373691E63" gateway: "0xa825eAa55b497AF892faca73a3797046C10B7c23" + test_dapp_v2: "0xBFF76e77D56B3C1202107f059425D56f0AEF87Ed" evm: zeta_eth: "0x733aB8b06DDDEf27Eaa72294B0d7c9cEF7f12db9" connector_eth: "0xD28D6A0b8189305551a0A8bd247a6ECa9CE781Ca" - custody: "0xff3135df4F2775f4091b81f4c7B6359CfA07862a" + custody: "0x784aE8B474aebabB74526701146a708734f6931c" erc20: "0xbD1e64A22B9F92D9Ce81aA9B4b0fFacd80215564" test_dapp: "0xBFF76e77D56B3C1202107f059425D56f0AEF87Ed" gateway: "0xF0deebCB0E9C829519C4baa794c5445171973826" + test_dapp_v2: "0xa825eAa55b497AF892faca73a3797046C10B7c23" solana: gateway_program_id: "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d" spl: "" \ No newline at end of file diff --git a/cmd/zetae2e/run.go b/cmd/zetae2e/run.go index fe52f056d5..91116f234c 100644 --- a/cmd/zetae2e/run.go +++ b/cmd/zetae2e/run.go @@ -16,6 +16,8 @@ import ( "github.com/zeta-chain/node/e2e/config" "github.com/zeta-chain/node/e2e/e2etests" "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/txserver" + "github.com/zeta-chain/node/e2e/utils" fungibletypes "github.com/zeta-chain/node/x/fungible/types" observertypes "github.com/zeta-chain/node/x/observer/types" ) @@ -104,6 +106,29 @@ func runE2ETest(cmd *cobra.Command, args []string) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + var runnerOpts []runner.E2ERunnerOption + + // if keys are defined for all policy accounts, we initialize a ZETA tx server allowing to send admin actions + emergencyKey := conf.PolicyAccounts.EmergencyPolicyAccount.RawPrivateKey.String() + operationalKey := conf.PolicyAccounts.OperationalPolicyAccount.RawPrivateKey.String() + adminKey := conf.PolicyAccounts.AdminPolicyAccount.RawPrivateKey.String() + if emergencyKey != "" && operationalKey != "" && adminKey != "" { + zetaTxServer, err := txserver.NewZetaTxServer( + conf.RPCs.ZetaCoreRPC, + []string{utils.EmergencyPolicyName, utils.OperationalPolicyName, utils.AdminPolicyName}, + []string{ + emergencyKey, + operationalKey, + adminKey, + }, + conf.ZetaChainID, + ) + if err != nil { + return err + } + runnerOpts = append(runnerOpts, runner.WithZetaTxServer(zetaTxServer)) + } + // initialize deployer runner with config testRunner, err := zetae2econfig.RunnerFromConfig( ctx, @@ -112,6 +137,7 @@ func runE2ETest(cmd *cobra.Command, args []string) error { conf, conf.DefaultAccount, logger, + runnerOpts..., ) if err != nil { return err diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index 52c7022be5..53c145372d 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -110,9 +110,10 @@ const ( Miscellaneous tests Test various functionalities not related to assets */ - TestContextUpgradeName = "context_upgrade" - TestMyTestName = "my_test" - TestDonationEtherName = "donation_ether" + TestContextUpgradeName = "context_upgrade" + TestMyTestName = "my_test" + TestDonationEtherName = "donation_ether" + TestInboundTrackersName = "inbound_trackers" /* Stress tests @@ -737,6 +738,12 @@ var AllE2ETests = []runner.E2ETest{ }, TestDonationEther, ), + runner.NewE2ETest( + TestInboundTrackersName, + "test processing inbound trackers for observation", + []runner.ArgDefinition{}, + TestInboundTrackers, + ), /* Stress tests */ diff --git a/e2e/e2etests/test_inbound_trackers.go b/e2e/e2etests/test_inbound_trackers.go new file mode 100644 index 0000000000..b26b505cf1 --- /dev/null +++ b/e2e/e2etests/test_inbound_trackers.go @@ -0,0 +1,87 @@ +package e2etests + +import ( + "math/big" + + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/utils" + "github.com/zeta-chain/node/pkg/coin" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +// TestInboundTrackers tests inbound trackers processing in ZetaClient +// It run deposits, send inbound trackers and check cctxs are mined +// IMPORTANT: the test requires inbound observation to be disabled, the following line should be uncommented: +// https://github.com/zeta-chain/node/blob/9dcb42729653e033f5ba60a77dc37e5e19b092ad/zetaclient/chains/evm/observer/inbound.go#L210 +func TestInboundTrackers(r *runner.E2ERunner, args []string) { + require.Len(r, args, 0) + + amount := big.NewInt(1e17) + + addTrackerAndWaitForCCTX := func(coinType coin.CoinType, txHash string) { + r.AddInboundTracker(coinType, txHash) + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash, r.CctxClient, r.Logger, r.CctxTimeout) + require.EqualValues(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + r.Logger.CCTX(*cctx, "cctx") + } + + // send v1 eth deposit + r.Logger.Print("🏃test v1 eth deposit") + txHash := r.DepositEtherWithAmount(amount) + addTrackerAndWaitForCCTX(coin.CoinType_Gas, txHash.Hex()) + r.Logger.Print("🍾v1 eth deposit observed") + + // send v1 erc20 deposit + r.Logger.Print("🏃test v1 erc20 deposit") + txHash = r.DepositERC20WithAmountAndMessage(r.EVMAddress(), amount, []byte{}) + addTrackerAndWaitForCCTX(coin.CoinType_ERC20, txHash.Hex()) + r.Logger.Print("🍾v1 erc20 deposit observed") + + // send v2 eth deposit + r.Logger.Print("🏃test v2 eth deposit") + tx := r.V2ETHDeposit(r.EVMAddress(), amount, gatewayevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}) + addTrackerAndWaitForCCTX(coin.CoinType_Gas, tx.Hash().Hex()) + r.Logger.Print("🍾v2 eth deposit observed") + + // send v2 eth deposit and call + r.Logger.Print("🏃test v2 eth eposit and call") + tx = r.V2ETHDepositAndCall( + r.TestDAppV2ZEVMAddr, + amount, + []byte(randomPayload(r)), + gatewayevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + addTrackerAndWaitForCCTX(coin.CoinType_Gas, tx.Hash().Hex()) + r.Logger.Print("🍾v2 eth deposit and call observed") + + // send v2 erc20 deposit + r.Logger.Print("🏃test v2 erc20 deposit") + r.ApproveERC20OnEVM(r.GatewayEVMAddr) + tx = r.V2ERC20Deposit(r.EVMAddress(), amount, gatewayevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}) + addTrackerAndWaitForCCTX(coin.CoinType_Gas, tx.Hash().Hex()) + r.Logger.Print("🍾v2 erc20 deposit observed") + + // send v2 erc20 deposit and call + r.Logger.Print("🏃test v2 erc20 deposit and call") + tx = r.V2ERC20DepositAndCall( + r.TestDAppV2ZEVMAddr, + amount, + []byte(randomPayload(r)), + gatewayevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + addTrackerAndWaitForCCTX(coin.CoinType_Gas, tx.Hash().Hex()) + r.Logger.Print("🍾v2 erc20 deposit and call observed") + + // send v2 call + r.Logger.Print("🏃test v2 call") + tx = r.V2EVMToZEMVCall( + r.TestDAppV2ZEVMAddr, + []byte(randomPayload(r)), + gatewayevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + addTrackerAndWaitForCCTX(coin.CoinType_NoAssetCall, tx.Hash().Hex()) + r.Logger.Print("🍾v2 call observed") +} diff --git a/e2e/runner/zeta.go b/e2e/runner/zeta.go index d59ef85645..fe55c3946c 100644 --- a/e2e/runner/zeta.go +++ b/e2e/runner/zeta.go @@ -15,6 +15,7 @@ import ( "github.com/zeta-chain/node/e2e/utils" "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/pkg/retry" "github.com/zeta-chain/node/x/crosschain/types" observertypes "github.com/zeta-chain/node/x/observer/types" @@ -332,3 +333,20 @@ func (r *E2ERunner) skipChainOperations(chainID int64) bool { return skip } + +// AddInboundTracker adds an inbound tracker from the tx hash +func (r *E2ERunner) AddInboundTracker(coinType coin.CoinType, txHash string) { + require.NotNil(r, r.ZetaTxServer) + + chainID, err := r.EVMClient.ChainID(r.Ctx) + require.NoError(r, err) + + msg := types.NewMsgAddInboundTracker( + r.ZetaTxServer.MustGetAccountAddressFromName(utils.EmergencyPolicyName), + chainID.Int64(), + coinType, + txHash, + ) + _, err = r.ZetaTxServer.BroadcastTx(utils.EmergencyPolicyName, msg) + require.NoError(r, err) +} diff --git a/zetaclient/chains/base/observer.go b/zetaclient/chains/base/observer.go index 67f38e627a..9056e3aa1d 100644 --- a/zetaclient/chains/base/observer.go +++ b/zetaclient/chains/base/observer.go @@ -211,7 +211,7 @@ func (ob *Observer) WithZetacoreClient(client interfaces.ZetacoreClient) *Observ return ob } -// Tss returns the tss signer for the observer. +// TSS returns the tss signer for the observer. func (ob *Observer) TSS() interfaces.TSSSigner { return ob.tss } diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index cb409f408e..d7632ac192 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -121,6 +121,7 @@ func (ob *Observer) ProcessInboundTrackers(ctx context.Context) error { if err != nil { return err } + for _, tracker := range trackers { // query tx and receipt tx, _, err := ob.TransactionByHash(tracker.TxHash) @@ -144,24 +145,35 @@ func (ob *Observer) ProcessInboundTrackers(ctx context.Context) error { } ob.Logger().Inbound.Info().Msgf("checking tracker for inbound %s chain %d", tracker.TxHash, ob.Chain().ChainId) - // check and vote on inbound tx - switch tracker.CoinType { - case coin.CoinType_Zeta: - _, err = ob.CheckAndVoteInboundTokenZeta(ctx, tx, receipt, true) - case coin.CoinType_ERC20: - _, err = ob.CheckAndVoteInboundTokenERC20(ctx, tx, receipt, true) - case coin.CoinType_Gas: - _, err = ob.CheckAndVoteInboundTokenGas(ctx, tx, receipt, true) - default: - return fmt.Errorf( - "unknown coin type %s for inbound %s chain %d", - tracker.CoinType, - tx.Hash, - ob.Chain().ChainId, - ) - } + // if the transaction is sent to the gateway, this is a v2 inbound + gatewayAddr, gateway, err := ob.GetGatewayContract() if err != nil { - return errors.Wrapf(err, "error checking and voting for inbound %s chain %d", tx.Hash, ob.Chain().ChainId) + ob.Logger().Inbound.Debug().Err(err).Msg("error getting gateway contract for processing inbound tracker") + } + if err == nil && tx != nil && ethcommon.HexToAddress(tx.To) == gatewayAddr { + if err := ob.ProcessInboundTrackerV2(ctx, gateway, tx, receipt); err != nil { + return err + } + } else { + // check and vote on inbound tx + switch tracker.CoinType { + case coin.CoinType_Zeta: + _, err = ob.CheckAndVoteInboundTokenZeta(ctx, tx, receipt, true) + case coin.CoinType_ERC20: + _, err = ob.CheckAndVoteInboundTokenERC20(ctx, tx, receipt, true) + case coin.CoinType_Gas: + _, err = ob.CheckAndVoteInboundTokenGas(ctx, tx, receipt, true) + default: + return fmt.Errorf( + "unknown coin type %s for inbound %s chain %d", + tracker.CoinType, + tx.Hash, + ob.Chain().ChainId, + ) + } + if err != nil { + return errors.Wrapf(err, "error checking and voting for inbound %s chain %d", tx.Hash, ob.Chain().ChainId) + } } } return nil @@ -186,6 +198,12 @@ func (ob *Observer) ObserveInbound(ctx context.Context, sampledLogger zerolog.Lo // increment prom counter metrics.GetBlockByNumberPerChain.WithLabelValues(ob.Chain().Name).Inc() + // uncomment this line to stop observing inbound and test observation with inbound trackers + // https://github.com/zeta-chain/node/blob/3879b5ef8b418542c82a4383263604222f0605c6/e2e/e2etests/test_inbound_trackers.go#L19 + // TODO: implement a better way to disable inbound observation + // https://github.com/zeta-chain/node/issues/3186 + //return nil + // skip if current height is too low if blockNumber < ob.ChainParams().ConfirmationCount { return fmt.Errorf("observeInbound: skipping observer, current block number %d is too low", blockNumber) diff --git a/zetaclient/chains/evm/observer/v2_inbound_tracker.go b/zetaclient/chains/evm/observer/v2_inbound_tracker.go new file mode 100644 index 0000000000..11f39fe2a5 --- /dev/null +++ b/zetaclient/chains/evm/observer/v2_inbound_tracker.go @@ -0,0 +1,88 @@ +package observer + +import ( + "context" + "fmt" + + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/onrik/ethrpc" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" + + "github.com/zeta-chain/node/zetaclient/zetacore" +) + +// ProcessInboundTrackerV2 processes inbound tracker events from the gateway +func (ob *Observer) ProcessInboundTrackerV2( + ctx context.Context, + gateway *gatewayevm.GatewayEVM, + tx *ethrpc.Transaction, + receipt *ethtypes.Receipt, +) error { + // check confirmations + if confirmed := ob.HasEnoughConfirmations(receipt, ob.LastBlock()); !confirmed { + return fmt.Errorf( + "inbound %s has not been confirmed yet: receipt block %d", + tx.Hash, + receipt.BlockNumber.Uint64(), + ) + } + + for _, log := range receipt.Logs { + if log == nil { + continue + } + + // try parsing deposit + eventDeposit, err := gateway.ParseDeposited(*log) + if err == nil { + // check if the event is processable + if !ob.checkEventProcessability( + eventDeposit.Sender, + eventDeposit.Receiver, + eventDeposit.Raw.TxHash, + eventDeposit.Payload, + ) { + return fmt.Errorf("event from inbound tracker %s is not processable", tx.Hash) + } + msg := ob.newDepositInboundVote(eventDeposit) + _, err = ob.PostVoteInbound(ctx, &msg, zetacore.PostVoteInboundExecutionGasLimit) + return err + } + + // try parsing deposit and call + eventDepositAndCall, err := gateway.ParseDepositedAndCalled(*log) + if err == nil { + // check if the event is processable + if !ob.checkEventProcessability( + eventDepositAndCall.Sender, + eventDepositAndCall.Receiver, + eventDepositAndCall.Raw.TxHash, + eventDepositAndCall.Payload, + ) { + return fmt.Errorf("event from inbound tracker %s is not processable", tx.Hash) + } + msg := ob.newDepositAndCallInboundVote(eventDepositAndCall) + _, err = ob.PostVoteInbound(ctx, &msg, zetacore.PostVoteInboundExecutionGasLimit) + return err + } + + // try parsing call + eventCall, err := gateway.ParseCalled(*log) + if err == nil { + // check if the event is processable + if !ob.checkEventProcessability( + eventCall.Sender, + eventCall.Receiver, + eventCall.Raw.TxHash, + eventCall.Payload, + ) { + return fmt.Errorf("event from inbound tracker %s is not processable", tx.Hash) + } + msg := ob.newCallInboundVote(eventCall) + _, err = ob.PostVoteInbound(ctx, &msg, zetacore.PostVoteInboundExecutionGasLimit) + return err + } + } + + return fmt.Errorf("no gateway event found in inbound tracker %s", tx.Hash) +} From f5e5adb7b72a8b38b18b07f0c642c16f21fbfa57 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Wed, 20 Nov 2024 09:43:24 -0800 Subject: [PATCH 14/15] feat(zetaclient): enable pprof http server (#3182) * feat(zetaclient): enable pprof http server * changelog * fmt --- changelog.md | 1 + cmd/zetaclientd/start.go | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/changelog.md b/changelog.md index 2d1b39ead5..378991ce1a 100644 --- a/changelog.md +++ b/changelog.md @@ -8,6 +8,7 @@ * [3091](https://github.com/zeta-chain/node/pull/3091) - improve build reproducability. `make release{,-build-only}` checksums should now be stable. * [3124](https://github.com/zeta-chain/node/pull/3124) - integrate SPL deposits * [3134](https://github.com/zeta-chain/node/pull/3134) - integrate SPL tokens withdraw to Solana +* [3182](https://github.com/zeta-chain/node/pull/3182) - enable zetaclient pprof server on port 6061 ### Tests diff --git a/cmd/zetaclientd/start.go b/cmd/zetaclientd/start.go index b9722c9213..0ac52f0690 100644 --- a/cmd/zetaclientd/start.go +++ b/cmd/zetaclientd/start.go @@ -5,6 +5,8 @@ import ( "encoding/json" "fmt" "io" + "net/http" + _ "net/http/pprof" // #nosec G108 -- pprof enablement is intentional "os" "os/signal" "path/filepath" @@ -256,6 +258,15 @@ func Start(_ *cobra.Command, _ []string) error { time.Sleep(30 * time.Second) } }() + // pprof http server + // zetacored/cometbft is already listening for pprof on 6060 (by default) + go func() { + // #nosec G114 -- timeouts uneeded + err := http.ListenAndServe("localhost:6061", nil) + if err != nil { + log.Error().Err(err).Msg("pprof http server error") + } + }() // Generate a new TSS if keygen is set and add it into the tss server // If TSS has already been generated, and keygen was successful ; we use the existing TSS From 495235ea84580acb2229596f8da6eac589f2ed93 Mon Sep 17 00:00:00 2001 From: skosito Date: Thu, 21 Nov 2024 10:56:13 +0000 Subject: [PATCH 15/15] test(e2e): add e2e test for v2 deposit and call with swap (#3188) * add v2 deposit and call with swap test * changelog * PR comments --- changelog.md | 1 + cmd/zetae2e/local/v2.go | 1 + e2e/contracts/zevmswap/ZEVMSwapApp.abi | 45 ++++++++++ e2e/contracts/zevmswap/ZEVMSwapApp.bin | 2 +- e2e/contracts/zevmswap/ZEVMSwapApp.go | 25 +++++- e2e/contracts/zevmswap/ZEVMSwapApp.json | 47 +++++++++- e2e/contracts/zevmswap/ZEVMSwapApp.sol | 24 +++++ e2e/e2etests/e2etests.go | 7 ++ e2e/e2etests/test_v2_deposit_and_call_swap.go | 88 +++++++++++++++++++ 9 files changed, 236 insertions(+), 4 deletions(-) create mode 100644 e2e/e2etests/test_v2_deposit_and_call_swap.go diff --git a/changelog.md b/changelog.md index 378991ce1a..6992b9a706 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ * [3075](https://github.com/zeta-chain/node/pull/3075) - ton: withdraw concurrent, deposit & revert. * [3105](https://github.com/zeta-chain/node/pull/3105) - split Bitcoin E2E tests into two runners for deposit and withdraw * [3154](https://github.com/zeta-chain/node/pull/3154) - configure Solana gateway program id for E2E tests +* [3188](https://github.com/zeta-chain/node/pull/3188) - add e2e test for v2 deposit and call with swap ### Refactor diff --git a/cmd/zetae2e/local/v2.go b/cmd/zetae2e/local/v2.go index 770d7201ef..88423b9742 100644 --- a/cmd/zetae2e/local/v2.go +++ b/cmd/zetae2e/local/v2.go @@ -40,6 +40,7 @@ func startV2Tests(eg *errgroup.Group, conf config.Config, deployerRunner *runner e2etests.TestV2ERC20WithdrawAndCallName, e2etests.TestV2ERC20DepositAndCallNoMessageName, e2etests.TestV2ERC20WithdrawAndCallNoMessageName, + e2etests.TestV2DepositAndCallSwapName, )) // Test revert cases for gas token workflow diff --git a/e2e/contracts/zevmswap/ZEVMSwapApp.abi b/e2e/contracts/zevmswap/ZEVMSwapApp.abi index 50bf177b93..39b360e605 100644 --- a/e2e/contracts/zevmswap/ZEVMSwapApp.abi +++ b/e2e/contracts/zevmswap/ZEVMSwapApp.abi @@ -73,6 +73,51 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "origin", + "type": "bytes" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "chainID", + "type": "uint256" + } + ], + "internalType": "struct Context", + "name": "", + "type": "tuple" + }, + { + "internalType": "address", + "name": "zrc20", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + } + ], + "name": "onCall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/e2e/contracts/zevmswap/ZEVMSwapApp.bin b/e2e/contracts/zevmswap/ZEVMSwapApp.bin index f512145bdd..8b208b65b3 100644 --- a/e2e/contracts/zevmswap/ZEVMSwapApp.bin +++ b/e2e/contracts/zevmswap/ZEVMSwapApp.bin @@ -1 +1 @@ -60c06040523480156200001157600080fd5b50604051620012ee380380620012ee833981810160405281019062000037919062000111565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1681525050505062000158565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620000d982620000ac565b9050919050565b620000eb81620000cc565b8114620000f757600080fd5b50565b6000815190506200010b81620000e0565b92915050565b600080604083850312156200012b576200012a620000a7565b5b60006200013b85828601620000fa565b92505060206200014e85828601620000fa565b9150509250929050565b60805160a05161115b62000193600039600081816101b101526101f90152600081816101d50152818161039b0152610420015261115b6000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063a06ea8bc1461005c578063bb88b7691461008d578063bd00c9c4146100ab578063de43156e146100c9578063df73044e146100e5575b600080fd5b610076600480360381019061007191906107bc565b610115565b6040516100849291906108da565b60405180910390f35b6100956101af565b6040516100a2919061090a565b60405180910390f35b6100b36101d3565b6040516100c0919061090a565b60405180910390f35b6100e360048036038101906100de91906109ab565b6101f7565b005b6100ff60048036038101906100fa9190610a4f565b610714565b60405161010c9190610aaf565b60405180910390f35b6000606080600080868690509150868660009060149261013793929190610adb565b906101429190610b5a565b60601c90508686601490809261015a93929190610adb565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505092508083945094505050509250929050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461027c576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608061028b8585610115565b8093508194505050600267ffffffffffffffff8111156102ae576102ad610bb9565b5b6040519080825280602002602001820160405280156102dc5781602001602082028036833780820191505090505b50905086816000815181106102f4576102f3610be8565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061034357610342610be8565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b81526004016103d8929190610c26565b6020604051808303816000875af11580156103f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041b9190610c87565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b8152600401610489959493929190610db7565b6000604051808303816000875af11580156104a8573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906104d19190610f35565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa158015610520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105449190610f93565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610583929190610c26565b6020604051808303816000875af11580156105a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c69190610c87565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a866001815181106105fa576105f9610be8565b5b602002602001015161060c9190611002565b6040518363ffffffff1660e01b8152600401610629929190610c26565b6020604051808303816000875af1158015610648573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066c9190610c87565b508573ffffffffffffffffffffffffffffffffffffffff1663c7012626868560018151811061069e5761069d610be8565b5b60200260200101516040518363ffffffff1660e01b81526004016106c3929190611044565b6020604051808303816000875af11580156106e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107069190610c87565b505050505050505050505050565b606083838360405160200161072b939291906110fb565b60405160208183030381529060405290509392505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261077c5761077b610757565b5b8235905067ffffffffffffffff8111156107995761079861075c565b5b6020830191508360018202830111156107b5576107b4610761565b5b9250929050565b600080602083850312156107d3576107d261074d565b5b600083013567ffffffffffffffff8111156107f1576107f0610752565b5b6107fd85828601610766565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061083482610809565b9050919050565b61084481610829565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610884578082015181840152602081019050610869565b60008484015250505050565b6000601f19601f8301169050919050565b60006108ac8261084a565b6108b68185610855565b93506108c6818560208601610866565b6108cf81610890565b840191505092915050565b60006040820190506108ef600083018561083b565b818103602083015261090181846108a1565b90509392505050565b600060208201905061091f600083018461083b565b92915050565b600080fd5b6000606082840312156109405761093f610925565b5b81905092915050565b61095281610829565b811461095d57600080fd5b50565b60008135905061096f81610949565b92915050565b6000819050919050565b61098881610975565b811461099357600080fd5b50565b6000813590506109a58161097f565b92915050565b6000806000806000608086880312156109c7576109c661074d565b5b600086013567ffffffffffffffff8111156109e5576109e4610752565b5b6109f18882890161092a565b9550506020610a0288828901610960565b9450506040610a1388828901610996565b935050606086013567ffffffffffffffff811115610a3457610a33610752565b5b610a4088828901610766565b92509250509295509295909350565b600080600060408486031215610a6857610a6761074d565b5b6000610a7686828701610960565b935050602084013567ffffffffffffffff811115610a9757610a96610752565b5b610aa386828701610766565b92509250509250925092565b60006020820190508181036000830152610ac981846108a1565b905092915050565b600080fd5b600080fd5b60008085851115610aef57610aee610ad1565b5b83861115610b0057610aff610ad6565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b6000610b668383610b16565b82610b718135610b21565b92506014821015610bb157610bac7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802610b4d565b831692505b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b610c2081610975565b82525050565b6000604082019050610c3b600083018561083b565b610c486020830184610c17565b9392505050565b60008115159050919050565b610c6481610c4f565b8114610c6f57600080fd5b50565b600081519050610c8181610c5b565b92915050565b600060208284031215610c9d57610c9c61074d565b5b6000610cab84828501610c72565b91505092915050565b6000819050919050565b6000819050919050565b6000610ce3610cde610cd984610cb4565b610cbe565b610975565b9050919050565b610cf381610cc8565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b610d2e81610829565b82525050565b6000610d408383610d25565b60208301905092915050565b6000602082019050919050565b6000610d6482610cf9565b610d6e8185610d04565b9350610d7983610d15565b8060005b83811015610daa578151610d918882610d34565b9750610d9c83610d4c565b925050600181019050610d7d565b5085935050505092915050565b600060a082019050610dcc6000830188610c17565b610dd96020830187610cea565b8181036040830152610deb8186610d59565b9050610dfa606083018561083b565b610e076080830184610c17565b9695505050505050565b610e1a82610890565b810181811067ffffffffffffffff82111715610e3957610e38610bb9565b5b80604052505050565b6000610e4c610743565b9050610e588282610e11565b919050565b600067ffffffffffffffff821115610e7857610e77610bb9565b5b602082029050602081019050919050565b600081519050610e988161097f565b92915050565b6000610eb1610eac84610e5d565b610e42565b90508083825260208201905060208402830185811115610ed457610ed3610761565b5b835b81811015610efd5780610ee98882610e89565b845260208401935050602081019050610ed6565b5050509392505050565b600082601f830112610f1c57610f1b610757565b5b8151610f2c848260208601610e9e565b91505092915050565b600060208284031215610f4b57610f4a61074d565b5b600082015167ffffffffffffffff811115610f6957610f68610752565b5b610f7584828501610f07565b91505092915050565b600081519050610f8d81610949565b92915050565b60008060408385031215610faa57610fa961074d565b5b6000610fb885828601610f7e565b9250506020610fc985828601610e89565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061100d82610975565b915061101883610975565b925082820261102681610975565b9150828204841483151761103d5761103c610fd3565b5b5092915050565b6000604082019050818103600083015261105e81856108a1565b905061106d6020830184610c17565b9392505050565b60008160601b9050919050565b600061108c82611074565b9050919050565b600061109e82611081565b9050919050565b6110b66110b182610829565b611093565b82525050565b600081905092915050565b82818337600083830152505050565b60006110e283856110bc565b93506110ef8385846110c7565b82840190509392505050565b600061110782866110a5565b6014820191506111188284866110d6565b915081905094935050505056fea2646970667358221220e59a6599851c1ec787995687e8a35035524f5024bc92edd5c91793d9c6e77adf64736f6c63430008170033 +60c060405234801561001057600080fd5b506040516117a63803806117a683398181016040528101906100329190610104565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505050610144565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100d1826100a6565b9050919050565b6100e1816100c6565b81146100ec57600080fd5b50565b6000815190506100fe816100d8565b92915050565b6000806040838503121561011b5761011a6100a1565b5b6000610129858286016100ef565b925050602061013a858286016100ef565b9150509250929050565b60805160a05161161a61018c6000396000818161067001526106b801526000818161025b015281816102e0015281816106940152818161085a01526108df015261161a6000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80635bcfd61614610067578063a06ea8bc14610083578063bb88b769146100b4578063bd00c9c4146100d2578063de43156e146100f0578063df73044e1461010c575b600080fd5b610081600480360381019061007c9190610d33565b61013c565b005b61009d60048036038101906100989190610dd7565b6105d4565b6040516100ab929190610ec3565b60405180910390f35b6100bc61066e565b6040516100c99190610ef3565b60405180910390f35b6100da610692565b6040516100e79190610ef3565b60405180910390f35b61010a60048036038101906101059190610d33565b6106b6565b005b61012660048036038101906101219190610f0e565b610bd3565b6040516101339190610f6e565b60405180910390f35b600060608061014b85856105d4565b8093508194505050600267ffffffffffffffff81111561016e5761016d610f90565b5b60405190808252806020026020018201604052801561019c5781602001602082028036833780820191505090505b50905086816000815181106101b4576101b3610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061020357610202610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b8152600401610298929190610ffd565b6020604051808303816000875af11580156102b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102db919061105e565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b815260040161034995949392919061118e565b6000604051808303816000875af1158015610368573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610391919061130c565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa1580156103e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610404919061136a565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610443929190610ffd565b6020604051808303816000875af1158015610462573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610486919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a866001815181106104ba576104b9610fbf565b5b60200260200101516104cc91906113d9565b6040518363ffffffff1660e01b81526004016104e9929190610ffd565b6020604051808303816000875af1158015610508573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052c919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663c7012626868560018151811061055e5761055d610fbf565b5b60200260200101516040518363ffffffff1660e01b815260040161058392919061141b565b6020604051808303816000875af11580156105a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c6919061105e565b505050505050505050505050565b600060608060008086869050915086866000906014926105f693929190611455565b9061060191906114d4565b60601c90508686601490809261061993929190611455565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505092508083945094505050509250929050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461073b576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608061074a85856105d4565b8093508194505050600267ffffffffffffffff81111561076d5761076c610f90565b5b60405190808252806020026020018201604052801561079b5781602001602082028036833780820191505090505b50905086816000815181106107b3576107b2610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061080257610801610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b8152600401610897929190610ffd565b6020604051808303816000875af11580156108b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108da919061105e565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b815260040161094895949392919061118e565b6000604051808303816000875af1158015610967573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610990919061130c565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a03919061136a565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610a42929190610ffd565b6020604051808303816000875af1158015610a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a85919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a86600181518110610ab957610ab8610fbf565b5b6020026020010151610acb91906113d9565b6040518363ffffffff1660e01b8152600401610ae8929190610ffd565b6020604051808303816000875af1158015610b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2b919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663c70126268685600181518110610b5d57610b5c610fbf565b5b60200260200101516040518363ffffffff1660e01b8152600401610b8292919061141b565b6020604051808303816000875af1158015610ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc5919061105e565b505050505050505050505050565b6060838383604051602001610bea939291906115ba565b60405160208183030381529060405290509392505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600060608284031215610c3157610c30610c16565b5b81905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c6582610c3a565b9050919050565b610c7581610c5a565b8114610c8057600080fd5b50565b600081359050610c9281610c6c565b92915050565b6000819050919050565b610cab81610c98565b8114610cb657600080fd5b50565b600081359050610cc881610ca2565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610cf357610cf2610cce565b5b8235905067ffffffffffffffff811115610d1057610d0f610cd3565b5b602083019150836001820283011115610d2c57610d2b610cd8565b5b9250929050565b600080600080600060808688031215610d4f57610d4e610c0c565b5b600086013567ffffffffffffffff811115610d6d57610d6c610c11565b5b610d7988828901610c1b565b9550506020610d8a88828901610c83565b9450506040610d9b88828901610cb9565b935050606086013567ffffffffffffffff811115610dbc57610dbb610c11565b5b610dc888828901610cdd565b92509250509295509295909350565b60008060208385031215610dee57610ded610c0c565b5b600083013567ffffffffffffffff811115610e0c57610e0b610c11565b5b610e1885828601610cdd565b92509250509250929050565b610e2d81610c5a565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e6d578082015181840152602081019050610e52565b60008484015250505050565b6000601f19601f8301169050919050565b6000610e9582610e33565b610e9f8185610e3e565b9350610eaf818560208601610e4f565b610eb881610e79565b840191505092915050565b6000604082019050610ed86000830185610e24565b8181036020830152610eea8184610e8a565b90509392505050565b6000602082019050610f086000830184610e24565b92915050565b600080600060408486031215610f2757610f26610c0c565b5b6000610f3586828701610c83565b935050602084013567ffffffffffffffff811115610f5657610f55610c11565b5b610f6286828701610cdd565b92509250509250925092565b60006020820190508181036000830152610f888184610e8a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b610ff781610c98565b82525050565b60006040820190506110126000830185610e24565b61101f6020830184610fee565b9392505050565b60008115159050919050565b61103b81611026565b811461104657600080fd5b50565b60008151905061105881611032565b92915050565b60006020828403121561107457611073610c0c565b5b600061108284828501611049565b91505092915050565b6000819050919050565b6000819050919050565b60006110ba6110b56110b08461108b565b611095565b610c98565b9050919050565b6110ca8161109f565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61110581610c5a565b82525050565b600061111783836110fc565b60208301905092915050565b6000602082019050919050565b600061113b826110d0565b61114581856110db565b9350611150836110ec565b8060005b83811015611181578151611168888261110b565b975061117383611123565b925050600181019050611154565b5085935050505092915050565b600060a0820190506111a36000830188610fee565b6111b060208301876110c1565b81810360408301526111c28186611130565b90506111d16060830185610e24565b6111de6080830184610fee565b9695505050505050565b6111f182610e79565b810181811067ffffffffffffffff821117156112105761120f610f90565b5b80604052505050565b6000611223610c02565b905061122f82826111e8565b919050565b600067ffffffffffffffff82111561124f5761124e610f90565b5b602082029050602081019050919050565b60008151905061126f81610ca2565b92915050565b600061128861128384611234565b611219565b905080838252602082019050602084028301858111156112ab576112aa610cd8565b5b835b818110156112d457806112c08882611260565b8452602084019350506020810190506112ad565b5050509392505050565b600082601f8301126112f3576112f2610cce565b5b8151611303848260208601611275565b91505092915050565b60006020828403121561132257611321610c0c565b5b600082015167ffffffffffffffff8111156113405761133f610c11565b5b61134c848285016112de565b91505092915050565b60008151905061136481610c6c565b92915050565b6000806040838503121561138157611380610c0c565b5b600061138f85828601611355565b92505060206113a085828601611260565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006113e482610c98565b91506113ef83610c98565b92508282026113fd81610c98565b91508282048414831517611414576114136113aa565b5b5092915050565b600060408201905081810360008301526114358185610e8a565b90506114446020830184610fee565b9392505050565b600080fd5b600080fd5b600080858511156114695761146861144b565b5b8386111561147a57611479611450565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006114e08383611490565b826114eb813561149b565b9250601482101561152b576115267fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026114c7565b831692505b505092915050565b60008160601b9050919050565b600061154b82611533565b9050919050565b600061155d82611540565b9050919050565b61157561157082610c5a565b611552565b82525050565b600081905092915050565b82818337600083830152505050565b60006115a1838561157b565b93506115ae838584611586565b82840190509392505050565b60006115c68286611564565b6014820191506115d7828486611595565b915081905094935050505056fea2646970667358221220154bbadb87b49f8568829220c413c264d9405e5acb49ef710acf293adbd4f01564736f6c634300081a0033 diff --git a/e2e/contracts/zevmswap/ZEVMSwapApp.go b/e2e/contracts/zevmswap/ZEVMSwapApp.go index b02a69f878..ecf0ef8dc2 100644 --- a/e2e/contracts/zevmswap/ZEVMSwapApp.go +++ b/e2e/contracts/zevmswap/ZEVMSwapApp.go @@ -38,8 +38,8 @@ type Context struct { // ZEVMSwapAppMetaData contains all meta data concerning the ZEVMSwapApp contract. var ZEVMSwapAppMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router02_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"systemContract_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LowAmount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"decodeMemo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"targetZRC20\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"recipient\",\"type\":\"bytes\"}],\"name\":\"encodeMemo\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structContext\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCrossChainCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router02\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"systemContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b50604051620012ee380380620012ee833981810160405281019062000037919062000111565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1681525050505062000158565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620000d982620000ac565b9050919050565b620000eb81620000cc565b8114620000f757600080fd5b50565b6000815190506200010b81620000e0565b92915050565b600080604083850312156200012b576200012a620000a7565b5b60006200013b85828601620000fa565b92505060206200014e85828601620000fa565b9150509250929050565b60805160a05161115b62000193600039600081816101b101526101f90152600081816101d50152818161039b0152610420015261115b6000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063a06ea8bc1461005c578063bb88b7691461008d578063bd00c9c4146100ab578063de43156e146100c9578063df73044e146100e5575b600080fd5b610076600480360381019061007191906107bc565b610115565b6040516100849291906108da565b60405180910390f35b6100956101af565b6040516100a2919061090a565b60405180910390f35b6100b36101d3565b6040516100c0919061090a565b60405180910390f35b6100e360048036038101906100de91906109ab565b6101f7565b005b6100ff60048036038101906100fa9190610a4f565b610714565b60405161010c9190610aaf565b60405180910390f35b6000606080600080868690509150868660009060149261013793929190610adb565b906101429190610b5a565b60601c90508686601490809261015a93929190610adb565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505092508083945094505050509250929050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461027c576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608061028b8585610115565b8093508194505050600267ffffffffffffffff8111156102ae576102ad610bb9565b5b6040519080825280602002602001820160405280156102dc5781602001602082028036833780820191505090505b50905086816000815181106102f4576102f3610be8565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061034357610342610be8565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b81526004016103d8929190610c26565b6020604051808303816000875af11580156103f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041b9190610c87565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b8152600401610489959493929190610db7565b6000604051808303816000875af11580156104a8573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906104d19190610f35565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa158015610520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105449190610f93565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610583929190610c26565b6020604051808303816000875af11580156105a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c69190610c87565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a866001815181106105fa576105f9610be8565b5b602002602001015161060c9190611002565b6040518363ffffffff1660e01b8152600401610629929190610c26565b6020604051808303816000875af1158015610648573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066c9190610c87565b508573ffffffffffffffffffffffffffffffffffffffff1663c7012626868560018151811061069e5761069d610be8565b5b60200260200101516040518363ffffffff1660e01b81526004016106c3929190611044565b6020604051808303816000875af11580156106e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107069190610c87565b505050505050505050505050565b606083838360405160200161072b939291906110fb565b60405160208183030381529060405290509392505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261077c5761077b610757565b5b8235905067ffffffffffffffff8111156107995761079861075c565b5b6020830191508360018202830111156107b5576107b4610761565b5b9250929050565b600080602083850312156107d3576107d261074d565b5b600083013567ffffffffffffffff8111156107f1576107f0610752565b5b6107fd85828601610766565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061083482610809565b9050919050565b61084481610829565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610884578082015181840152602081019050610869565b60008484015250505050565b6000601f19601f8301169050919050565b60006108ac8261084a565b6108b68185610855565b93506108c6818560208601610866565b6108cf81610890565b840191505092915050565b60006040820190506108ef600083018561083b565b818103602083015261090181846108a1565b90509392505050565b600060208201905061091f600083018461083b565b92915050565b600080fd5b6000606082840312156109405761093f610925565b5b81905092915050565b61095281610829565b811461095d57600080fd5b50565b60008135905061096f81610949565b92915050565b6000819050919050565b61098881610975565b811461099357600080fd5b50565b6000813590506109a58161097f565b92915050565b6000806000806000608086880312156109c7576109c661074d565b5b600086013567ffffffffffffffff8111156109e5576109e4610752565b5b6109f18882890161092a565b9550506020610a0288828901610960565b9450506040610a1388828901610996565b935050606086013567ffffffffffffffff811115610a3457610a33610752565b5b610a4088828901610766565b92509250509295509295909350565b600080600060408486031215610a6857610a6761074d565b5b6000610a7686828701610960565b935050602084013567ffffffffffffffff811115610a9757610a96610752565b5b610aa386828701610766565b92509250509250925092565b60006020820190508181036000830152610ac981846108a1565b905092915050565b600080fd5b600080fd5b60008085851115610aef57610aee610ad1565b5b83861115610b0057610aff610ad6565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b6000610b668383610b16565b82610b718135610b21565b92506014821015610bb157610bac7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802610b4d565b831692505b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b610c2081610975565b82525050565b6000604082019050610c3b600083018561083b565b610c486020830184610c17565b9392505050565b60008115159050919050565b610c6481610c4f565b8114610c6f57600080fd5b50565b600081519050610c8181610c5b565b92915050565b600060208284031215610c9d57610c9c61074d565b5b6000610cab84828501610c72565b91505092915050565b6000819050919050565b6000819050919050565b6000610ce3610cde610cd984610cb4565b610cbe565b610975565b9050919050565b610cf381610cc8565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b610d2e81610829565b82525050565b6000610d408383610d25565b60208301905092915050565b6000602082019050919050565b6000610d6482610cf9565b610d6e8185610d04565b9350610d7983610d15565b8060005b83811015610daa578151610d918882610d34565b9750610d9c83610d4c565b925050600181019050610d7d565b5085935050505092915050565b600060a082019050610dcc6000830188610c17565b610dd96020830187610cea565b8181036040830152610deb8186610d59565b9050610dfa606083018561083b565b610e076080830184610c17565b9695505050505050565b610e1a82610890565b810181811067ffffffffffffffff82111715610e3957610e38610bb9565b5b80604052505050565b6000610e4c610743565b9050610e588282610e11565b919050565b600067ffffffffffffffff821115610e7857610e77610bb9565b5b602082029050602081019050919050565b600081519050610e988161097f565b92915050565b6000610eb1610eac84610e5d565b610e42565b90508083825260208201905060208402830185811115610ed457610ed3610761565b5b835b81811015610efd5780610ee98882610e89565b845260208401935050602081019050610ed6565b5050509392505050565b600082601f830112610f1c57610f1b610757565b5b8151610f2c848260208601610e9e565b91505092915050565b600060208284031215610f4b57610f4a61074d565b5b600082015167ffffffffffffffff811115610f6957610f68610752565b5b610f7584828501610f07565b91505092915050565b600081519050610f8d81610949565b92915050565b60008060408385031215610faa57610fa961074d565b5b6000610fb885828601610f7e565b9250506020610fc985828601610e89565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061100d82610975565b915061101883610975565b925082820261102681610975565b9150828204841483151761103d5761103c610fd3565b5b5092915050565b6000604082019050818103600083015261105e81856108a1565b905061106d6020830184610c17565b9392505050565b60008160601b9050919050565b600061108c82611074565b9050919050565b600061109e82611081565b9050919050565b6110b66110b182610829565b611093565b82525050565b600081905092915050565b82818337600083830152505050565b60006110e283856110bc565b93506110ef8385846110c7565b82840190509392505050565b600061110782866110a5565b6014820191506111188284866110d6565b915081905094935050505056fea2646970667358221220e59a6599851c1ec787995687e8a35035524f5024bc92edd5c91793d9c6e77adf64736f6c63430008170033", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router02_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"systemContract_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LowAmount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"decodeMemo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"targetZRC20\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"recipient\",\"type\":\"bytes\"}],\"name\":\"encodeMemo\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structContext\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structContext\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCrossChainCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router02\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"systemContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60c060405234801561001057600080fd5b506040516117a63803806117a683398181016040528101906100329190610104565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505050610144565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100d1826100a6565b9050919050565b6100e1816100c6565b81146100ec57600080fd5b50565b6000815190506100fe816100d8565b92915050565b6000806040838503121561011b5761011a6100a1565b5b6000610129858286016100ef565b925050602061013a858286016100ef565b9150509250929050565b60805160a05161161a61018c6000396000818161067001526106b801526000818161025b015281816102e0015281816106940152818161085a01526108df015261161a6000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80635bcfd61614610067578063a06ea8bc14610083578063bb88b769146100b4578063bd00c9c4146100d2578063de43156e146100f0578063df73044e1461010c575b600080fd5b610081600480360381019061007c9190610d33565b61013c565b005b61009d60048036038101906100989190610dd7565b6105d4565b6040516100ab929190610ec3565b60405180910390f35b6100bc61066e565b6040516100c99190610ef3565b60405180910390f35b6100da610692565b6040516100e79190610ef3565b60405180910390f35b61010a60048036038101906101059190610d33565b6106b6565b005b61012660048036038101906101219190610f0e565b610bd3565b6040516101339190610f6e565b60405180910390f35b600060608061014b85856105d4565b8093508194505050600267ffffffffffffffff81111561016e5761016d610f90565b5b60405190808252806020026020018201604052801561019c5781602001602082028036833780820191505090505b50905086816000815181106101b4576101b3610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061020357610202610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b8152600401610298929190610ffd565b6020604051808303816000875af11580156102b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102db919061105e565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b815260040161034995949392919061118e565b6000604051808303816000875af1158015610368573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610391919061130c565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa1580156103e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610404919061136a565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610443929190610ffd565b6020604051808303816000875af1158015610462573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610486919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a866001815181106104ba576104b9610fbf565b5b60200260200101516104cc91906113d9565b6040518363ffffffff1660e01b81526004016104e9929190610ffd565b6020604051808303816000875af1158015610508573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052c919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663c7012626868560018151811061055e5761055d610fbf565b5b60200260200101516040518363ffffffff1660e01b815260040161058392919061141b565b6020604051808303816000875af11580156105a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c6919061105e565b505050505050505050505050565b600060608060008086869050915086866000906014926105f693929190611455565b9061060191906114d4565b60601c90508686601490809261061993929190611455565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505092508083945094505050509250929050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461073b576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608061074a85856105d4565b8093508194505050600267ffffffffffffffff81111561076d5761076c610f90565b5b60405190808252806020026020018201604052801561079b5781602001602082028036833780820191505090505b50905086816000815181106107b3576107b2610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061080257610801610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b8152600401610897929190610ffd565b6020604051808303816000875af11580156108b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108da919061105e565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b815260040161094895949392919061118e565b6000604051808303816000875af1158015610967573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610990919061130c565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a03919061136a565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610a42929190610ffd565b6020604051808303816000875af1158015610a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a85919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a86600181518110610ab957610ab8610fbf565b5b6020026020010151610acb91906113d9565b6040518363ffffffff1660e01b8152600401610ae8929190610ffd565b6020604051808303816000875af1158015610b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2b919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663c70126268685600181518110610b5d57610b5c610fbf565b5b60200260200101516040518363ffffffff1660e01b8152600401610b8292919061141b565b6020604051808303816000875af1158015610ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc5919061105e565b505050505050505050505050565b6060838383604051602001610bea939291906115ba565b60405160208183030381529060405290509392505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600060608284031215610c3157610c30610c16565b5b81905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c6582610c3a565b9050919050565b610c7581610c5a565b8114610c8057600080fd5b50565b600081359050610c9281610c6c565b92915050565b6000819050919050565b610cab81610c98565b8114610cb657600080fd5b50565b600081359050610cc881610ca2565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610cf357610cf2610cce565b5b8235905067ffffffffffffffff811115610d1057610d0f610cd3565b5b602083019150836001820283011115610d2c57610d2b610cd8565b5b9250929050565b600080600080600060808688031215610d4f57610d4e610c0c565b5b600086013567ffffffffffffffff811115610d6d57610d6c610c11565b5b610d7988828901610c1b565b9550506020610d8a88828901610c83565b9450506040610d9b88828901610cb9565b935050606086013567ffffffffffffffff811115610dbc57610dbb610c11565b5b610dc888828901610cdd565b92509250509295509295909350565b60008060208385031215610dee57610ded610c0c565b5b600083013567ffffffffffffffff811115610e0c57610e0b610c11565b5b610e1885828601610cdd565b92509250509250929050565b610e2d81610c5a565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e6d578082015181840152602081019050610e52565b60008484015250505050565b6000601f19601f8301169050919050565b6000610e9582610e33565b610e9f8185610e3e565b9350610eaf818560208601610e4f565b610eb881610e79565b840191505092915050565b6000604082019050610ed86000830185610e24565b8181036020830152610eea8184610e8a565b90509392505050565b6000602082019050610f086000830184610e24565b92915050565b600080600060408486031215610f2757610f26610c0c565b5b6000610f3586828701610c83565b935050602084013567ffffffffffffffff811115610f5657610f55610c11565b5b610f6286828701610cdd565b92509250509250925092565b60006020820190508181036000830152610f888184610e8a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b610ff781610c98565b82525050565b60006040820190506110126000830185610e24565b61101f6020830184610fee565b9392505050565b60008115159050919050565b61103b81611026565b811461104657600080fd5b50565b60008151905061105881611032565b92915050565b60006020828403121561107457611073610c0c565b5b600061108284828501611049565b91505092915050565b6000819050919050565b6000819050919050565b60006110ba6110b56110b08461108b565b611095565b610c98565b9050919050565b6110ca8161109f565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61110581610c5a565b82525050565b600061111783836110fc565b60208301905092915050565b6000602082019050919050565b600061113b826110d0565b61114581856110db565b9350611150836110ec565b8060005b83811015611181578151611168888261110b565b975061117383611123565b925050600181019050611154565b5085935050505092915050565b600060a0820190506111a36000830188610fee565b6111b060208301876110c1565b81810360408301526111c28186611130565b90506111d16060830185610e24565b6111de6080830184610fee565b9695505050505050565b6111f182610e79565b810181811067ffffffffffffffff821117156112105761120f610f90565b5b80604052505050565b6000611223610c02565b905061122f82826111e8565b919050565b600067ffffffffffffffff82111561124f5761124e610f90565b5b602082029050602081019050919050565b60008151905061126f81610ca2565b92915050565b600061128861128384611234565b611219565b905080838252602082019050602084028301858111156112ab576112aa610cd8565b5b835b818110156112d457806112c08882611260565b8452602084019350506020810190506112ad565b5050509392505050565b600082601f8301126112f3576112f2610cce565b5b8151611303848260208601611275565b91505092915050565b60006020828403121561132257611321610c0c565b5b600082015167ffffffffffffffff8111156113405761133f610c11565b5b61134c848285016112de565b91505092915050565b60008151905061136481610c6c565b92915050565b6000806040838503121561138157611380610c0c565b5b600061138f85828601611355565b92505060206113a085828601611260565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006113e482610c98565b91506113ef83610c98565b92508282026113fd81610c98565b91508282048414831517611414576114136113aa565b5b5092915050565b600060408201905081810360008301526114358185610e8a565b90506114446020830184610fee565b9392505050565b600080fd5b600080fd5b600080858511156114695761146861144b565b5b8386111561147a57611479611450565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006114e08383611490565b826114eb813561149b565b9250601482101561152b576115267fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026114c7565b831692505b505092915050565b60008160601b9050919050565b600061154b82611533565b9050919050565b600061155d82611540565b9050919050565b61157561157082610c5a565b611552565b82525050565b600081905092915050565b82818337600083830152505050565b60006115a1838561157b565b93506115ae838584611586565b82840190509392505050565b60006115c68286611564565b6014820191506115d7828486611595565b915081905094935050505056fea2646970667358221220154bbadb87b49f8568829220c413c264d9405e5acb49ef710acf293adbd4f01564736f6c634300081a0033", } // ZEVMSwapAppABI is the input ABI used to generate the binding from. @@ -334,6 +334,27 @@ func (_ZEVMSwapApp *ZEVMSwapAppCallerSession) SystemContract() (common.Address, return _ZEVMSwapApp.Contract.SystemContract(&_ZEVMSwapApp.CallOpts) } +// OnCall is a paid mutator transaction binding the contract method 0x5bcfd616. +// +// Solidity: function onCall((bytes,address,uint256) , address zrc20, uint256 amount, bytes message) returns() +func (_ZEVMSwapApp *ZEVMSwapAppTransactor) OnCall(opts *bind.TransactOpts, arg0 Context, zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { + return _ZEVMSwapApp.contract.Transact(opts, "onCall", arg0, zrc20, amount, message) +} + +// OnCall is a paid mutator transaction binding the contract method 0x5bcfd616. +// +// Solidity: function onCall((bytes,address,uint256) , address zrc20, uint256 amount, bytes message) returns() +func (_ZEVMSwapApp *ZEVMSwapAppSession) OnCall(arg0 Context, zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { + return _ZEVMSwapApp.Contract.OnCall(&_ZEVMSwapApp.TransactOpts, arg0, zrc20, amount, message) +} + +// OnCall is a paid mutator transaction binding the contract method 0x5bcfd616. +// +// Solidity: function onCall((bytes,address,uint256) , address zrc20, uint256 amount, bytes message) returns() +func (_ZEVMSwapApp *ZEVMSwapAppTransactorSession) OnCall(arg0 Context, zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { + return _ZEVMSwapApp.Contract.OnCall(&_ZEVMSwapApp.TransactOpts, arg0, zrc20, amount, message) +} + // OnCrossChainCall is a paid mutator transaction binding the contract method 0xde43156e. // // Solidity: function onCrossChainCall((bytes,address,uint256) , address zrc20, uint256 amount, bytes message) returns() diff --git a/e2e/contracts/zevmswap/ZEVMSwapApp.json b/e2e/contracts/zevmswap/ZEVMSwapApp.json index 5c803781fa..b8898c7994 100644 --- a/e2e/contracts/zevmswap/ZEVMSwapApp.json +++ b/e2e/contracts/zevmswap/ZEVMSwapApp.json @@ -74,6 +74,51 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "origin", + "type": "bytes" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "chainID", + "type": "uint256" + } + ], + "internalType": "struct Context", + "name": "", + "type": "tuple" + }, + { + "internalType": "address", + "name": "zrc20", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + } + ], + "name": "onCall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -146,5 +191,5 @@ "type": "function" } ], - "bin": "60c06040523480156200001157600080fd5b50604051620012ee380380620012ee833981810160405281019062000037919062000111565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff1681525050505062000158565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620000d982620000ac565b9050919050565b620000eb81620000cc565b8114620000f757600080fd5b50565b6000815190506200010b81620000e0565b92915050565b600080604083850312156200012b576200012a620000a7565b5b60006200013b85828601620000fa565b92505060206200014e85828601620000fa565b9150509250929050565b60805160a05161115b62000193600039600081816101b101526101f90152600081816101d50152818161039b0152610420015261115b6000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063a06ea8bc1461005c578063bb88b7691461008d578063bd00c9c4146100ab578063de43156e146100c9578063df73044e146100e5575b600080fd5b610076600480360381019061007191906107bc565b610115565b6040516100849291906108da565b60405180910390f35b6100956101af565b6040516100a2919061090a565b60405180910390f35b6100b36101d3565b6040516100c0919061090a565b60405180910390f35b6100e360048036038101906100de91906109ab565b6101f7565b005b6100ff60048036038101906100fa9190610a4f565b610714565b60405161010c9190610aaf565b60405180910390f35b6000606080600080868690509150868660009060149261013793929190610adb565b906101429190610b5a565b60601c90508686601490809261015a93929190610adb565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505092508083945094505050509250929050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461027c576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608061028b8585610115565b8093508194505050600267ffffffffffffffff8111156102ae576102ad610bb9565b5b6040519080825280602002602001820160405280156102dc5781602001602082028036833780820191505090505b50905086816000815181106102f4576102f3610be8565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061034357610342610be8565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b81526004016103d8929190610c26565b6020604051808303816000875af11580156103f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041b9190610c87565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b8152600401610489959493929190610db7565b6000604051808303816000875af11580156104a8573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906104d19190610f35565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa158015610520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105449190610f93565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610583929190610c26565b6020604051808303816000875af11580156105a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c69190610c87565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a866001815181106105fa576105f9610be8565b5b602002602001015161060c9190611002565b6040518363ffffffff1660e01b8152600401610629929190610c26565b6020604051808303816000875af1158015610648573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066c9190610c87565b508573ffffffffffffffffffffffffffffffffffffffff1663c7012626868560018151811061069e5761069d610be8565b5b60200260200101516040518363ffffffff1660e01b81526004016106c3929190611044565b6020604051808303816000875af11580156106e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107069190610c87565b505050505050505050505050565b606083838360405160200161072b939291906110fb565b60405160208183030381529060405290509392505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261077c5761077b610757565b5b8235905067ffffffffffffffff8111156107995761079861075c565b5b6020830191508360018202830111156107b5576107b4610761565b5b9250929050565b600080602083850312156107d3576107d261074d565b5b600083013567ffffffffffffffff8111156107f1576107f0610752565b5b6107fd85828601610766565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061083482610809565b9050919050565b61084481610829565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610884578082015181840152602081019050610869565b60008484015250505050565b6000601f19601f8301169050919050565b60006108ac8261084a565b6108b68185610855565b93506108c6818560208601610866565b6108cf81610890565b840191505092915050565b60006040820190506108ef600083018561083b565b818103602083015261090181846108a1565b90509392505050565b600060208201905061091f600083018461083b565b92915050565b600080fd5b6000606082840312156109405761093f610925565b5b81905092915050565b61095281610829565b811461095d57600080fd5b50565b60008135905061096f81610949565b92915050565b6000819050919050565b61098881610975565b811461099357600080fd5b50565b6000813590506109a58161097f565b92915050565b6000806000806000608086880312156109c7576109c661074d565b5b600086013567ffffffffffffffff8111156109e5576109e4610752565b5b6109f18882890161092a565b9550506020610a0288828901610960565b9450506040610a1388828901610996565b935050606086013567ffffffffffffffff811115610a3457610a33610752565b5b610a4088828901610766565b92509250509295509295909350565b600080600060408486031215610a6857610a6761074d565b5b6000610a7686828701610960565b935050602084013567ffffffffffffffff811115610a9757610a96610752565b5b610aa386828701610766565b92509250509250925092565b60006020820190508181036000830152610ac981846108a1565b905092915050565b600080fd5b600080fd5b60008085851115610aef57610aee610ad1565b5b83861115610b0057610aff610ad6565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b6000610b668383610b16565b82610b718135610b21565b92506014821015610bb157610bac7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802610b4d565b831692505b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b610c2081610975565b82525050565b6000604082019050610c3b600083018561083b565b610c486020830184610c17565b9392505050565b60008115159050919050565b610c6481610c4f565b8114610c6f57600080fd5b50565b600081519050610c8181610c5b565b92915050565b600060208284031215610c9d57610c9c61074d565b5b6000610cab84828501610c72565b91505092915050565b6000819050919050565b6000819050919050565b6000610ce3610cde610cd984610cb4565b610cbe565b610975565b9050919050565b610cf381610cc8565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b610d2e81610829565b82525050565b6000610d408383610d25565b60208301905092915050565b6000602082019050919050565b6000610d6482610cf9565b610d6e8185610d04565b9350610d7983610d15565b8060005b83811015610daa578151610d918882610d34565b9750610d9c83610d4c565b925050600181019050610d7d565b5085935050505092915050565b600060a082019050610dcc6000830188610c17565b610dd96020830187610cea565b8181036040830152610deb8186610d59565b9050610dfa606083018561083b565b610e076080830184610c17565b9695505050505050565b610e1a82610890565b810181811067ffffffffffffffff82111715610e3957610e38610bb9565b5b80604052505050565b6000610e4c610743565b9050610e588282610e11565b919050565b600067ffffffffffffffff821115610e7857610e77610bb9565b5b602082029050602081019050919050565b600081519050610e988161097f565b92915050565b6000610eb1610eac84610e5d565b610e42565b90508083825260208201905060208402830185811115610ed457610ed3610761565b5b835b81811015610efd5780610ee98882610e89565b845260208401935050602081019050610ed6565b5050509392505050565b600082601f830112610f1c57610f1b610757565b5b8151610f2c848260208601610e9e565b91505092915050565b600060208284031215610f4b57610f4a61074d565b5b600082015167ffffffffffffffff811115610f6957610f68610752565b5b610f7584828501610f07565b91505092915050565b600081519050610f8d81610949565b92915050565b60008060408385031215610faa57610fa961074d565b5b6000610fb885828601610f7e565b9250506020610fc985828601610e89565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061100d82610975565b915061101883610975565b925082820261102681610975565b9150828204841483151761103d5761103c610fd3565b5b5092915050565b6000604082019050818103600083015261105e81856108a1565b905061106d6020830184610c17565b9392505050565b60008160601b9050919050565b600061108c82611074565b9050919050565b600061109e82611081565b9050919050565b6110b66110b182610829565b611093565b82525050565b600081905092915050565b82818337600083830152505050565b60006110e283856110bc565b93506110ef8385846110c7565b82840190509392505050565b600061110782866110a5565b6014820191506111188284866110d6565b915081905094935050505056fea2646970667358221220e59a6599851c1ec787995687e8a35035524f5024bc92edd5c91793d9c6e77adf64736f6c63430008170033" + "bin": "60c060405234801561001057600080fd5b506040516117a63803806117a683398181016040528101906100329190610104565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505050610144565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100d1826100a6565b9050919050565b6100e1816100c6565b81146100ec57600080fd5b50565b6000815190506100fe816100d8565b92915050565b6000806040838503121561011b5761011a6100a1565b5b6000610129858286016100ef565b925050602061013a858286016100ef565b9150509250929050565b60805160a05161161a61018c6000396000818161067001526106b801526000818161025b015281816102e0015281816106940152818161085a01526108df015261161a6000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80635bcfd61614610067578063a06ea8bc14610083578063bb88b769146100b4578063bd00c9c4146100d2578063de43156e146100f0578063df73044e1461010c575b600080fd5b610081600480360381019061007c9190610d33565b61013c565b005b61009d60048036038101906100989190610dd7565b6105d4565b6040516100ab929190610ec3565b60405180910390f35b6100bc61066e565b6040516100c99190610ef3565b60405180910390f35b6100da610692565b6040516100e79190610ef3565b60405180910390f35b61010a60048036038101906101059190610d33565b6106b6565b005b61012660048036038101906101219190610f0e565b610bd3565b6040516101339190610f6e565b60405180910390f35b600060608061014b85856105d4565b8093508194505050600267ffffffffffffffff81111561016e5761016d610f90565b5b60405190808252806020026020018201604052801561019c5781602001602082028036833780820191505090505b50905086816000815181106101b4576101b3610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061020357610202610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b8152600401610298929190610ffd565b6020604051808303816000875af11580156102b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102db919061105e565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b815260040161034995949392919061118e565b6000604051808303816000875af1158015610368573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610391919061130c565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa1580156103e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610404919061136a565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610443929190610ffd565b6020604051808303816000875af1158015610462573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610486919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a866001815181106104ba576104b9610fbf565b5b60200260200101516104cc91906113d9565b6040518363ffffffff1660e01b81526004016104e9929190610ffd565b6020604051808303816000875af1158015610508573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052c919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663c7012626868560018151811061055e5761055d610fbf565b5b60200260200101516040518363ffffffff1660e01b815260040161058392919061141b565b6020604051808303816000875af11580156105a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c6919061105e565b505050505050505050505050565b600060608060008086869050915086866000906014926105f693929190611455565b9061060191906114d4565b60601c90508686601490809261061993929190611455565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505092508083945094505050509250929050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461073b576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608061074a85856105d4565b8093508194505050600267ffffffffffffffff81111561076d5761076c610f90565b5b60405190808252806020026020018201604052801561079b5781602001602082028036833780820191505090505b50905086816000815181106107b3576107b2610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828160018151811061080257610801610fbf565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508673ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f0000000000000000000000000000000000000000000000000000000000000000886040518363ffffffff1660e01b8152600401610897929190610ffd565b6020604051808303816000875af11580156108b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108da919061105e565b5060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166338ed17398860008530680100000000000000006040518663ffffffff1660e01b815260040161094895949392919061118e565b6000604051808303816000875af1158015610967573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610990919061130c565b90506000808573ffffffffffffffffffffffffffffffffffffffff1663d9eeebed6040518163ffffffff1660e01b81526004016040805180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a03919061136a565b915091508173ffffffffffffffffffffffffffffffffffffffff1663095ea7b387836040518363ffffffff1660e01b8152600401610a42929190610ffd565b6020604051808303816000875af1158015610a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a85919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663095ea7b387600a86600181518110610ab957610ab8610fbf565b5b6020026020010151610acb91906113d9565b6040518363ffffffff1660e01b8152600401610ae8929190610ffd565b6020604051808303816000875af1158015610b07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2b919061105e565b508573ffffffffffffffffffffffffffffffffffffffff1663c70126268685600181518110610b5d57610b5c610fbf565b5b60200260200101516040518363ffffffff1660e01b8152600401610b8292919061141b565b6020604051808303816000875af1158015610ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc5919061105e565b505050505050505050505050565b6060838383604051602001610bea939291906115ba565b60405160208183030381529060405290509392505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600060608284031215610c3157610c30610c16565b5b81905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c6582610c3a565b9050919050565b610c7581610c5a565b8114610c8057600080fd5b50565b600081359050610c9281610c6c565b92915050565b6000819050919050565b610cab81610c98565b8114610cb657600080fd5b50565b600081359050610cc881610ca2565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610cf357610cf2610cce565b5b8235905067ffffffffffffffff811115610d1057610d0f610cd3565b5b602083019150836001820283011115610d2c57610d2b610cd8565b5b9250929050565b600080600080600060808688031215610d4f57610d4e610c0c565b5b600086013567ffffffffffffffff811115610d6d57610d6c610c11565b5b610d7988828901610c1b565b9550506020610d8a88828901610c83565b9450506040610d9b88828901610cb9565b935050606086013567ffffffffffffffff811115610dbc57610dbb610c11565b5b610dc888828901610cdd565b92509250509295509295909350565b60008060208385031215610dee57610ded610c0c565b5b600083013567ffffffffffffffff811115610e0c57610e0b610c11565b5b610e1885828601610cdd565b92509250509250929050565b610e2d81610c5a565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610e6d578082015181840152602081019050610e52565b60008484015250505050565b6000601f19601f8301169050919050565b6000610e9582610e33565b610e9f8185610e3e565b9350610eaf818560208601610e4f565b610eb881610e79565b840191505092915050565b6000604082019050610ed86000830185610e24565b8181036020830152610eea8184610e8a565b90509392505050565b6000602082019050610f086000830184610e24565b92915050565b600080600060408486031215610f2757610f26610c0c565b5b6000610f3586828701610c83565b935050602084013567ffffffffffffffff811115610f5657610f55610c11565b5b610f6286828701610cdd565b92509250509250925092565b60006020820190508181036000830152610f888184610e8a565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b610ff781610c98565b82525050565b60006040820190506110126000830185610e24565b61101f6020830184610fee565b9392505050565b60008115159050919050565b61103b81611026565b811461104657600080fd5b50565b60008151905061105881611032565b92915050565b60006020828403121561107457611073610c0c565b5b600061108284828501611049565b91505092915050565b6000819050919050565b6000819050919050565b60006110ba6110b56110b08461108b565b611095565b610c98565b9050919050565b6110ca8161109f565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61110581610c5a565b82525050565b600061111783836110fc565b60208301905092915050565b6000602082019050919050565b600061113b826110d0565b61114581856110db565b9350611150836110ec565b8060005b83811015611181578151611168888261110b565b975061117383611123565b925050600181019050611154565b5085935050505092915050565b600060a0820190506111a36000830188610fee565b6111b060208301876110c1565b81810360408301526111c28186611130565b90506111d16060830185610e24565b6111de6080830184610fee565b9695505050505050565b6111f182610e79565b810181811067ffffffffffffffff821117156112105761120f610f90565b5b80604052505050565b6000611223610c02565b905061122f82826111e8565b919050565b600067ffffffffffffffff82111561124f5761124e610f90565b5b602082029050602081019050919050565b60008151905061126f81610ca2565b92915050565b600061128861128384611234565b611219565b905080838252602082019050602084028301858111156112ab576112aa610cd8565b5b835b818110156112d457806112c08882611260565b8452602084019350506020810190506112ad565b5050509392505050565b600082601f8301126112f3576112f2610cce565b5b8151611303848260208601611275565b91505092915050565b60006020828403121561132257611321610c0c565b5b600082015167ffffffffffffffff8111156113405761133f610c11565b5b61134c848285016112de565b91505092915050565b60008151905061136481610c6c565b92915050565b6000806040838503121561138157611380610c0c565b5b600061138f85828601611355565b92505060206113a085828601611260565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006113e482610c98565b91506113ef83610c98565b92508282026113fd81610c98565b91508282048414831517611414576114136113aa565b5b5092915050565b600060408201905081810360008301526114358185610e8a565b90506114446020830184610fee565b9392505050565b600080fd5b600080fd5b600080858511156114695761146861144b565b5b8386111561147a57611479611450565b5b6001850283019150848603905094509492505050565b600082905092915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b600082821b905092915050565b60006114e08383611490565b826114eb813561149b565b9250601482101561152b576115267fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026114c7565b831692505b505092915050565b60008160601b9050919050565b600061154b82611533565b9050919050565b600061155d82611540565b9050919050565b61157561157082610c5a565b611552565b82525050565b600081905092915050565b82818337600083830152505050565b60006115a1838561157b565b93506115ae838584611586565b82840190509392505050565b60006115c68286611564565b6014820191506115d7828486611595565b915081905094935050505056fea2646970667358221220154bbadb87b49f8568829220c413c264d9405e5acb49ef710acf293adbd4f01564736f6c634300081a0033" } diff --git a/e2e/contracts/zevmswap/ZEVMSwapApp.sol b/e2e/contracts/zevmswap/ZEVMSwapApp.sol index e9f098699d..a25e6a3bd1 100644 --- a/e2e/contracts/zevmswap/ZEVMSwapApp.sol +++ b/e2e/contracts/zevmswap/ZEVMSwapApp.sol @@ -96,4 +96,28 @@ contract ZEVMSwapApp is zContract { IZRC20(targetZRC20).approve(address(targetZRC20), amounts[1]*10); IZRC20(targetZRC20).withdraw(recipient, amounts[1]); } + + // used with v2 contracts + function onCall(Context calldata, address zrc20, uint256 amount, bytes calldata message) external { + address targetZRC20; + bytes memory recipient; + address[] memory path; + + (targetZRC20, recipient) = decodeMemo(message); + path = new address[](2); + path[0] = zrc20; + path[1] = targetZRC20; + + // approve the usage of this token by router02 + IZRC20(zrc20).approve(address(router02), amount); + + // swap for target token + uint256[] memory amounts = IUniswapV2Router02(router02).swapExactTokensForTokens(amount, 0, path, address(this), _DEADLINE); + + // perform withdrawal with the target token + (address gasZRC20Addr,uint256 gasFee) = IZRC20(targetZRC20).withdrawGasFee(); + IZRC20(gasZRC20Addr).approve(address(targetZRC20), gasFee); + IZRC20(targetZRC20).approve(address(targetZRC20), amounts[1]*10); + IZRC20(targetZRC20).withdraw(recipient, amounts[1]); + } } \ No newline at end of file diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index 53c145372d..db99a5ce0d 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -172,6 +172,7 @@ const ( TestV2ZEVMToEVMCallName = "v2_zevm_to_evm_call" TestV2ZEVMToEVMCallThroughContractName = "v2_zevm_to_evm_call_through_contract" TestV2EVMToZEVMCallName = "v2_evm_to_zevm_call" + TestV2DepositAndCallSwapName = "v2_deposit_and_call_swap" /* Operational tests @@ -1073,6 +1074,12 @@ var AllE2ETests = []runner.E2ETest{ []runner.ArgDefinition{}, TestV2EVMToZEVMCall, ), + runner.NewE2ETest( + TestV2DepositAndCallSwapName, + "evm -> zevm deposit and call with swap and withdraw back to evm", + []runner.ArgDefinition{}, + TestV2DepositAndCallSwap, + ), /* Special tests */ diff --git a/e2e/e2etests/test_v2_deposit_and_call_swap.go b/e2e/e2etests/test_v2_deposit_and_call_swap.go new file mode 100644 index 0000000000..ed71ed3c53 --- /dev/null +++ b/e2e/e2etests/test_v2_deposit_and_call_swap.go @@ -0,0 +1,88 @@ +package e2etests + +import ( + "math/big" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/utils" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +// TODO: This test is similar to TestCrosschainSwap +// purpose is to test similar scenario with v2 contracts where there is swap + withdraw in onCall +// to showcase that it's not reverting with gas limit issues +// this test should be removed when this issue is completed: https://github.com/zeta-chain/node/issues/2711 +func TestV2DepositAndCallSwap(r *runner.E2ERunner, _ []string) { + // create tokens pair (erc20 and eth) + tx, err := r.UniswapV2Factory.CreatePair(r.ZEVMAuth, r.ERC20ZRC20Addr, r.ETHZRC20Addr) + require.NoError(r, err) + utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + + // approve router to spend tokens being swapped + tx, err = r.ERC20ZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e18)) + require.NoError(r, err) + utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + + tx, err = r.ETHZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e18)) + require.NoError(r, err) + utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + + // fund ZEVMSwapApp with gas ZRC20s for withdraw + tx, err = r.ETHZRC20.Transfer(r.ZEVMAuth, r.ZEVMSwapAppAddr, big.NewInt(1e10)) + require.NoError(r, err) + utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + + tx, err = r.ERC20ZRC20.Transfer(r.ZEVMAuth, r.ZEVMSwapAppAddr, big.NewInt(1e6)) + require.NoError(r, err) + utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + + // temporarily increase gas limit to 400000 + previousGasLimit := r.ZEVMAuth.GasLimit + defer func() { + r.ZEVMAuth.GasLimit = previousGasLimit + }() + + // add liquidity for swap + r.ZEVMAuth.GasLimit = 400000 + tx, err = r.UniswapV2Router.AddLiquidity( + r.ZEVMAuth, + r.ERC20ZRC20Addr, + r.ETHZRC20Addr, + big.NewInt(1e8), + big.NewInt(1e8), + big.NewInt(1e8), + big.NewInt(1e5), + r.EVMAddress(), + big.NewInt(time.Now().Add(10*time.Minute).Unix()), + ) + require.NoError(r, err) + utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + + // memobytes is dApp specific; see the contracts/ZEVMSwapApp.sol for details + // it is [targetZRC20, receiver] + memobytes, err := r.ZEVMSwapApp.EncodeMemo( + &bind.CallOpts{}, + r.ETHZRC20Addr, + r.EVMAddress().Bytes(), + ) + require.NoError(r, err) + + // perform the deposit and call + r.ApproveERC20OnEVM(r.GatewayEVMAddr) + tx = r.V2ERC20DepositAndCall( + r.ZEVMSwapAppAddr, + big.NewInt(8e7), + memobytes, + gatewayevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + + // wait for the cctx to be mined + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "deposit_and_call") + require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) +}