diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0056022622..bbe1f5365f 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -92,6 +92,7 @@ jobs: core.setOutput('STATEFUL_DATA_TESTS', labels.includes('STATEFUL_DATA_TESTS')); core.setOutput('TSS_MIGRATION_TESTS', labels.includes('TSS_MIGRATION_TESTS')); core.setOutput('SOLANA_TESTS', labels.includes('SOLANA_TESTS')); + core.setOutput('V2_TESTS', labels.includes('V2_TESTS')); // for v2 tests, TODO: remove this once we fully migrate to v2 (https://github.com/zeta-chain/node/issues/2627) } else if (context.eventName === 'merge_group') { core.setOutput('DEFAULT_TESTS', true); } else if (context.eventName === 'push' && context.ref === 'refs/heads/develop') { @@ -160,6 +161,9 @@ jobs: - make-target: "start-solana-test" runs-on: ubuntu-20.04 run: ${{ needs.matrix-conditionals.outputs.SOLANA_TESTS == 'true' }} + - make-target: "start-v2-test" + runs-on: ubuntu-20.04 + run: ${{ needs.matrix-conditionals.outputs.V2_TESTS == 'true' }} name: ${{ matrix.make-target }} uses: ./.github/workflows/reusable-e2e.yml with: diff --git a/Makefile b/Makefile index f5ee441cad..497abbbe88 100644 --- a/Makefile +++ b/Makefile @@ -273,7 +273,7 @@ start-solana-test: zetanode solana start-v2-test: zetanode @echo "--> Starting e2e smart contracts v2 test" - export E2E_ARGS="--test-v2" && \ + export E2E_ARGS="--skip-regular --test-v2" && \ cd contrib/localnet/ && $(DOCKER_COMPOSE) -f docker-compose.yml up -d ############################################################################### diff --git a/cmd/zetae2e/config/config.go b/cmd/zetae2e/config/config.go index 8a91bc1f86..5d3df17f83 100644 --- a/cmd/zetae2e/config/config.go +++ b/cmd/zetae2e/config/config.go @@ -88,5 +88,10 @@ func ExportContractsFromRunner(r *runner.E2ERunner, conf config.Config) config.C conf.Contracts.ZEVM.ContextAppAddr = config.DoubleQuotedString(r.ContextAppAddr.Hex()) conf.Contracts.ZEVM.TestDappAddr = config.DoubleQuotedString(r.ZevmTestDAppAddr.Hex()) + // v2 + conf.Contracts.EVM.Gateway = config.DoubleQuotedString(r.GatewayEVMAddr.Hex()) + conf.Contracts.EVM.ERC20CustodyNew = config.DoubleQuotedString(r.ERC20CustodyV2Addr.Hex()) + conf.Contracts.ZEVM.Gateway = config.DoubleQuotedString(r.GatewayZEVMAddr.Hex()) + return conf } diff --git a/cmd/zetae2e/config/local.yml b/cmd/zetae2e/config/local.yml index 54534124bd..a0205ee000 100644 --- a/cmd/zetae2e/config/local.yml +++ b/cmd/zetae2e/config/local.yml @@ -27,9 +27,11 @@ contracts: connector_zevm: "0x239e96c8f17C85c30100AC26F635Ea15f23E9c67" wzeta: "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf" test_dapp: "0xA8D5060feb6B456e886F023709A2795373691E63" + gateway: "0xa825eAa55b497AF892faca73a3797046C10B7c23" evm: zeta_eth: "0x733aB8b06DDDEf27Eaa72294B0d7c9cEF7f12db9" connector_eth: "0xD28D6A0b8189305551a0A8bd247a6ECa9CE781Ca" custody: "0xff3135df4F2775f4091b81f4c7B6359CfA07862a" erc20: "0xbD1e64A22B9F92D9Ce81aA9B4b0fFacd80215564" - test_dapp: "0xBFF76e77D56B3C1202107f059425D56f0AEF87Ed" \ No newline at end of file + test_dapp: "0xBFF76e77D56B3C1202107f059425D56f0AEF87Ed" + gateway: "0xF0deebCB0E9C829519C4baa794c5445171973826" \ No newline at end of file diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 52de24d2eb..aac97c4be8 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -335,15 +335,15 @@ func localE2ETest(cmd *cobra.Command, _ []string) { if testV2 { eg.Go(v2TestRoutine(conf, deployerRunner, verbose, e2etests.TestV2ETHDepositName, - e2etests.TestV2ETHDepositAndCallName, - e2etests.TestV2ETHWithdrawName, - e2etests.TestV2ETHWithdrawAndCallName, - e2etests.TestV2ERC20DepositName, - e2etests.TestV2ERC20DepositAndCallName, - e2etests.TestV2ERC20WithdrawName, - e2etests.TestV2ERC20WithdrawAndCallName, - e2etests.TestV2ZEVMToEVMCallName, - e2etests.TestV2EVMToZEVMCallName, + //e2etests.TestV2ETHDepositAndCallName, + //e2etests.TestV2ETHWithdrawName, + //e2etests.TestV2ETHWithdrawAndCallName, + //e2etests.TestV2ERC20DepositName, + //e2etests.TestV2ERC20DepositAndCallName, + //e2etests.TestV2ERC20WithdrawName, + //e2etests.TestV2ERC20WithdrawAndCallName, + //e2etests.TestV2ZEVMToEVMCallName, + //e2etests.TestV2EVMToZEVMCallName, )) } diff --git a/cmd/zetae2e/local/v2.go b/cmd/zetae2e/local/v2.go index 8cf3af1395..9b91bcd955 100644 --- a/cmd/zetae2e/local/v2.go +++ b/cmd/zetae2e/local/v2.go @@ -43,14 +43,6 @@ func v2TestRoutine( txERC20Send := deployerRunner.SendERC20OnEvm(account.EVMAddress(), 10) v2Runner.WaitForTxReceiptOnEvm(txERC20Send) - // depositing the necessary tokens on ZetaChain - // TODO: update with v2 deposits - // https://github.com/zeta-chain/node/issues/2554 - txEtherDeposit := v2Runner.DepositEther(false) - txERC20Deposit := v2Runner.DepositERC20() - v2Runner.WaitForMinedCCTX(txEtherDeposit) - v2Runner.WaitForMinedCCTX(txERC20Deposit) - // run erc20 test testsToRun, err := v2Runner.GetE2ETestsToRunByName( e2etests.AllE2ETests, diff --git a/docs/cli/zetacored/zetacored_tx_crosschain_vote-inbound.md b/docs/cli/zetacored/zetacored_tx_crosschain_vote-inbound.md index 920412c14f..37ae805907 100644 --- a/docs/cli/zetacored/zetacored_tx_crosschain_vote-inbound.md +++ b/docs/cli/zetacored/zetacored_tx_crosschain_vote-inbound.md @@ -3,7 +3,7 @@ Broadcast message to vote an inbound ``` -zetacored tx crosschain vote-inbound [sender] [senderChainID] [txOrigin] [receiver] [receiverChainID] [amount] [message] [inboundHash] [inBlockHeight] [coinType] [asset] [eventIndex] [flags] +zetacored tx crosschain vote-inbound [sender] [senderChainID] [txOrigin] [receiver] [receiverChainID] [amount] [message] [inboundHash] [inBlockHeight] [coinType] [asset] [eventIndex] [protocolContractVersion] [flags] ``` ### Options diff --git a/docs/cli/zetacored/zetacored_tx_fungible_update-gateway-contract.md b/docs/cli/zetacored/zetacored_tx_fungible_update-gateway-contract.md index d75877c440..0b4217c65b 100644 --- a/docs/cli/zetacored/zetacored_tx_fungible_update-gateway-contract.md +++ b/docs/cli/zetacored/zetacored_tx_fungible_update-gateway-contract.md @@ -3,7 +3,7 @@ Broadcast message UpdateGatewayContract to update the gateway contract address ``` -zetacored tx fungible update-gateway-contract [contract-address] [flags] +zetacored tx fungible update-gateway-contract [contract-address] [flags] ``` ### Options diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index a91158997d..9e8598e15e 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -57121,6 +57121,8 @@ definitions: items: type: object $ref: '#/definitions/crosschainOutboundParams' + protocol_contract_version: + $ref: '#/definitions/crosschainProtocolContractVersion' crosschainGasPrice: type: object properties: @@ -57315,6 +57317,15 @@ definitions: items: type: object $ref: '#/definitions/crosschainTxHash' + crosschainProtocolContractVersion: + type: string + enum: + - V1 + - V2 + default: V1 + title: |- + ProtocolContractVersion represents the version of the protocol contract used + for cctx workflow crosschainQueryAllCctxResponse: type: object properties: diff --git a/docs/spec/crosschain/messages.md b/docs/spec/crosschain/messages.md index feb02afc1f..466ea051df 100644 --- a/docs/spec/crosschain/messages.md +++ b/docs/spec/crosschain/messages.md @@ -187,6 +187,7 @@ message MsgVoteInbound { string tx_origin = 13; string asset = 14; uint64 event_index = 15; + ProtocolContractVersion protocol_contract_version = 16; } ``` diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index 1d714f7d10..0a42a0131d 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -579,7 +579,7 @@ var AllE2ETests = []runner.E2ETest{ []runner.ArgDefinition{ {Description: "amount in wei", DefaultValue: "10000000000000000"}, }, - TestV2ERC20Deposit, + TestV2ETHDeposit, ), runner.NewE2ETest( TestV2ETHDepositAndCallName, diff --git a/e2e/e2etests/test_v2_eth_deposit.go b/e2e/e2etests/test_v2_eth_deposit.go index 4b9b53e142..74ec64a70b 100644 --- a/e2e/e2etests/test_v2_eth_deposit.go +++ b/e2e/e2etests/test_v2_eth_deposit.go @@ -15,6 +15,8 @@ func TestV2ETHDeposit(r *runner.E2ERunner, args []string) { amount, ok := big.NewInt(0).SetString(args[0], 10) require.True(r, ok, "Invalid amount specified for TestV2ETHDeposit") + r.Logger.Info("starting v2 eth deposit test") + // perform the deposit tx := r.V2ETHDeposit(r.EVMAddress(), amount) diff --git a/e2e/runner/logger.go b/e2e/runner/logger.go index fc1843b512..db38d9a6fd 100644 --- a/e2e/runner/logger.go +++ b/e2e/runner/logger.go @@ -1,12 +1,14 @@ package runner import ( + "encoding/hex" "fmt" "sync" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/fatih/color" "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/zevm/zrc20.sol" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -199,6 +201,31 @@ func (l *Logger) ZRC20Withdrawal( } } +type depositParser interface { + ParseDeposit(ethtypes.Log) (*gatewayevm.GatewayEVMDeposit, error) +} + +// GatewayDeposit prints a GatewayDeposit event +func (l *Logger) GatewayDeposit( + contract depositParser, + receipt ethtypes.Receipt, + name string, +) { + for _, log := range receipt.Logs { + event, err := contract.ParseDeposit(*log) + if err != nil { + continue + } + + l.Info(" Gateway Deposit: %s", name) + l.Info(" Sender: %s", event.Sender.Hex()) + l.Info(" Receiver: %s", event.Receiver.Hex()) + l.Info(" Amount: %s", event.Amount.String()) + l.Info(" Asset: %s", event.Asset.Hex()) + l.Info(" Payload: %s", hex.EncodeToString(event.Payload)) + } +} + func (l *Logger) getPrefixWithPadding() string { // add padding to prefix prefix := l.prefix diff --git a/e2e/runner/v2_evm.go b/e2e/runner/v2_evm.go index 96cb4c32bc..1724a3c73b 100644 --- a/e2e/runner/v2_evm.go +++ b/e2e/runner/v2_evm.go @@ -6,6 +6,8 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" + + "github.com/zeta-chain/zetacore/e2e/utils" ) // V2ETHDeposit calls Deposit of Gateway with gas token on EVM @@ -20,6 +22,14 @@ func (r *E2ERunner) V2ETHDeposit(receiver ethcommon.Address, amount *big.Int) *e tx, err := r.GatewayEVM.Deposit(r.EVMAuth, receiver) require.NoError(r, err) + r.Logger.EVMTransaction(*tx, "eth_deposit") + + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt, "eth_deposit failed") + + r.Logger.EVMReceipt(*receipt, "eth_deposit") + r.Logger.GatewayDeposit(r.GatewayEVM, *receipt, "eth_deposit") + return tx } diff --git a/e2e/runner/v2_setup_zeta.go b/e2e/runner/v2_setup_zeta.go index 5524b1591b..02bf89a93b 100644 --- a/e2e/runner/v2_setup_zeta.go +++ b/e2e/runner/v2_setup_zeta.go @@ -51,5 +51,9 @@ func (r *E2ERunner) SetZEVMContractsV2() { require.NoError(r, err) r.Logger.Info("Gateway ZEVM contract address: %s, tx hash: %s", gatewayZEVMAddr.Hex(), txGateway.Hash().Hex()) + // Set the gateway address in the protocol + err = r.ZetaTxServer.UpdateGatewayAddress(utils.AdminPolicyName, r.GatewayZEVMAddr.Hex()) + require.NoError(r, err) + ensureTxReceipt(txProxy, "Gateway proxy deployment failed") } diff --git a/e2e/txserver/zeta_tx_server.go b/e2e/txserver/zeta_tx_server.go index b3687276a1..1d16a8b68a 100644 --- a/e2e/txserver/zeta_tx_server.go +++ b/e2e/txserver/zeta_tx_server.go @@ -310,12 +310,11 @@ func (zts ZetaTxServer) UpdateGatewayAddress(account, gatewayAddr string) error return err } - //_, err = zts.BroadcastTx(account, fungibletypes.Neew( - // addr.String(), - // gatewayAddr, - //)) + _, err = zts.BroadcastTx(account, fungibletypes.NewMsgUpdateGatewayContract( + addr.String(), + gatewayAddr, + )) return err - } // DeploySystemContractsAndZRC20 deploys the system contracts and ZRC20 contracts diff --git a/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto b/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto index 88ca547482..0ff31160da 100644 --- a/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto +++ b/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto @@ -91,6 +91,14 @@ message Status { bool isAbortRefunded = 4; } +// ProtocolContractVersion represents the version of the protocol contract used +// for cctx workflow +enum ProtocolContractVersion { + option (gogoproto.goproto_enum_stringer) = true; + V1 = 0; + V2 = 1; +} + message CrossChainTx { string creator = 1; string index = 2; @@ -103,4 +111,5 @@ message CrossChainTx { Status cctx_status = 8; InboundParams inbound_params = 9; repeated OutboundParams outbound_params = 10; + ProtocolContractVersion protocol_contract_version = 11; } diff --git a/proto/zetachain/zetacore/crosschain/tx.proto b/proto/zetachain/zetacore/crosschain/tx.proto index 2bff84f733..1a781ac09e 100644 --- a/proto/zetachain/zetacore/crosschain/tx.proto +++ b/proto/zetachain/zetacore/crosschain/tx.proto @@ -6,6 +6,7 @@ import "zetachain/zetacore/pkg/chains/chains.proto"; import "zetachain/zetacore/pkg/coin/coin.proto"; import "zetachain/zetacore/pkg/proofs/proofs.proto"; import "zetachain/zetacore/crosschain/rate_limiter_flags.proto"; +import "zetachain/zetacore/crosschain/cross_chain_tx.proto"; option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; @@ -162,6 +163,9 @@ message MsgVoteInbound { string asset = 14; // event index of the sent asset in the observed tx uint64 event_index = 15; + + // protocol contract version to use for the cctx workflow + ProtocolContractVersion protocol_contract_version = 16; } message MsgVoteInboundResponse {} diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index 6f350aa5ed..40ce858497 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -359,6 +359,7 @@ func MockRevertForHandleEVMDeposit( mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) } diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index 9eab868481..5612e1470f 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -8,6 +8,8 @@ import ( common "github.com/ethereum/go-ethereum/common" coin "github.com/zeta-chain/zetacore/pkg/coin" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" @@ -677,9 +679,9 @@ func (_m *CrosschainFungibleKeeper) ZETARevertAndCallContract(ctx types.Context, return r0, r1 } -// ZRC20DepositAndCallContract provides a mock function with given fields: ctx, from, to, amount, senderChainID, data, coinType, asset -func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Context, from []byte, to common.Address, amount *big.Int, senderChainID int64, data []byte, coinType coin.CoinType, asset string) (*evmtypes.MsgEthereumTxResponse, bool, error) { - ret := _m.Called(ctx, from, to, amount, senderChainID, data, coinType, asset) +// ZRC20DepositAndCallContract provides a mock function with given fields: ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion +func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Context, from []byte, to common.Address, amount *big.Int, senderChainID int64, data []byte, coinType coin.CoinType, asset string, protocolContractVersion crosschaintypes.ProtocolContractVersion) (*evmtypes.MsgEthereumTxResponse, bool, error) { + ret := _m.Called(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) if len(ret) == 0 { panic("no return value specified for ZRC20DepositAndCallContract") @@ -688,25 +690,25 @@ func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Contex var r0 *evmtypes.MsgEthereumTxResponse var r1 bool var r2 error - if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string) (*evmtypes.MsgEthereumTxResponse, bool, error)); ok { - return rf(ctx, from, to, amount, senderChainID, data, coinType, asset) + if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion) (*evmtypes.MsgEthereumTxResponse, bool, error)); ok { + return rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) } - if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string) *evmtypes.MsgEthereumTxResponse); ok { - r0 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset) + if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion) *evmtypes.MsgEthereumTxResponse); ok { + r0 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*evmtypes.MsgEthereumTxResponse) } } - if rf, ok := ret.Get(1).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string) bool); ok { - r1 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset) + if rf, ok := ret.Get(1).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion) bool); ok { + r1 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) } else { r1 = ret.Get(1).(bool) } - if rf, ok := ret.Get(2).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string) error); ok { - r2 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset) + if rf, ok := ret.Get(2).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion) error); ok { + r2 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) } else { r2 = ret.Error(2) } diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 1c189b6b3d..f6007d5ace 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -53,33 +53,6 @@ func RateLimiterFlags() types.RateLimiterFlags { } } -// CustomRateLimiterFlags creates a custom rate limiter flags with the given parameters -func CustomRateLimiterFlags( - enabled bool, - window int64, - rate math.Uint, - conversions []types.Conversion, -) types.RateLimiterFlags { - return types.RateLimiterFlags{ - Enabled: enabled, - Window: window, - Rate: rate, - Conversions: conversions, - } -} - -func AssetRate() types.AssetRate { - r := Rand() - - return types.AssetRate{ - ChainId: r.Int63(), - Asset: EthAddress().Hex(), - Decimals: uint32(r.Uint64()), - CoinType: coin.CoinType_ERC20, - Rate: sdk.NewDec(r.Int63()), - } -} - // CustomAssetRate creates a custom asset rate with the given parameters func CustomAssetRate( chainID int64, @@ -211,13 +184,14 @@ func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { r := newRandFromStringSeed(t, index) return &types.CrossChainTx{ - Creator: AccAddress(), - Index: GetCctxIndexFromString(index), - ZetaFees: math.NewUint(uint64(r.Int63())), - RelayedMessage: StringRandom(r, 32), - CctxStatus: Status(t, index), - InboundParams: InboundParams(r), - OutboundParams: []*types.OutboundParams{OutboundParams(r), OutboundParams(r)}, + Creator: AccAddress(), + Index: GetCctxIndexFromString(index), + ZetaFees: math.NewUint(uint64(r.Int63())), + RelayedMessage: StringRandom(r, 32), + CctxStatus: Status(t, index), + InboundParams: InboundParams(r), + OutboundParams: []*types.OutboundParams{OutboundParams(r), OutboundParams(r)}, + ProtocolContractVersion: types.ProtocolContractVersion_V1, } } diff --git a/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts b/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts index c4839a61f5..d1e57ab4eb 100644 --- a/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts +++ b/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts @@ -80,6 +80,24 @@ export declare enum TxFinalizationStatus { Executed = 2, } +/** + * ProtocolContractVersion represents the version of the protocol contract used + * for cctx workflow + * + * @generated from enum zetachain.zetacore.crosschain.ProtocolContractVersion + */ +export declare enum ProtocolContractVersion { + /** + * @generated from enum value: V1 = 0; + */ + V1 = 0, + + /** + * @generated from enum value: V2 = 1; + */ + V2 = 1, +} + /** * @generated from message zetachain.zetacore.crosschain.InboundParams */ @@ -371,6 +389,11 @@ export declare class CrossChainTx extends Message { */ outboundParams: OutboundParams[]; + /** + * @generated from field: zetachain.zetacore.crosschain.ProtocolContractVersion protocol_contract_version = 11; + */ + protocolContractVersion: ProtocolContractVersion; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts b/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts index e15cf71780..334382fb07 100644 --- a/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts +++ b/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts @@ -8,6 +8,7 @@ import { Message, proto3 } from "@bufbuild/protobuf"; import type { CoinType } from "../pkg/coin/coin_pb.js"; import type { Proof } from "../pkg/proofs/proofs_pb.js"; import type { ReceiveStatus } from "../pkg/chains/chains_pb.js"; +import type { ProtocolContractVersion } from "./cross_chain_tx_pb.js"; import type { RateLimiterFlags } from "./rate_limiter_flags_pb.js"; /** @@ -641,6 +642,13 @@ export declare class MsgVoteInbound extends Message { */ eventIndex: bigint; + /** + * protocol contract version to use for the cctx workflow + * + * @generated from field: zetachain.zetacore.crosschain.ProtocolContractVersion protocol_contract_version = 16; + */ + protocolContractVersion: ProtocolContractVersion; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/x/crosschain/client/cli/tx_vote_inbound.go b/x/crosschain/client/cli/tx_vote_inbound.go index 3581b01e0c..61d6deab2e 100644 --- a/x/crosschain/client/cli/tx_vote_inbound.go +++ b/x/crosschain/client/cli/tx_vote_inbound.go @@ -17,9 +17,9 @@ import ( func CmdVoteInbound() *cobra.Command { cmd := &cobra.Command{ Use: "vote-inbound [sender] [senderChainID] [txOrigin] [receiver] [receiverChainID] [amount] [message" + - "] [inboundHash] [inBlockHeight] [coinType] [asset] [eventIndex]", + "] [inboundHash] [inBlockHeight] [coinType] [asset] [eventIndex] [protocolContractVersion]", Short: "Broadcast message to vote an inbound", - Args: cobra.ExactArgs(12), + Args: cobra.ExactArgs(13), RunE: func(cmd *cobra.Command, args []string) error { argsSender := args[0] argsSenderChain, err := strconv.ParseInt(args[1], 10, 64) @@ -62,6 +62,11 @@ func CmdVoteInbound() *cobra.Command { return err } + protocolContractVersion, err := parseProtocolContractVersion(args[12]) + if err != nil { + return err + } + msg := types.NewMsgVoteInbound( clientCtx.GetFromAddress().String(), argsSender, @@ -77,6 +82,7 @@ func CmdVoteInbound() *cobra.Command { argsCoinType, argsAsset, uint(argsEventIndex), + protocolContractVersion, ) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) @@ -87,3 +93,16 @@ func CmdVoteInbound() *cobra.Command { return cmd } + +func parseProtocolContractVersion(version string) (types.ProtocolContractVersion, error) { + switch version { + case "V1": + return types.ProtocolContractVersion_V1, nil + case "V2": + return types.ProtocolContractVersion_V2, nil + default: + return types.ProtocolContractVersion_V1, fmt.Errorf( + "invalid protocol contract version, specify either V1 or V2", + ) + } +} diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index b1e55e3f6f..c82dd1705c 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -92,6 +92,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo data, inboundCoinType, cctx.InboundParams.Asset, + cctx.ProtocolContractVersion, ) if fungibletypes.IsContractReverted(evmTxResponse, err) || errShouldRevertCctx(err) { return true, err diff --git a/x/crosschain/keeper/evm_deposit_test.go b/x/crosschain/keeper/evm_deposit_test.go index 7541c21aa6..45e8a5547e 100644 --- a/x/crosschain/keeper/evm_deposit_test.go +++ b/x/crosschain/keeper/evm_deposit_test.go @@ -67,7 +67,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { fungibleMock.On("ZETADepositAndCallContract", ctx, ethcommon.HexToAddress(sender.String()), receiver, senderChainId, amount, mock.Anything, mock.Anything). Return(nil, errDeposit) - // call HandleEVMDeposit + // call HandleEVMDeposit cctx.InboundParams.Sender = sender.String() cctx.GetCurrentOutboundParam().Receiver = receiver.String() @@ -106,6 +106,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) // call HandleEVMDeposit @@ -151,6 +152,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{ Logs: []*evmtypes.Log{ { @@ -213,6 +215,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{ Logs: []*evmtypes.Log{ { @@ -302,6 +305,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, errDeposit) // call HandleEVMDeposit @@ -346,6 +350,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) // call HandleEVMDeposit @@ -389,6 +394,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrForeignCoinCapReached) // call HandleEVMDeposit @@ -432,6 +438,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrPausedZRC20) // call HandleEVMDeposit @@ -475,6 +482,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrCallNonContract) // call HandleEVMDeposit @@ -544,6 +552,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { data, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) cctx.GetCurrentOutboundParam().Receiver = sample.EthAddress().String() @@ -586,6 +595,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { data, coin.CoinType_ERC20, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) cctx := sample.CrossChainTx(t, "foo") diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index 16666f7c42..d774a0ecb2 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -178,6 +178,7 @@ func (k Keeper) ProcessZRC20WithdrawalEvent( foreignCoin.CoinType, foreignCoin.Asset, event.Raw.Index, + types.ProtocolContractVersion_V1, ) cctx, err := k.ValidateInbound(ctx, msg, false) @@ -241,6 +242,7 @@ func (k Keeper) ProcessZetaSentEvent( amount := math.NewUintFromBigInt(event.ZetaValueAndGas) messageString := base64.StdEncoding.EncodeToString(event.Message) + // Bump gasLimit by event index (which is very unlikely to be larger than 1000) to always have different ZetaSent events msgs. msg := types.NewMsgVoteInbound( "", @@ -256,6 +258,7 @@ func (k Keeper) ProcessZetaSentEvent( coin.CoinType_Zeta, "", event.Raw.Index, + types.ProtocolContractVersion_V1, ) cctx, err := k.ValidateInbound(ctx, msg, true) diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go index 27b9b30968..694fc92052 100644 --- a/x/crosschain/types/cctx.go +++ b/x/crosschain/types/cctx.go @@ -210,13 +210,14 @@ func NewCCTX(ctx sdk.Context, msg MsgVoteInbound, tssPubkey string) (CrossChainT IsAbortRefunded: false, } cctx := CrossChainTx{ - Creator: msg.Creator, - Index: index, - ZetaFees: sdkmath.ZeroUint(), - RelayedMessage: msg.Message, - CctxStatus: status, - InboundParams: inboundParams, - OutboundParams: []*OutboundParams{outboundParams}, + Creator: msg.Creator, + Index: index, + ZetaFees: sdkmath.ZeroUint(), + RelayedMessage: msg.Message, + CctxStatus: status, + InboundParams: inboundParams, + OutboundParams: []*OutboundParams{outboundParams}, + ProtocolContractVersion: msg.ProtocolContractVersion, } // TODO: remove this validate call diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index eecdf0cdf0..eea8a8143d 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -23,7 +23,7 @@ func TestCrossChainTx_GetCCTXIndexBytes(t *testing.T) { require.Equal(t, cctx.Index, types.GetCctxIndexFromBytes(indexBytes)) } -func Test_InitializeCCTX(t *testing.T) { +func Test_NewCCTX(t *testing.T) { t.Run("should return a cctx with correct values", func(t *testing.T) { _, ctx, _, _ := keepertest.CrosschainKeeper(t) senderChain := chains.Goerli @@ -41,20 +41,21 @@ func Test_InitializeCCTX(t *testing.T) { cointType := coin.CoinType_ERC20 tss := sample.Tss() msg := types.MsgVoteInbound{ - Creator: creator, - Sender: sender.String(), - SenderChainId: senderChain.ChainId, - Receiver: receiver.String(), - ReceiverChain: receiverChain.ChainId, - Amount: amount, - Message: message, - InboundHash: inboundHash.String(), - InboundBlockHeight: inboundBlockHeight, - GasLimit: gasLimit, - CoinType: cointType, - TxOrigin: sender.String(), - Asset: asset, - EventIndex: eventIndex, + Creator: creator, + Sender: sender.String(), + SenderChainId: senderChain.ChainId, + Receiver: receiver.String(), + ReceiverChain: receiverChain.ChainId, + Amount: amount, + Message: message, + InboundHash: inboundHash.String(), + InboundBlockHeight: inboundBlockHeight, + GasLimit: gasLimit, + CoinType: cointType, + TxOrigin: sender.String(), + Asset: asset, + EventIndex: eventIndex, + ProtocolContractVersion: types.ProtocolContractVersion_V2, } cctx, err := types.NewCCTX(ctx, msg, tss.TssPubkey) require.NoError(t, err) @@ -73,7 +74,9 @@ func Test_InitializeCCTX(t *testing.T) { require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutboundParam().Amount) require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) + require.Equal(t, types.ProtocolContractVersion_V2, cctx.ProtocolContractVersion) }) + t.Run("should return an error if the cctx is invalid", func(t *testing.T) { _, ctx, _, _ := keepertest.CrosschainKeeper(t) senderChain := chains.Goerli @@ -109,6 +112,11 @@ func Test_InitializeCCTX(t *testing.T) { _, err := types.NewCCTX(ctx, msg, tss.TssPubkey) require.ErrorContains(t, err, "sender cannot be empty") }) + + t.Run("zero value for protocol contract version gives V1", func(t *testing.T) { + cctx := types.CrossChainTx{} + require.Equal(t, types.ProtocolContractVersion_V1, cctx.ProtocolContractVersion) + }) } func TestCrossChainTx_Validate(t *testing.T) { diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index 5817c7b709..e702dd8ac8 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -90,6 +90,33 @@ func (TxFinalizationStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor_d4c1966807fb5cb2, []int{1} } +// ProtocolContractVersion represents the version of the protocol contract used +// for cctx workflow +type ProtocolContractVersion int32 + +const ( + ProtocolContractVersion_V1 ProtocolContractVersion = 0 + ProtocolContractVersion_V2 ProtocolContractVersion = 1 +) + +var ProtocolContractVersion_name = map[int32]string{ + 0: "V1", + 1: "V2", +} + +var ProtocolContractVersion_value = map[string]int32{ + "V1": 0, + "V2": 1, +} + +func (x ProtocolContractVersion) String() string { + return proto.EnumName(ProtocolContractVersion_name, int32(x)) +} + +func (ProtocolContractVersion) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_d4c1966807fb5cb2, []int{2} +} + type InboundParams struct { Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` // the Connector.send() @@ -468,13 +495,14 @@ func (m *Status) GetIsAbortRefunded() bool { } type CrossChainTx struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - Index string `protobuf:"bytes,2,opt,name=index,proto3" json:"index,omitempty"` - ZetaFees github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,5,opt,name=zeta_fees,json=zetaFees,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"zeta_fees" yaml:"zeta_fees"` - RelayedMessage string `protobuf:"bytes,6,opt,name=relayed_message,json=relayedMessage,proto3" json:"relayed_message,omitempty"` - CctxStatus *Status `protobuf:"bytes,8,opt,name=cctx_status,json=cctxStatus,proto3" json:"cctx_status,omitempty"` - InboundParams *InboundParams `protobuf:"bytes,9,opt,name=inbound_params,json=inboundParams,proto3" json:"inbound_params,omitempty"` - OutboundParams []*OutboundParams `protobuf:"bytes,10,rep,name=outbound_params,json=outboundParams,proto3" json:"outbound_params,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Index string `protobuf:"bytes,2,opt,name=index,proto3" json:"index,omitempty"` + ZetaFees github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,5,opt,name=zeta_fees,json=zetaFees,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"zeta_fees" yaml:"zeta_fees"` + RelayedMessage string `protobuf:"bytes,6,opt,name=relayed_message,json=relayedMessage,proto3" json:"relayed_message,omitempty"` + CctxStatus *Status `protobuf:"bytes,8,opt,name=cctx_status,json=cctxStatus,proto3" json:"cctx_status,omitempty"` + InboundParams *InboundParams `protobuf:"bytes,9,opt,name=inbound_params,json=inboundParams,proto3" json:"inbound_params,omitempty"` + OutboundParams []*OutboundParams `protobuf:"bytes,10,rep,name=outbound_params,json=outboundParams,proto3" json:"outbound_params,omitempty"` + ProtocolContractVersion ProtocolContractVersion `protobuf:"varint,11,opt,name=protocol_contract_version,json=protocolContractVersion,proto3,enum=zetachain.zetacore.crosschain.ProtocolContractVersion" json:"protocol_contract_version,omitempty"` } func (m *CrossChainTx) Reset() { *m = CrossChainTx{} } @@ -552,9 +580,17 @@ func (m *CrossChainTx) GetOutboundParams() []*OutboundParams { return nil } +func (m *CrossChainTx) GetProtocolContractVersion() ProtocolContractVersion { + if m != nil { + return m.ProtocolContractVersion + } + return ProtocolContractVersion_V1 +} + func init() { proto.RegisterEnum("zetachain.zetacore.crosschain.CctxStatus", CctxStatus_name, CctxStatus_value) proto.RegisterEnum("zetachain.zetacore.crosschain.TxFinalizationStatus", TxFinalizationStatus_name, TxFinalizationStatus_value) + proto.RegisterEnum("zetachain.zetacore.crosschain.ProtocolContractVersion", ProtocolContractVersion_name, ProtocolContractVersion_value) proto.RegisterType((*InboundParams)(nil), "zetachain.zetacore.crosschain.InboundParams") proto.RegisterType((*ZetaAccounting)(nil), "zetachain.zetacore.crosschain.ZetaAccounting") proto.RegisterType((*OutboundParams)(nil), "zetachain.zetacore.crosschain.OutboundParams") @@ -567,76 +603,80 @@ func init() { } var fileDescriptor_d4c1966807fb5cb2 = []byte{ - // 1100 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x72, 0x13, 0x47, - 0x10, 0xd6, 0x22, 0x21, 0x4b, 0xad, 0xbf, 0x65, 0x2c, 0x9c, 0x8d, 0x53, 0x08, 0x47, 0x29, 0x40, - 0x50, 0x41, 0x2a, 0xcc, 0x25, 0x95, 0x9b, 0xed, 0xc2, 0xe0, 0x10, 0xc0, 0xb5, 0x98, 0x1c, 0x38, - 0x64, 0x33, 0xda, 0x6d, 0xad, 0xa6, 0x2c, 0xed, 0x28, 0x3b, 0x23, 0xd7, 0x8a, 0xca, 0x43, 0x24, - 0xef, 0x90, 0x43, 0x8e, 0x79, 0x82, 0x9c, 0xb9, 0x85, 0x63, 0x2a, 0x07, 0x2a, 0x85, 0xdf, 0x20, - 0x4f, 0x90, 0x9a, 0x99, 0x5d, 0xc9, 0x72, 0xb9, 0x6c, 0x42, 0x72, 0x52, 0xf7, 0xd7, 0x33, 0x5f, - 0xb7, 0x7a, 0xbe, 0x9e, 0x59, 0xd8, 0x7c, 0x85, 0x92, 0xfa, 0x43, 0xca, 0xa2, 0x9e, 0xb6, 0x78, - 0x8c, 0x3d, 0x3f, 0xe6, 0x42, 0x18, 0x4c, 0x9b, 0x9e, 0xb6, 0x3d, 0x99, 0x74, 0x27, 0x31, 0x97, - 0x9c, 0x5c, 0x9b, 0xef, 0xe9, 0x66, 0x7b, 0xba, 0x8b, 0x3d, 0xeb, 0xcd, 0x90, 0x87, 0x5c, 0xaf, - 0xec, 0x29, 0xcb, 0x6c, 0x5a, 0xbf, 0x79, 0x46, 0xa2, 0xc9, 0x61, 0xd8, 0xf3, 0xb9, 0x4a, 0xc3, - 0x59, 0x64, 0xd6, 0xb5, 0x7f, 0x2d, 0x40, 0x6d, 0x2f, 0xea, 0xf3, 0x69, 0x14, 0xec, 0xd3, 0x98, - 0x8e, 0x05, 0x59, 0x83, 0xa2, 0xc0, 0x28, 0xc0, 0xd8, 0xb1, 0x36, 0xac, 0x4e, 0xd9, 0x4d, 0x3d, - 0x72, 0x13, 0x1a, 0xc6, 0x4a, 0xeb, 0x63, 0x81, 0x73, 0x69, 0xc3, 0xea, 0xe4, 0xdd, 0x9a, 0x81, - 0x77, 0x14, 0xba, 0x17, 0x90, 0x4f, 0xa0, 0x2c, 0x13, 0x8f, 0xc7, 0x2c, 0x64, 0x91, 0x93, 0xd7, - 0x14, 0x25, 0x99, 0x3c, 0xd3, 0x3e, 0xd9, 0x86, 0xb2, 0x4a, 0xee, 0xc9, 0xd9, 0x04, 0x9d, 0xc2, - 0x86, 0xd5, 0xa9, 0x6f, 0xde, 0xe8, 0x9e, 0xf1, 0xff, 0x26, 0x87, 0x61, 0x57, 0x57, 0xb9, 0xc3, - 0x59, 0x74, 0x30, 0x9b, 0xa0, 0x5b, 0xf2, 0x53, 0x8b, 0x34, 0xe1, 0x32, 0x15, 0x02, 0xa5, 0x73, - 0x59, 0x93, 0x1b, 0x87, 0x3c, 0x84, 0x22, 0x1d, 0xf3, 0x69, 0x24, 0x9d, 0xa2, 0x82, 0xb7, 0x7b, - 0xaf, 0xdf, 0x5e, 0xcf, 0xfd, 0xf9, 0xf6, 0xfa, 0xad, 0x90, 0xc9, 0xe1, 0xb4, 0xdf, 0xf5, 0xf9, - 0xb8, 0xe7, 0x73, 0x31, 0xe6, 0x22, 0xfd, 0xb9, 0x2b, 0x82, 0xc3, 0x9e, 0xaa, 0x43, 0x74, 0x5f, - 0xb0, 0x48, 0xba, 0xe9, 0x76, 0xf2, 0x19, 0xd4, 0x78, 0x5f, 0x60, 0x7c, 0x84, 0x81, 0x37, 0xa4, - 0x62, 0xe8, 0xac, 0xe8, 0x34, 0xd5, 0x0c, 0x7c, 0x44, 0xc5, 0x90, 0x7c, 0x01, 0xce, 0x7c, 0x11, - 0x26, 0x12, 0xe3, 0x88, 0x8e, 0xbc, 0x21, 0xb2, 0x70, 0x28, 0x9d, 0xd2, 0x86, 0xd5, 0x29, 0xb8, - 0x6b, 0x59, 0xfc, 0x41, 0x1a, 0x7e, 0xa4, 0xa3, 0xe4, 0x53, 0xa8, 0xf6, 0xe9, 0x68, 0xc4, 0xa5, - 0xc7, 0xa2, 0x00, 0x13, 0xa7, 0xac, 0xd9, 0x2b, 0x06, 0xdb, 0x53, 0x10, 0xd9, 0x84, 0xab, 0x03, - 0x16, 0xd1, 0x11, 0x7b, 0x85, 0x81, 0xa7, 0x5a, 0x92, 0x31, 0x83, 0x66, 0x5e, 0x9d, 0x07, 0x5f, - 0xa2, 0xa4, 0x29, 0x2d, 0x83, 0x35, 0x99, 0x78, 0x69, 0x84, 0x4a, 0xc6, 0x23, 0x4f, 0x48, 0x2a, - 0xa7, 0xc2, 0xa9, 0xe8, 0x2e, 0xdf, 0xef, 0x9e, 0xab, 0xa2, 0xee, 0x41, 0xb2, 0x7b, 0x62, 0xef, - 0x73, 0xbd, 0xd5, 0x6d, 0xca, 0x33, 0xd0, 0xf6, 0xf7, 0x50, 0x57, 0x89, 0xb7, 0x7c, 0x5f, 0xf5, - 0x8b, 0x45, 0x21, 0xf1, 0x60, 0x95, 0xf6, 0x79, 0x2c, 0xb3, 0x72, 0xd3, 0x83, 0xb0, 0x3e, 0xec, - 0x20, 0xae, 0xa4, 0x5c, 0x3a, 0x89, 0x66, 0x6a, 0xff, 0x54, 0x84, 0xfa, 0xb3, 0xa9, 0x3c, 0x29, - 0xd3, 0x75, 0x28, 0xc5, 0xe8, 0x23, 0x3b, 0x9a, 0x0b, 0x75, 0xee, 0x93, 0xdb, 0x60, 0x67, 0xb6, - 0x11, 0xeb, 0x5e, 0xa6, 0xd5, 0x46, 0x86, 0x67, 0x6a, 0x5d, 0x12, 0x64, 0xfe, 0xc3, 0x04, 0xb9, - 0x90, 0x5e, 0xe1, 0xbf, 0x49, 0x4f, 0x8d, 0x8e, 0x10, 0x5e, 0xc4, 0x23, 0x1f, 0xb5, 0xba, 0x0b, - 0x6e, 0x49, 0x0a, 0xf1, 0x54, 0xf9, 0x2a, 0x18, 0x52, 0xe1, 0x8d, 0xd8, 0x98, 0x19, 0x8d, 0x17, - 0xdc, 0x52, 0x48, 0xc5, 0xd7, 0xca, 0xcf, 0x82, 0x93, 0x98, 0xf9, 0x98, 0x0a, 0x56, 0x05, 0xf7, - 0x95, 0x4f, 0x3a, 0x60, 0xa7, 0x41, 0x1e, 0x33, 0x39, 0xf3, 0x06, 0x88, 0xce, 0x47, 0x7a, 0x4d, - 0xdd, 0xac, 0xd1, 0xf0, 0x2e, 0x22, 0x21, 0x50, 0xd0, 0x92, 0x2f, 0xe9, 0xa8, 0xb6, 0xdf, 0x47, - 0xb0, 0xe7, 0x4d, 0x03, 0x9c, 0x3b, 0x0d, 0x1f, 0x83, 0x2a, 0xd3, 0x9b, 0x0a, 0x0c, 0x9c, 0xa6, - 0x5e, 0xb9, 0x12, 0x52, 0xf1, 0x42, 0x60, 0x40, 0xbe, 0x85, 0x55, 0x1c, 0x0c, 0xd0, 0x97, 0xec, - 0x08, 0xbd, 0xc5, 0x9f, 0xbb, 0xaa, 0x5b, 0xdc, 0x4d, 0x5b, 0x7c, 0xf3, 0x3d, 0x5a, 0xbc, 0xa7, - 0x34, 0x35, 0xa7, 0x7a, 0x98, 0x75, 0xa5, 0x7b, 0x9a, 0xdf, 0x74, 0x76, 0x4d, 0x57, 0xb1, 0xb4, - 0xde, 0xb4, 0xf8, 0x1a, 0x80, 0x3a, 0x9c, 0xc9, 0xb4, 0x7f, 0x88, 0x33, 0x3d, 0x55, 0x65, 0x57, - 0x1d, 0xd7, 0xbe, 0x06, 0xce, 0x19, 0xc0, 0xea, 0xff, 0x3c, 0x80, 0x5f, 0x15, 0x4a, 0x35, 0xbb, - 0xd9, 0xfe, 0xdd, 0x82, 0xa2, 0x01, 0xc8, 0x16, 0x14, 0xd3, 0x5c, 0x96, 0xce, 0x75, 0xfb, 0x82, - 0x5c, 0x3b, 0xbe, 0x4c, 0xd2, 0x0c, 0xe9, 0x46, 0x72, 0x03, 0xea, 0xc6, 0xf2, 0xc6, 0x28, 0x04, - 0x0d, 0x51, 0x0f, 0x4c, 0xd9, 0xad, 0x19, 0xf4, 0x89, 0x01, 0xc9, 0x3d, 0x68, 0x8e, 0xa8, 0x90, - 0x2f, 0x26, 0x01, 0x95, 0xe8, 0x49, 0x36, 0x46, 0x21, 0xe9, 0x78, 0xa2, 0x27, 0x27, 0xef, 0xae, - 0x2e, 0x62, 0x07, 0x59, 0x88, 0x74, 0xa0, 0xc1, 0xc4, 0x96, 0x1a, 0x69, 0x17, 0x07, 0xd3, 0x28, - 0xc0, 0x40, 0x8f, 0x49, 0xc9, 0x3d, 0x0d, 0xb7, 0x7f, 0xcb, 0x43, 0x75, 0x47, 0x55, 0xa9, 0x87, - 0xf3, 0x20, 0x21, 0x0e, 0xac, 0xf8, 0x31, 0x52, 0xc9, 0xb3, 0x11, 0xcf, 0x5c, 0xf5, 0x06, 0x18, - 0x35, 0x9a, 0x2a, 0x8d, 0x43, 0xbe, 0x83, 0xb2, 0xbe, 0x7f, 0x06, 0x88, 0xc2, 0xbc, 0x0e, 0xdb, - 0x3b, 0xff, 0x72, 0x16, 0xff, 0x7e, 0x7b, 0xdd, 0x9e, 0xd1, 0xf1, 0xe8, 0xcb, 0xf6, 0x9c, 0xa9, - 0xed, 0x96, 0x94, 0xbd, 0x8b, 0x28, 0xc8, 0x2d, 0x68, 0xc4, 0x38, 0xa2, 0x33, 0x0c, 0xe6, 0x7d, - 0x2a, 0x9a, 0x49, 0x4a, 0xe1, 0xac, 0x51, 0xbb, 0x50, 0xf1, 0x7d, 0x99, 0x64, 0x1a, 0x50, 0x03, - 0x55, 0x39, 0xfb, 0x66, 0x39, 0x71, 0x2e, 0xe9, 0x99, 0x80, 0x3f, 0x3f, 0x1f, 0xf2, 0x1c, 0xea, - 0xcc, 0x3c, 0xcf, 0xde, 0x44, 0x5f, 0x7c, 0x7a, 0xfe, 0x2a, 0x9b, 0x9f, 0x5f, 0x40, 0xb5, 0xf4, - 0xa6, 0xbb, 0x35, 0xb6, 0xf4, 0xc4, 0x7f, 0x03, 0x0d, 0x9e, 0xde, 0xa6, 0x19, 0x2b, 0x6c, 0xe4, - 0x3b, 0x95, 0xcd, 0xbb, 0x17, 0xb0, 0x2e, 0xdf, 0xc1, 0x6e, 0x9d, 0x2f, 0xf9, 0x77, 0x7e, 0x00, - 0x58, 0x48, 0x8b, 0x10, 0xa8, 0xef, 0x63, 0x14, 0xb0, 0x28, 0x4c, 0x8b, 0xb1, 0x73, 0x64, 0x15, - 0x1a, 0x29, 0x96, 0x51, 0xd9, 0x16, 0xb9, 0x02, 0xb5, 0xcc, 0x7b, 0xc2, 0x22, 0x0c, 0xec, 0xbc, - 0x82, 0xd2, 0x75, 0x2e, 0x1e, 0x61, 0x2c, 0xed, 0x02, 0xa9, 0x42, 0xc9, 0xd8, 0x18, 0xd8, 0x97, - 0x49, 0x05, 0x56, 0xb6, 0xcc, 0x33, 0x61, 0x17, 0xd7, 0x0b, 0xbf, 0xfc, 0xdc, 0xb2, 0xee, 0x3c, - 0x86, 0xe6, 0x59, 0x43, 0x44, 0x6c, 0xa8, 0x3e, 0xe5, 0x72, 0x37, 0x7b, 0x34, 0xed, 0x1c, 0xa9, - 0x41, 0x79, 0xe1, 0x5a, 0x8a, 0xf9, 0x41, 0x82, 0xfe, 0x54, 0x91, 0x5d, 0x32, 0x64, 0xdb, 0x8f, - 0x5f, 0xbf, 0x6b, 0x59, 0x6f, 0xde, 0xb5, 0xac, 0xbf, 0xde, 0xb5, 0xac, 0x1f, 0x8f, 0x5b, 0xb9, - 0x37, 0xc7, 0xad, 0xdc, 0x1f, 0xc7, 0xad, 0xdc, 0xcb, 0x7b, 0x27, 0x94, 0xa4, 0x7a, 0x74, 0xf7, - 0xd4, 0x57, 0x56, 0x72, 0xf2, 0x83, 0x4e, 0x0b, 0xab, 0x5f, 0xd4, 0xdf, 0x5a, 0xf7, 0xff, 0x09, - 0x00, 0x00, 0xff, 0xff, 0xea, 0x6a, 0x48, 0x57, 0xfe, 0x09, 0x00, 0x00, + // 1159 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdf, 0x6e, 0x13, 0xc7, + 0x17, 0xf6, 0x12, 0xe3, 0xd8, 0xc7, 0xb1, 0xb3, 0x4c, 0x4c, 0x58, 0xf2, 0x13, 0x26, 0x3f, 0x57, + 0x80, 0x41, 0xc5, 0x16, 0x41, 0xaa, 0xaa, 0xde, 0x25, 0x11, 0x81, 0x94, 0x02, 0xd1, 0x12, 0xb8, + 0xe0, 0xa2, 0xdb, 0xf1, 0xee, 0xc9, 0x7a, 0x14, 0x7b, 0xc7, 0xdd, 0x19, 0x47, 0x1b, 0xd4, 0x87, + 0x68, 0xdf, 0xa1, 0x17, 0xbd, 0xac, 0xfa, 0x14, 0xdc, 0x95, 0xcb, 0xaa, 0x17, 0xa8, 0x82, 0x37, + 0xe8, 0x13, 0x54, 0xf3, 0x67, 0xed, 0x18, 0xb9, 0x09, 0xa5, 0xbd, 0xf2, 0x39, 0xdf, 0x99, 0x73, + 0xce, 0xf8, 0xcc, 0xf7, 0xcd, 0x2c, 0x6c, 0xbc, 0x44, 0x49, 0xc3, 0x3e, 0x65, 0x49, 0x57, 0x5b, + 0x3c, 0xc5, 0x6e, 0x98, 0x72, 0x21, 0x0c, 0xa6, 0xcd, 0x40, 0xdb, 0x81, 0xcc, 0x3a, 0xa3, 0x94, + 0x4b, 0x4e, 0xae, 0x4c, 0x72, 0x3a, 0x79, 0x4e, 0x67, 0x9a, 0xb3, 0xd6, 0x88, 0x79, 0xcc, 0xf5, + 0xca, 0xae, 0xb2, 0x4c, 0xd2, 0xda, 0xf5, 0x39, 0x8d, 0x46, 0x87, 0x71, 0x37, 0xe4, 0xaa, 0x0d, + 0x67, 0x89, 0x59, 0xd7, 0xfa, 0xb9, 0x08, 0xb5, 0xdd, 0xa4, 0xc7, 0xc7, 0x49, 0xb4, 0x47, 0x53, + 0x3a, 0x14, 0x64, 0x15, 0x4a, 0x02, 0x93, 0x08, 0x53, 0xcf, 0x59, 0x77, 0xda, 0x15, 0xdf, 0x7a, + 0xe4, 0x3a, 0x2c, 0x1b, 0xcb, 0xee, 0x8f, 0x45, 0xde, 0xb9, 0x75, 0xa7, 0xbd, 0xe0, 0xd7, 0x0c, + 0xbc, 0xad, 0xd0, 0xdd, 0x88, 0xfc, 0x0f, 0x2a, 0x32, 0x0b, 0x78, 0xca, 0x62, 0x96, 0x78, 0x0b, + 0xba, 0x44, 0x59, 0x66, 0x4f, 0xb4, 0x4f, 0xb6, 0xa0, 0xa2, 0x9a, 0x07, 0xf2, 0x78, 0x84, 0x5e, + 0x71, 0xdd, 0x69, 0xd7, 0x37, 0xae, 0x75, 0xe6, 0xfc, 0xbf, 0xd1, 0x61, 0xdc, 0xd1, 0xbb, 0xdc, + 0xe6, 0x2c, 0xd9, 0x3f, 0x1e, 0xa1, 0x5f, 0x0e, 0xad, 0x45, 0x1a, 0x70, 0x9e, 0x0a, 0x81, 0xd2, + 0x3b, 0xaf, 0x8b, 0x1b, 0x87, 0xdc, 0x87, 0x12, 0x1d, 0xf2, 0x71, 0x22, 0xbd, 0x92, 0x82, 0xb7, + 0xba, 0xaf, 0xde, 0x5c, 0x2d, 0xfc, 0xfe, 0xe6, 0xea, 0x8d, 0x98, 0xc9, 0xfe, 0xb8, 0xd7, 0x09, + 0xf9, 0xb0, 0x1b, 0x72, 0x31, 0xe4, 0xc2, 0xfe, 0xdc, 0x16, 0xd1, 0x61, 0x57, 0xed, 0x43, 0x74, + 0x9e, 0xb1, 0x44, 0xfa, 0x36, 0x9d, 0x7c, 0x02, 0x35, 0xde, 0x13, 0x98, 0x1e, 0x61, 0x14, 0xf4, + 0xa9, 0xe8, 0x7b, 0x8b, 0xba, 0xcd, 0x52, 0x0e, 0x3e, 0xa0, 0xa2, 0x4f, 0x3e, 0x07, 0x6f, 0xb2, + 0x08, 0x33, 0x89, 0x69, 0x42, 0x07, 0x41, 0x1f, 0x59, 0xdc, 0x97, 0x5e, 0x79, 0xdd, 0x69, 0x17, + 0xfd, 0xd5, 0x3c, 0x7e, 0xcf, 0x86, 0x1f, 0xe8, 0x28, 0xf9, 0x3f, 0x2c, 0xf5, 0xe8, 0x60, 0xc0, + 0x65, 0xc0, 0x92, 0x08, 0x33, 0xaf, 0xa2, 0xab, 0x57, 0x0d, 0xb6, 0xab, 0x20, 0xb2, 0x01, 0x17, + 0x0f, 0x58, 0x42, 0x07, 0xec, 0x25, 0x46, 0x81, 0x1a, 0x49, 0x5e, 0x19, 0x74, 0xe5, 0x95, 0x49, + 0xf0, 0x05, 0x4a, 0x6a, 0xcb, 0x32, 0x58, 0x95, 0x59, 0x60, 0x23, 0x54, 0x32, 0x9e, 0x04, 0x42, + 0x52, 0x39, 0x16, 0x5e, 0x55, 0x4f, 0xf9, 0x6e, 0xe7, 0x54, 0x16, 0x75, 0xf6, 0xb3, 0x9d, 0x13, + 0xb9, 0x4f, 0x75, 0xaa, 0xdf, 0x90, 0x73, 0xd0, 0xd6, 0xb7, 0x50, 0x57, 0x8d, 0x37, 0xc3, 0x50, + 0xcd, 0x8b, 0x25, 0x31, 0x09, 0x60, 0x85, 0xf6, 0x78, 0x2a, 0xf3, 0xed, 0xda, 0x83, 0x70, 0x3e, + 0xee, 0x20, 0x2e, 0xd8, 0x5a, 0xba, 0x89, 0xae, 0xd4, 0xfa, 0xa1, 0x04, 0xf5, 0x27, 0x63, 0x79, + 0x92, 0xa6, 0x6b, 0x50, 0x4e, 0x31, 0x44, 0x76, 0x34, 0x21, 0xea, 0xc4, 0x27, 0x37, 0xc1, 0xcd, + 0x6d, 0x43, 0xd6, 0xdd, 0x9c, 0xab, 0xcb, 0x39, 0x9e, 0xb3, 0x75, 0x86, 0x90, 0x0b, 0x1f, 0x47, + 0xc8, 0x29, 0xf5, 0x8a, 0xff, 0x8e, 0x7a, 0x4a, 0x3a, 0x42, 0x04, 0x09, 0x4f, 0x42, 0xd4, 0xec, + 0x2e, 0xfa, 0x65, 0x29, 0xc4, 0x63, 0xe5, 0xab, 0x60, 0x4c, 0x45, 0x30, 0x60, 0x43, 0x66, 0x38, + 0x5e, 0xf4, 0xcb, 0x31, 0x15, 0x5f, 0x29, 0x3f, 0x0f, 0x8e, 0x52, 0x16, 0xa2, 0x25, 0xac, 0x0a, + 0xee, 0x29, 0x9f, 0xb4, 0xc1, 0xb5, 0x41, 0x9e, 0x32, 0x79, 0x1c, 0x1c, 0x20, 0x7a, 0x97, 0xf4, + 0x9a, 0xba, 0x59, 0xa3, 0xe1, 0x1d, 0x44, 0x42, 0xa0, 0xa8, 0x29, 0x5f, 0xd6, 0x51, 0x6d, 0x7f, + 0x08, 0x61, 0x4f, 0x53, 0x03, 0x9c, 0xaa, 0x86, 0xcb, 0xa0, 0xb6, 0x19, 0x8c, 0x05, 0x46, 0x5e, + 0x43, 0xaf, 0x5c, 0x8c, 0xa9, 0x78, 0x26, 0x30, 0x22, 0x5f, 0xc3, 0x0a, 0x1e, 0x1c, 0x60, 0x28, + 0xd9, 0x11, 0x06, 0xd3, 0x3f, 0x77, 0x51, 0x8f, 0xb8, 0x63, 0x47, 0x7c, 0xfd, 0x03, 0x46, 0xbc, + 0xab, 0x38, 0x35, 0x29, 0x75, 0x3f, 0x9f, 0x4a, 0xe7, 0xfd, 0xfa, 0x66, 0xb2, 0xab, 0x7a, 0x17, + 0x33, 0xeb, 0xcd, 0x88, 0xaf, 0x00, 0xa8, 0xc3, 0x19, 0x8d, 0x7b, 0x87, 0x78, 0xac, 0x55, 0x55, + 0xf1, 0xd5, 0x71, 0xed, 0x69, 0xe0, 0x14, 0x01, 0x2e, 0xfd, 0xc7, 0x02, 0xfc, 0xb2, 0x58, 0xae, + 0xb9, 0x8d, 0xd6, 0xaf, 0x0e, 0x94, 0x0c, 0x40, 0x36, 0xa1, 0x64, 0x7b, 0x39, 0xba, 0xd7, 0xcd, + 0x33, 0x7a, 0x6d, 0x87, 0x32, 0xb3, 0x1d, 0x6c, 0x22, 0xb9, 0x06, 0x75, 0x63, 0x05, 0x43, 0x14, + 0x82, 0xc6, 0xa8, 0x05, 0x53, 0xf1, 0x6b, 0x06, 0x7d, 0x64, 0x40, 0x72, 0x07, 0x1a, 0x03, 0x2a, + 0xe4, 0xb3, 0x51, 0x44, 0x25, 0x06, 0x92, 0x0d, 0x51, 0x48, 0x3a, 0x1c, 0x69, 0xe5, 0x2c, 0xf8, + 0x2b, 0xd3, 0xd8, 0x7e, 0x1e, 0x22, 0x6d, 0x58, 0x66, 0x62, 0x53, 0x49, 0xda, 0xc7, 0x83, 0x71, + 0x12, 0x61, 0xa4, 0x65, 0x52, 0xf6, 0xdf, 0x87, 0x5b, 0xbf, 0x14, 0x61, 0x69, 0x5b, 0xed, 0x52, + 0x8b, 0x73, 0x3f, 0x23, 0x1e, 0x2c, 0x86, 0x29, 0x52, 0xc9, 0x73, 0x89, 0xe7, 0xae, 0x7a, 0x03, + 0x0c, 0x1b, 0xcd, 0x2e, 0x8d, 0x43, 0xbe, 0x81, 0x8a, 0xbe, 0x7f, 0x0e, 0x10, 0x85, 0x79, 0x1d, + 0xb6, 0xb6, 0xff, 0xa1, 0x16, 0xff, 0x7c, 0x73, 0xd5, 0x3d, 0xa6, 0xc3, 0xc1, 0x17, 0xad, 0x49, + 0xa5, 0x96, 0x5f, 0x56, 0xf6, 0x0e, 0xa2, 0x20, 0x37, 0x60, 0x39, 0xc5, 0x01, 0x3d, 0xc6, 0x68, + 0x32, 0xa7, 0x92, 0x51, 0x92, 0x85, 0xf3, 0x41, 0xed, 0x40, 0x35, 0x0c, 0x65, 0x96, 0x73, 0x40, + 0x09, 0xaa, 0x3a, 0xff, 0x66, 0x39, 0x71, 0x2e, 0xf6, 0x4c, 0x20, 0x9c, 0x9c, 0x0f, 0x79, 0x0a, + 0x75, 0x66, 0x9e, 0xe7, 0x60, 0xa4, 0x2f, 0x3e, 0xad, 0xbf, 0xea, 0xc6, 0xa7, 0x67, 0x94, 0x9a, + 0x79, 0xd3, 0xfd, 0x1a, 0x9b, 0x79, 0xe2, 0x9f, 0xc3, 0x32, 0xb7, 0xb7, 0x69, 0x5e, 0x15, 0xd6, + 0x17, 0xda, 0xd5, 0x8d, 0xdb, 0x67, 0x54, 0x9d, 0xbd, 0x83, 0xfd, 0x3a, 0x9f, 0xbd, 0x93, 0x53, + 0xb8, 0xac, 0xbf, 0x2a, 0x42, 0x3e, 0x08, 0x42, 0x9e, 0xc8, 0x94, 0x86, 0x32, 0x38, 0xc2, 0x54, + 0x30, 0x9e, 0xd8, 0x77, 0xe8, 0xb3, 0x33, 0x3a, 0xec, 0xd9, 0xfc, 0x6d, 0x9b, 0xfe, 0xdc, 0x64, + 0xfb, 0x97, 0x46, 0xf3, 0x03, 0xb7, 0xbe, 0x03, 0x98, 0xd2, 0x99, 0x10, 0xa8, 0xef, 0x61, 0x12, + 0xb1, 0x24, 0xb6, 0x03, 0x70, 0x0b, 0x64, 0x05, 0x96, 0x2d, 0x96, 0x6f, 0xdf, 0x75, 0xc8, 0x05, + 0xa8, 0xe5, 0xde, 0x23, 0x96, 0x60, 0xe4, 0x2e, 0x28, 0xc8, 0xae, 0xf3, 0xf1, 0x08, 0x53, 0xe9, + 0x16, 0xc9, 0x12, 0x94, 0x8d, 0x8d, 0x91, 0x7b, 0x9e, 0x54, 0x61, 0x71, 0xd3, 0x3c, 0x4d, 0x6e, + 0x69, 0xad, 0xf8, 0xd3, 0x8f, 0x4d, 0xe7, 0xd6, 0x43, 0x68, 0xcc, 0x13, 0x2e, 0x71, 0x61, 0xe9, + 0x31, 0x97, 0x3b, 0xf9, 0x43, 0xed, 0x16, 0x48, 0x0d, 0x2a, 0x53, 0xd7, 0x51, 0x95, 0xef, 0x65, + 0x18, 0x8e, 0x55, 0xb1, 0x73, 0xb6, 0x58, 0x17, 0x2e, 0xfd, 0xcd, 0xdf, 0x27, 0x25, 0x38, 0xf7, + 0xfc, 0x8e, 0x5b, 0xd0, 0xbf, 0x1b, 0xae, 0x63, 0x12, 0xb6, 0x1e, 0xbe, 0x7a, 0xdb, 0x74, 0x5e, + 0xbf, 0x6d, 0x3a, 0x7f, 0xbc, 0x6d, 0x3a, 0xdf, 0xbf, 0x6b, 0x16, 0x5e, 0xbf, 0x6b, 0x16, 0x7e, + 0x7b, 0xd7, 0x2c, 0xbc, 0xb8, 0x73, 0x82, 0xee, 0x6a, 0xcc, 0xb7, 0xdf, 0xfb, 0x14, 0xcc, 0x4e, + 0x7e, 0x75, 0x6a, 0xf6, 0xf7, 0x4a, 0x7a, 0xc2, 0x77, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xba, + 0x38, 0x19, 0x72, 0xa3, 0x0a, 0x00, 0x00, } func (m *InboundParams) Marshal() (dAtA []byte, err error) { @@ -968,6 +1008,11 @@ func (m *CrossChainTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ProtocolContractVersion != 0 { + i = encodeVarintCrossChainTx(dAtA, i, uint64(m.ProtocolContractVersion)) + i-- + dAtA[i] = 0x58 + } if len(m.OutboundParams) > 0 { for iNdEx := len(m.OutboundParams) - 1; iNdEx >= 0; iNdEx-- { { @@ -1225,6 +1270,9 @@ func (m *CrossChainTx) Size() (n int) { n += 1 + l + sovCrossChainTx(uint64(l)) } } + if m.ProtocolContractVersion != 0 { + n += 1 + sovCrossChainTx(uint64(m.ProtocolContractVersion)) + } return n } @@ -2524,6 +2572,25 @@ func (m *CrossChainTx) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProtocolContractVersion", wireType) + } + m.ProtocolContractVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProtocolContractVersion |= ProtocolContractVersion(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index 1422538b2f..79b9809a10 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -145,6 +145,7 @@ type FungibleKeeper interface { data []byte, coinType coin.CoinType, asset string, + protocolContractVersion ProtocolContractVersion, ) (*evmtypes.MsgEthereumTxResponse, bool, error) CallUniswapV2RouterSwapExactTokensForTokens( ctx sdk.Context, diff --git a/x/crosschain/types/message_vote_inbound.go b/x/crosschain/types/message_vote_inbound.go index b2ee24ce2d..4bbc3f65ff 100644 --- a/x/crosschain/types/message_vote_inbound.go +++ b/x/crosschain/types/message_vote_inbound.go @@ -34,22 +34,24 @@ func NewMsgVoteInbound( coinType coin.CoinType, asset string, eventIndex uint, + protocolContractVersion ProtocolContractVersion, ) *MsgVoteInbound { return &MsgVoteInbound{ - Creator: creator, - Sender: sender, - SenderChainId: senderChain, - TxOrigin: txOrigin, - Receiver: receiver, - ReceiverChain: receiverChain, - Amount: amount, - Message: message, - InboundHash: inboundHash, - InboundBlockHeight: inboundBlockHeight, - GasLimit: gasLimit, - CoinType: coinType, - Asset: asset, - EventIndex: uint64(eventIndex), + Creator: creator, + Sender: sender, + SenderChainId: senderChain, + TxOrigin: txOrigin, + Receiver: receiver, + ReceiverChain: receiverChain, + Amount: amount, + Message: message, + InboundHash: inboundHash, + InboundBlockHeight: inboundBlockHeight, + GasLimit: gasLimit, + CoinType: coinType, + Asset: asset, + EventIndex: uint64(eventIndex), + ProtocolContractVersion: protocolContractVersion, } } diff --git a/x/crosschain/types/message_vote_inbound_test.go b/x/crosschain/types/message_vote_inbound_test.go index f96f640b9e..27af8f1901 100644 --- a/x/crosschain/types/message_vote_inbound_test.go +++ b/x/crosschain/types/message_vote_inbound_test.go @@ -40,6 +40,7 @@ func TestMsgVoteInbound_ValidateBasic(t *testing.T) { coin.CoinType_Zeta, sample.String(), 42, + types.ProtocolContractVersion_V1, ), }, { @@ -59,6 +60,7 @@ func TestMsgVoteInbound_ValidateBasic(t *testing.T) { coin.CoinType_Zeta, sample.String(), 42, + types.ProtocolContractVersion_V1, ), err: sdkerrors.ErrInvalidAddress, }, @@ -79,6 +81,7 @@ func TestMsgVoteInbound_ValidateBasic(t *testing.T) { coin.CoinType_Zeta, sample.String(), 42, + types.ProtocolContractVersion_V1, ), err: types.ErrInvalidChainID, }, @@ -99,6 +102,7 @@ func TestMsgVoteInbound_ValidateBasic(t *testing.T) { coin.CoinType_Zeta, sample.String(), 42, + types.ProtocolContractVersion_V1, ), err: types.ErrInvalidChainID, }, @@ -119,6 +123,7 @@ func TestMsgVoteInbound_ValidateBasic(t *testing.T) { coin.CoinType_Zeta, sample.String(), 42, + types.ProtocolContractVersion_V1, ), err: sdkerrors.ErrInvalidRequest, }, @@ -139,20 +144,21 @@ func TestMsgVoteInbound_Digest(t *testing.T) { r := rand.New(rand.NewSource(42)) msg := types.MsgVoteInbound{ - Creator: sample.AccAddress(), - Sender: sample.AccAddress(), - SenderChainId: 42, - TxOrigin: sample.String(), - Receiver: sample.String(), - ReceiverChain: 42, - Amount: math.NewUint(42), - Message: sample.String(), - InboundHash: sample.String(), - InboundBlockHeight: 42, - GasLimit: 42, - CoinType: coin.CoinType_Zeta, - Asset: sample.String(), - EventIndex: 42, + Creator: sample.AccAddress(), + Sender: sample.AccAddress(), + SenderChainId: 42, + TxOrigin: sample.String(), + Receiver: sample.String(), + ReceiverChain: 42, + Amount: math.NewUint(42), + Message: sample.String(), + InboundHash: sample.String(), + InboundBlockHeight: 42, + GasLimit: 42, + CoinType: coin.CoinType_Zeta, + Asset: sample.String(), + EventIndex: 42, + ProtocolContractVersion: types.ProtocolContractVersion_V1, } hash := msg.Digest() require.NotEmpty(t, hash, "hash should not be empty") @@ -240,6 +246,12 @@ func TestMsgVoteInbound_Digest(t *testing.T) { msg.EventIndex = 43 hash2 = msg.Digest() require.NotEqual(t, hash, hash2, "event index should change hash") + + // protocol contract version used + msg = msg + msg.ProtocolContractVersion = types.ProtocolContractVersion_V2 + hash2 = msg.Digest() + require.NotEqual(t, hash, hash2, "protocol contract version should change hash") } func TestMsgVoteInbound_GetSigners(t *testing.T) { diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index 4bd154f595..6f4f1ff170 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -997,6 +997,8 @@ type MsgVoteInbound struct { Asset string `protobuf:"bytes,14,opt,name=asset,proto3" json:"asset,omitempty"` // event index of the sent asset in the observed tx EventIndex uint64 `protobuf:"varint,15,opt,name=event_index,json=eventIndex,proto3" json:"event_index,omitempty"` + // protocol contract version to use for the cctx workflow + ProtocolContractVersion ProtocolContractVersion `protobuf:"varint,16,opt,name=protocol_contract_version,json=protocolContractVersion,proto3,enum=zetachain.zetacore.crosschain.ProtocolContractVersion" json:"protocol_contract_version,omitempty"` } func (m *MsgVoteInbound) Reset() { *m = MsgVoteInbound{} } @@ -1123,6 +1125,13 @@ func (m *MsgVoteInbound) GetEventIndex() uint64 { return 0 } +func (m *MsgVoteInbound) GetProtocolContractVersion() ProtocolContractVersion { + if m != nil { + return m.ProtocolContractVersion + } + return ProtocolContractVersion_V1 +} + type MsgVoteInboundResponse struct { } @@ -1463,105 +1472,108 @@ func init() { } var fileDescriptor_15f0860550897740 = []byte{ - // 1557 bytes of a gzipped FileDescriptorProto + // 1609 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0x36, 0x8e, 0x63, 0x3f, 0xc7, 0x4e, 0xba, 0xa4, 0xa9, 0xb3, 0x69, 0x9c, 0xd4, 0xa5, - 0x21, 0x42, 0xad, 0x9d, 0xba, 0xa5, 0x94, 0x16, 0x01, 0x8d, 0xe9, 0x9f, 0x40, 0xdd, 0x46, 0xdb, - 0x14, 0x10, 0x97, 0xd5, 0x7a, 0x77, 0xb2, 0x5e, 0xd9, 0xde, 0xb1, 0x76, 0xc6, 0x96, 0x53, 0x21, - 0x81, 0x90, 0x90, 0x38, 0x02, 0xe2, 0xc4, 0x81, 0x1b, 0x12, 0x67, 0x3e, 0x45, 0x8f, 0x15, 0x27, - 0xc4, 0xa1, 0x42, 0xed, 0x27, 0x80, 0x4f, 0x80, 0x76, 0x66, 0x76, 0xeb, 0x5d, 0xff, 0x8d, 0x2b, - 0xc4, 0xc5, 0xde, 0x79, 0xf3, 0x7e, 0x6f, 0xde, 0xbf, 0x79, 0xef, 0xed, 0xc2, 0xd6, 0x63, 0x44, - 0x75, 0xa3, 0xa6, 0xdb, 0x4e, 0x91, 0x3d, 0x61, 0x17, 0x15, 0x0d, 0x17, 0x13, 0xc2, 0x69, 0xb4, - 0x5b, 0x68, 0xb9, 0x98, 0x62, 0x79, 0x3d, 0xe0, 0x2b, 0xf8, 0x7c, 0x85, 0x97, 0x7c, 0xca, 0xb2, - 0x85, 0x2d, 0xcc, 0x38, 0x8b, 0xde, 0x13, 0x07, 0x29, 0x6f, 0x0e, 0x10, 0xde, 0xaa, 0x5b, 0x45, - 0x46, 0x22, 0xe2, 0x4f, 0xf0, 0x6e, 0x0d, 0xe3, 0xc5, 0xb6, 0xc3, 0x7e, 0xc6, 0xc8, 0x6c, 0xb9, - 0x18, 0x1f, 0x12, 0xf1, 0x27, 0x78, 0xaf, 0x8e, 0x36, 0xce, 0xd5, 0x29, 0xd2, 0x1a, 0x76, 0xd3, - 0xa6, 0xc8, 0xd5, 0x0e, 0x1b, 0xba, 0x25, 0x70, 0xf9, 0x1f, 0x24, 0x90, 0x2b, 0xc4, 0xaa, 0xd8, - 0x96, 0xc7, 0x72, 0x40, 0xc8, 0xed, 0xb6, 0x63, 0x12, 0x39, 0x0b, 0xf3, 0x86, 0x8b, 0x74, 0x8a, - 0xdd, 0xac, 0xb4, 0x29, 0x6d, 0x27, 0x55, 0x7f, 0x29, 0xaf, 0x42, 0x82, 0x89, 0xd4, 0x6c, 0x33, - 0x7b, 0x62, 0x53, 0xda, 0x9e, 0x55, 0xe7, 0xd9, 0x7a, 0xcf, 0x94, 0xef, 0x40, 0x5c, 0x6f, 0xe2, - 0xb6, 0x43, 0xb3, 0xb3, 0x1e, 0x66, 0xb7, 0xf8, 0xe4, 0xd9, 0xc6, 0xcc, 0x9f, 0xcf, 0x36, 0xde, - 0xb0, 0x6c, 0x5a, 0x6b, 0x57, 0x0b, 0x06, 0x6e, 0x16, 0x0d, 0x4c, 0x9a, 0x98, 0x88, 0xbf, 0x8b, - 0xc4, 0xac, 0x17, 0xe9, 0x51, 0x0b, 0x91, 0xc2, 0x23, 0xdb, 0xa1, 0xaa, 0x80, 0xe7, 0xcf, 0x80, - 0xd2, 0xaf, 0x93, 0x8a, 0x48, 0x0b, 0x3b, 0x04, 0xe5, 0xef, 0xc3, 0x6b, 0x15, 0x62, 0x3d, 0x6a, - 0x99, 0x7c, 0xf3, 0xa6, 0x69, 0xba, 0x88, 0x8c, 0x52, 0x79, 0x1d, 0x80, 0x12, 0xa2, 0xb5, 0xda, - 0xd5, 0x3a, 0x3a, 0x62, 0x4a, 0x27, 0xd5, 0x24, 0x25, 0x64, 0x9f, 0x11, 0xf2, 0xeb, 0xb0, 0x36, - 0x40, 0x5e, 0x70, 0xdc, 0xcf, 0x27, 0x60, 0xb9, 0x42, 0xac, 0x9b, 0xa6, 0xb9, 0xe7, 0x54, 0x71, - 0xdb, 0x31, 0x0f, 0x5c, 0xdd, 0xa8, 0x23, 0x77, 0x3a, 0x1f, 0x9d, 0x86, 0x79, 0xda, 0xd5, 0x6a, - 0x3a, 0xa9, 0x71, 0x27, 0xa9, 0x71, 0xda, 0xbd, 0xab, 0x93, 0x9a, 0xbc, 0x0b, 0x49, 0x2f, 0xf4, - 0x9a, 0xe7, 0x8e, 0x6c, 0x6c, 0x53, 0xda, 0xce, 0x94, 0xce, 0x17, 0x06, 0x64, 0x62, 0xab, 0x6e, - 0x15, 0x58, 0x8e, 0x94, 0xb1, 0xed, 0x1c, 0x1c, 0xb5, 0x90, 0x9a, 0x30, 0xc4, 0x93, 0x7c, 0x1d, - 0xe6, 0x58, 0x52, 0x64, 0xe7, 0x36, 0xa5, 0xed, 0x54, 0xe9, 0xf5, 0x61, 0x78, 0x91, 0x39, 0xfb, - 0xde, 0x9f, 0xca, 0x21, 0x9e, 0x93, 0xaa, 0x0d, 0x6c, 0xd4, 0xb9, 0x6e, 0x71, 0xee, 0x24, 0x46, - 0x61, 0xea, 0xad, 0x42, 0x82, 0x76, 0x35, 0xdb, 0x31, 0x51, 0x37, 0x3b, 0xcf, 0x4d, 0xa2, 0xdd, - 0x3d, 0x6f, 0x99, 0xcf, 0xc1, 0x99, 0x41, 0xfe, 0x09, 0x1c, 0xf8, 0xbb, 0x04, 0x27, 0x2b, 0xc4, - 0xfa, 0xb4, 0x66, 0x53, 0xd4, 0xb0, 0x09, 0xbd, 0xa5, 0x96, 0x4b, 0x3b, 0x23, 0xbc, 0x77, 0x0e, - 0xd2, 0xc8, 0x35, 0x4a, 0x3b, 0x9a, 0xce, 0x23, 0x21, 0x22, 0xb6, 0xc0, 0x88, 0x7e, 0xb4, 0x7b, - 0x5d, 0x3c, 0x1b, 0x76, 0xb1, 0x0c, 0x31, 0x47, 0x6f, 0x72, 0x27, 0x26, 0x55, 0xf6, 0x2c, 0xaf, - 0x40, 0x9c, 0x1c, 0x35, 0xab, 0xb8, 0xc1, 0x5c, 0x93, 0x54, 0xc5, 0x4a, 0x56, 0x20, 0x61, 0x22, - 0xc3, 0x6e, 0xea, 0x0d, 0xc2, 0x6c, 0x4e, 0xab, 0xc1, 0x5a, 0x5e, 0x83, 0xa4, 0xa5, 0x13, 0x7e, - 0x6b, 0x84, 0xcd, 0x09, 0x4b, 0x27, 0xf7, 0xbc, 0x75, 0x5e, 0x83, 0xd5, 0x3e, 0x9b, 0x7c, 0x8b, - 0x3d, 0x0b, 0x1e, 0x87, 0x2c, 0xe0, 0x16, 0x2e, 0x3c, 0xee, 0xb5, 0x60, 0x1d, 0xc0, 0x30, 0x02, - 0x9f, 0x8a, 0xac, 0xf4, 0x28, 0xdc, 0xab, 0x7f, 0x4b, 0x70, 0x8a, 0xbb, 0xf5, 0x41, 0x9b, 0xbe, - 0x7a, 0xde, 0x2d, 0xc3, 0x9c, 0x83, 0x1d, 0x03, 0x31, 0x67, 0xc5, 0x54, 0xbe, 0xe8, 0xcd, 0xc6, - 0x58, 0x28, 0x1b, 0xff, 0x9f, 0x4c, 0x7a, 0x0f, 0xd6, 0x07, 0x9a, 0x1c, 0x38, 0x76, 0x1d, 0xc0, - 0x26, 0x9a, 0x8b, 0x9a, 0xb8, 0x83, 0x4c, 0x66, 0x7d, 0x42, 0x4d, 0xda, 0x44, 0xe5, 0x84, 0x3c, - 0x82, 0x6c, 0x85, 0x58, 0x7c, 0xf5, 0xdf, 0x79, 0x2d, 0x9f, 0x87, 0xcd, 0x61, 0xc7, 0x04, 0x49, - 0xff, 0xab, 0x04, 0x8b, 0x15, 0x62, 0x7d, 0x82, 0x29, 0xba, 0xa3, 0x93, 0x7d, 0xd7, 0x36, 0xd0, - 0xd4, 0x2a, 0xb4, 0x3c, 0xb4, 0xaf, 0x02, 0x5b, 0xc8, 0x67, 0x61, 0xa1, 0xe5, 0xda, 0xd8, 0xb5, - 0xe9, 0x91, 0x76, 0x88, 0x10, 0xf3, 0x72, 0x4c, 0x4d, 0xf9, 0xb4, 0xdb, 0x88, 0xb1, 0xf0, 0x30, - 0x38, 0xed, 0x66, 0x15, 0xb9, 0x2c, 0xc0, 0x31, 0x35, 0xc5, 0x68, 0xf7, 0x19, 0xe9, 0xa3, 0x58, - 0x62, 0x6e, 0x29, 0x9e, 0x5f, 0x85, 0xd3, 0x11, 0x4d, 0x03, 0x2b, 0x7e, 0x89, 0x07, 0x56, 0xf8, - 0x86, 0x8e, 0xb0, 0x62, 0x0d, 0x58, 0xfe, 0xf2, 0xb8, 0xf3, 0x84, 0x4e, 0x78, 0x04, 0x16, 0xf6, - 0x2b, 0xb0, 0x82, 0xab, 0x04, 0xb9, 0x1d, 0x64, 0x6a, 0x58, 0xc8, 0xea, 0xad, 0x83, 0xcb, 0xfe, - 0xae, 0x7f, 0x10, 0x43, 0x95, 0x21, 0xd7, 0x8f, 0x12, 0xd9, 0x85, 0x6c, 0xab, 0x46, 0x85, 0x59, - 0x6b, 0x51, 0xf4, 0x2e, 0xcb, 0x37, 0xc6, 0x22, 0xdf, 0x00, 0xa5, 0x5f, 0x88, 0x77, 0xb5, 0xdb, - 0x04, 0x99, 0x59, 0x60, 0x02, 0x4e, 0x47, 0x05, 0xdc, 0xd1, 0xc9, 0x23, 0x82, 0x4c, 0xf9, 0x2b, - 0x09, 0xce, 0xf7, 0xa3, 0xd1, 0xe1, 0x21, 0x32, 0xa8, 0xdd, 0x41, 0x4c, 0x0e, 0x0f, 0x50, 0x8a, - 0x35, 0xbd, 0x82, 0x68, 0x7a, 0x5b, 0x13, 0x34, 0xbd, 0x3d, 0x87, 0xaa, 0x67, 0xa3, 0x07, 0xdf, - 0xf2, 0x45, 0x07, 0x79, 0xb3, 0x3f, 0x5e, 0x03, 0x5e, 0xa4, 0x16, 0x98, 0x29, 0x23, 0x25, 0xb2, - 0xea, 0x25, 0x63, 0xc8, 0x74, 0xf4, 0x46, 0x1b, 0x69, 0x2e, 0x32, 0x90, 0xed, 0xdd, 0x25, 0x56, - 0x16, 0x77, 0xef, 0x1e, 0xb3, 0x63, 0xff, 0xf3, 0x6c, 0xe3, 0xd4, 0x91, 0xde, 0x6c, 0x5c, 0xcf, - 0x87, 0xc5, 0xe5, 0xd5, 0x34, 0x23, 0xa8, 0x62, 0x2d, 0x7f, 0x08, 0x71, 0x42, 0x75, 0xda, 0xe6, - 0x55, 0x36, 0x53, 0xba, 0x30, 0xb4, 0xb5, 0xf1, 0x41, 0x49, 0x00, 0x1f, 0x32, 0x8c, 0x2a, 0xb0, - 0xf2, 0x79, 0xc8, 0x04, 0xf6, 0x33, 0x46, 0x51, 0x40, 0xd2, 0x3e, 0xb5, 0xec, 0x11, 0xe5, 0x0b, - 0x20, 0x07, 0x6c, 0x5e, 0xe3, 0xe7, 0x57, 0x38, 0xc1, 0x9c, 0xb3, 0xe4, 0xef, 0x1c, 0x10, 0x72, - 0x9f, 0xd5, 0xc0, 0x50, 0xe3, 0x4d, 0x4e, 0xd5, 0x78, 0x7b, 0xae, 0x90, 0xef, 0xf3, 0xe0, 0x0a, - 0xfd, 0x14, 0x83, 0x8c, 0xd8, 0x13, 0xfd, 0x71, 0xc4, 0x0d, 0xf2, 0xda, 0x14, 0x72, 0x4c, 0xe4, - 0x8a, 0xeb, 0x23, 0x56, 0xf2, 0x16, 0x2c, 0xf2, 0x27, 0x2d, 0xd2, 0xf4, 0xd2, 0x9c, 0x5c, 0x16, - 0xc5, 0x42, 0x81, 0x84, 0x08, 0x81, 0x2b, 0x0a, 0x7a, 0xb0, 0xf6, 0x9c, 0xe7, 0x3f, 0x0b, 0xe7, - 0xcd, 0x71, 0x11, 0x3e, 0x95, 0x3b, 0xef, 0xe5, 0x10, 0x17, 0x7f, 0xa5, 0x21, 0xce, 0xb3, 0xb2, - 0x89, 0x08, 0xd1, 0x2d, 0xee, 0xfa, 0xa4, 0xea, 0x2f, 0xbd, 0xca, 0x64, 0x3b, 0x3d, 0x05, 0x20, - 0xc9, 0xb6, 0x53, 0x82, 0xc6, 0xee, 0xfd, 0x0e, 0x2c, 0xfb, 0x2c, 0xa1, 0xdb, 0xce, 0x2f, 0xab, - 0x2c, 0xf6, 0x7a, 0x2f, 0x79, 0xa8, 0x5b, 0xa7, 0x18, 0x5b, 0xd0, 0xad, 0xc3, 0x31, 0x5e, 0x98, - 0x6e, 0xb8, 0x5a, 0x83, 0x24, 0xed, 0x6a, 0xd8, 0xb5, 0x2d, 0xdb, 0xc9, 0xa6, 0xb9, 0x73, 0x69, - 0xf7, 0x01, 0x5b, 0x7b, 0x55, 0x5a, 0x27, 0x04, 0xd1, 0x6c, 0x86, 0x6d, 0xf0, 0x85, 0xbc, 0x01, - 0x29, 0xd4, 0x41, 0x0e, 0x15, 0xdd, 0x6e, 0x91, 0x69, 0x05, 0x8c, 0xc4, 0x1b, 0x5e, 0x16, 0x56, - 0xc2, 0xb9, 0x11, 0xa4, 0xcd, 0x3d, 0x36, 0x33, 0xdd, 0xac, 0x62, 0x97, 0x3e, 0xa4, 0x6d, 0xa3, - 0x5e, 0x2e, 0x1f, 0x7c, 0x36, 0x7a, 0xc4, 0x1d, 0x35, 0x4c, 0xac, 0xb1, 0x69, 0x25, 0x2c, 0x2d, - 0x38, 0xaa, 0xc3, 0xe6, 0x5b, 0x15, 0x1d, 0xb6, 0x1d, 0x93, 0xb1, 0x20, 0xf3, 0x95, 0x4e, 0xe3, - 0x99, 0xe6, 0x49, 0x0b, 0xe6, 0x1f, 0x5e, 0xe2, 0xd3, 0x9c, 0x2a, 0x06, 0x20, 0x31, 0x37, 0xf6, - 0x9d, 0xfb, 0xf2, 0xe6, 0x48, 0x4c, 0x6b, 0x3e, 0x98, 0xab, 0x3a, 0x45, 0xf7, 0xf8, 0xfb, 0xcb, - 0x6d, 0xef, 0xf5, 0x65, 0x84, 0x76, 0x06, 0xc8, 0xfd, 0xaf, 0x3b, 0x4c, 0xcb, 0x54, 0xa9, 0x58, - 0x18, 0xf9, 0x72, 0x57, 0x88, 0x1e, 0xb3, 0x1b, 0xf3, 0xd2, 0x5f, 0x5d, 0x72, 0x23, 0xf4, 0xfc, - 0x39, 0x38, 0x3b, 0x54, 0x37, 0xdf, 0x82, 0xd2, 0x6f, 0x0b, 0x30, 0x5b, 0x21, 0x96, 0xfc, 0xad, - 0x04, 0xf2, 0x80, 0x41, 0xee, 0xca, 0x18, 0x65, 0x06, 0xce, 0x42, 0xca, 0xbb, 0xd3, 0xa0, 0x82, - 0x09, 0xea, 0x1b, 0x09, 0x4e, 0xf6, 0xbf, 0xca, 0x5c, 0x9e, 0x48, 0x66, 0x18, 0xa4, 0xdc, 0x98, - 0x02, 0x14, 0xe8, 0xf1, 0xbd, 0x04, 0xa7, 0x06, 0x0f, 0x6a, 0x6f, 0x8f, 0x17, 0x3b, 0x10, 0xa8, - 0xbc, 0x3f, 0x25, 0x30, 0xd0, 0xa9, 0x03, 0x0b, 0xa1, 0x79, 0xad, 0x30, 0x5e, 0x60, 0x2f, 0xbf, - 0x72, 0xf5, 0x78, 0xfc, 0xd1, 0x73, 0x83, 0x09, 0x6b, 0xc2, 0x73, 0x7d, 0xfe, 0x49, 0xcf, 0x8d, - 0xb6, 0x26, 0x99, 0x40, 0xaa, 0xb7, 0x2d, 0x5d, 0x9c, 0x4c, 0x8c, 0x60, 0x57, 0xde, 0x3a, 0x16, - 0x7b, 0x70, 0xe8, 0x17, 0x90, 0x89, 0xbc, 0x09, 0xee, 0x8c, 0x17, 0x14, 0x46, 0x28, 0xd7, 0x8e, - 0x8b, 0x08, 0x4e, 0xff, 0x5a, 0x82, 0xa5, 0xbe, 0x2f, 0x07, 0xa5, 0xf1, 0xe2, 0xa2, 0x18, 0xe5, - 0xfa, 0xf1, 0x31, 0x81, 0x12, 0x5f, 0xc2, 0x62, 0xf4, 0x7b, 0xcb, 0xa5, 0xf1, 0xe2, 0x22, 0x10, - 0xe5, 0x9d, 0x63, 0x43, 0x7a, 0x63, 0x10, 0xe9, 0x2c, 0x13, 0xc4, 0x20, 0x8c, 0x98, 0x24, 0x06, - 0x83, 0xfb, 0x0d, 0x2b, 0x41, 0xfd, 0xdd, 0xe6, 0xf2, 0x24, 0xb7, 0x37, 0x02, 0x9a, 0xa4, 0x04, - 0x0d, 0xed, 0x2f, 0xf2, 0x8f, 0x12, 0xac, 0x0c, 0x69, 0x2e, 0xd7, 0x26, 0x8d, 0x6e, 0x14, 0xa9, - 0x7c, 0x30, 0x2d, 0xd2, 0x57, 0x6b, 0xf7, 0xe3, 0x27, 0xcf, 0x73, 0xd2, 0xd3, 0xe7, 0x39, 0xe9, - 0xaf, 0xe7, 0x39, 0xe9, 0xbb, 0x17, 0xb9, 0x99, 0xa7, 0x2f, 0x72, 0x33, 0x7f, 0xbc, 0xc8, 0xcd, - 0x7c, 0x7e, 0xa9, 0x67, 0x04, 0xf3, 0x64, 0x5f, 0x8c, 0x7c, 0xef, 0xeb, 0x86, 0x3e, 0x67, 0x7a, - 0x13, 0x59, 0x35, 0xce, 0xbe, 0xf2, 0x5d, 0xfe, 0x37, 0x00, 0x00, 0xff, 0xff, 0xda, 0xb5, 0x92, - 0x0a, 0xfc, 0x14, 0x00, 0x00, + 0x14, 0xcf, 0x36, 0x8e, 0x63, 0x3f, 0xe7, 0x5f, 0x97, 0x34, 0x71, 0x9c, 0xc6, 0x49, 0x5d, 0x1a, + 0x22, 0xd4, 0xda, 0xa9, 0x5b, 0x4a, 0x69, 0x11, 0xd0, 0x98, 0xfe, 0x09, 0xd4, 0x6d, 0xb4, 0x4d, + 0x0b, 0xe2, 0xb2, 0x5a, 0xef, 0x4e, 0x36, 0xab, 0xd8, 0x3b, 0xd6, 0xce, 0xd8, 0x72, 0x2a, 0x24, + 0x10, 0x12, 0x12, 0x27, 0x04, 0x88, 0x13, 0x07, 0x6e, 0x48, 0x9c, 0xf9, 0x14, 0x3d, 0x56, 0x9c, + 0x10, 0x87, 0x0a, 0xb5, 0x9f, 0x00, 0x3e, 0x01, 0xda, 0x37, 0xb3, 0x5b, 0x7b, 0xed, 0xd8, 0x8e, + 0x2b, 0xc4, 0xc5, 0xde, 0xf7, 0xe6, 0xfd, 0xde, 0xbc, 0x7f, 0x33, 0xef, 0xed, 0xc2, 0xfa, 0x63, + 0xc2, 0x0d, 0x73, 0xdf, 0x70, 0xdc, 0x02, 0x3e, 0x51, 0x8f, 0x14, 0x4c, 0x8f, 0x32, 0x26, 0x78, + 0xbc, 0x95, 0xaf, 0x7b, 0x94, 0x53, 0x75, 0x25, 0x94, 0xcb, 0x07, 0x72, 0xf9, 0x97, 0x72, 0x99, + 0x79, 0x9b, 0xda, 0x14, 0x25, 0x0b, 0xfe, 0x93, 0x00, 0x65, 0xde, 0xec, 0xa1, 0xbc, 0x7e, 0x60, + 0x17, 0x90, 0xc5, 0xe4, 0x9f, 0x94, 0x5d, 0x3f, 0x4a, 0x96, 0x3a, 0x2e, 0xfe, 0x0c, 0xd0, 0x59, + 0xf7, 0x28, 0xdd, 0x63, 0xf2, 0x4f, 0xca, 0x5e, 0xe9, 0xef, 0x9c, 0x67, 0x70, 0xa2, 0x57, 0x9d, + 0x9a, 0xc3, 0x89, 0xa7, 0xef, 0x55, 0x0d, 0x3b, 0xc0, 0x15, 0xfb, 0xe3, 0xf0, 0x51, 0xc7, 0x67, + 0x3d, 0x08, 0x50, 0xee, 0x07, 0x05, 0xd4, 0x32, 0xb3, 0xcb, 0x8e, 0xed, 0xab, 0xdd, 0x65, 0xec, + 0x56, 0xc3, 0xb5, 0x98, 0x9a, 0x86, 0x49, 0xd3, 0x23, 0x06, 0xa7, 0x5e, 0x5a, 0x59, 0x53, 0x36, + 0x92, 0x5a, 0x40, 0xaa, 0x4b, 0x90, 0x10, 0x2a, 0x1c, 0x2b, 0x7d, 0x62, 0x4d, 0xd9, 0x18, 0xd7, + 0x26, 0x91, 0xde, 0xb6, 0xd4, 0xdb, 0x10, 0x37, 0x6a, 0xb4, 0xe1, 0xf2, 0xf4, 0xb8, 0x8f, 0xd9, + 0x2a, 0x3c, 0x79, 0xb6, 0x3a, 0xf6, 0xe7, 0xb3, 0xd5, 0x37, 0x6c, 0x87, 0xef, 0x37, 0x2a, 0x79, + 0x93, 0xd6, 0x0a, 0x26, 0x65, 0x35, 0xca, 0xe4, 0xdf, 0x05, 0x66, 0x1d, 0x14, 0xf8, 0x61, 0x9d, + 0xb0, 0xfc, 0x43, 0xc7, 0xe5, 0x9a, 0x84, 0xe7, 0x4e, 0x43, 0xa6, 0xdb, 0x26, 0x8d, 0xb0, 0x3a, + 0x75, 0x19, 0xc9, 0xdd, 0x83, 0xd7, 0xca, 0xcc, 0x7e, 0x58, 0xb7, 0xc4, 0xe2, 0x0d, 0xcb, 0xf2, + 0x08, 0xeb, 0x67, 0xf2, 0x0a, 0x00, 0x67, 0x4c, 0xaf, 0x37, 0x2a, 0x07, 0xe4, 0x10, 0x8d, 0x4e, + 0x6a, 0x49, 0xce, 0xd8, 0x0e, 0x32, 0x72, 0x2b, 0xb0, 0xdc, 0x43, 0x5f, 0xb8, 0xdd, 0xcf, 0x27, + 0x60, 0xbe, 0xcc, 0xec, 0x1b, 0x96, 0xb5, 0xed, 0x56, 0x68, 0xc3, 0xb5, 0x76, 0x3d, 0xc3, 0x3c, + 0x20, 0xde, 0x68, 0x31, 0x5a, 0x84, 0x49, 0xde, 0xd2, 0xf7, 0x0d, 0xb6, 0x2f, 0x82, 0xa4, 0xc5, + 0x79, 0xeb, 0x8e, 0xc1, 0xf6, 0xd5, 0x2d, 0x48, 0xfa, 0xe5, 0xa2, 0xfb, 0xe1, 0x48, 0xc7, 0xd6, + 0x94, 0x8d, 0x99, 0xe2, 0xb9, 0x7c, 0x8f, 0xea, 0xad, 0x1f, 0xd8, 0x79, 0xac, 0xab, 0x12, 0x75, + 0xdc, 0xdd, 0xc3, 0x3a, 0xd1, 0x12, 0xa6, 0x7c, 0x52, 0xaf, 0xc1, 0x04, 0x16, 0x52, 0x7a, 0x62, + 0x4d, 0xd9, 0x48, 0x15, 0x5f, 0x3f, 0x0a, 0x2f, 0xab, 0x6d, 0xc7, 0xff, 0xd3, 0x04, 0xc4, 0x0f, + 0x52, 0xa5, 0x4a, 0xcd, 0x03, 0x61, 0x5b, 0x5c, 0x04, 0x09, 0x39, 0x68, 0xde, 0x12, 0x24, 0x78, + 0x4b, 0x77, 0x5c, 0x8b, 0xb4, 0xd2, 0x93, 0xc2, 0x25, 0xde, 0xda, 0xf6, 0xc9, 0x5c, 0x16, 0x4e, + 0xf7, 0x8a, 0x4f, 0x18, 0xc0, 0xdf, 0x15, 0x38, 0x59, 0x66, 0xf6, 0x27, 0xfb, 0x0e, 0x27, 0x55, + 0x87, 0xf1, 0x9b, 0x5a, 0xa9, 0xb8, 0xd9, 0x27, 0x7a, 0x67, 0x61, 0x9a, 0x78, 0x66, 0x71, 0x53, + 0x37, 0x44, 0x26, 0x64, 0xc6, 0xa6, 0x90, 0x19, 0x64, 0xbb, 0x3d, 0xc4, 0xe3, 0x9d, 0x21, 0x56, + 0x21, 0xe6, 0x1a, 0x35, 0x11, 0xc4, 0xa4, 0x86, 0xcf, 0xea, 0x02, 0xc4, 0xd9, 0x61, 0xad, 0x42, + 0xab, 0x18, 0x9a, 0xa4, 0x26, 0x29, 0x35, 0x03, 0x09, 0x8b, 0x98, 0x4e, 0xcd, 0xa8, 0x32, 0xf4, + 0x79, 0x5a, 0x0b, 0x69, 0x75, 0x19, 0x92, 0xb6, 0xc1, 0xc4, 0x49, 0x93, 0x3e, 0x27, 0x6c, 0x83, + 0xdd, 0xf5, 0xe9, 0x9c, 0x0e, 0x4b, 0x5d, 0x3e, 0x05, 0x1e, 0xfb, 0x1e, 0x3c, 0xee, 0xf0, 0x40, + 0x78, 0x38, 0xf5, 0xb8, 0xdd, 0x83, 0x15, 0x00, 0xd3, 0x0c, 0x63, 0x2a, 0xab, 0xd2, 0xe7, 0x88, + 0xa8, 0xfe, 0xad, 0xc0, 0x29, 0x11, 0xd6, 0xfb, 0x0d, 0xfe, 0xea, 0x75, 0x37, 0x0f, 0x13, 0x2e, + 0x75, 0x4d, 0x82, 0xc1, 0x8a, 0x69, 0x82, 0x68, 0xaf, 0xc6, 0x58, 0x47, 0x35, 0xfe, 0x3f, 0x95, + 0xf4, 0x1e, 0xac, 0xf4, 0x74, 0x39, 0x0c, 0xec, 0x0a, 0x80, 0xc3, 0x74, 0x8f, 0xd4, 0x68, 0x93, + 0x58, 0xe8, 0x7d, 0x42, 0x4b, 0x3a, 0x4c, 0x13, 0x8c, 0x1c, 0x81, 0x74, 0x99, 0xd9, 0x82, 0xfa, + 0xef, 0xa2, 0x96, 0xcb, 0xc1, 0xda, 0x51, 0xdb, 0x84, 0x45, 0xff, 0xab, 0x02, 0xb3, 0x65, 0x66, + 0x3f, 0xa2, 0x9c, 0xdc, 0x36, 0xd8, 0x8e, 0xe7, 0x98, 0x64, 0x64, 0x13, 0xea, 0x3e, 0x3a, 0x30, + 0x01, 0x09, 0xf5, 0x0c, 0x4c, 0xd5, 0x3d, 0x87, 0x7a, 0x0e, 0x3f, 0xd4, 0xf7, 0x08, 0xc1, 0x28, + 0xc7, 0xb4, 0x54, 0xc0, 0xbb, 0x45, 0x50, 0x44, 0xa4, 0xc1, 0x6d, 0xd4, 0x2a, 0xc4, 0xc3, 0x04, + 0xc7, 0xb4, 0x14, 0xf2, 0xee, 0x21, 0xeb, 0xa3, 0x58, 0x62, 0x62, 0x2e, 0x9e, 0x5b, 0x82, 0xc5, + 0x88, 0xa5, 0xa1, 0x17, 0xbf, 0xc4, 0x43, 0x2f, 0x02, 0x47, 0xfb, 0x78, 0xb1, 0x0c, 0x58, 0xbf, + 0x22, 0xef, 0xa2, 0xa0, 0x13, 0x3e, 0x03, 0xd3, 0x7e, 0x19, 0x16, 0x68, 0x85, 0x11, 0xaf, 0x49, + 0x2c, 0x9d, 0x4a, 0x5d, 0xed, 0xf7, 0xe0, 0x7c, 0xb0, 0x1a, 0x6c, 0x84, 0xa8, 0x12, 0x64, 0xbb, + 0x51, 0xb2, 0xba, 0x88, 0x63, 0xef, 0x73, 0xe9, 0xd6, 0x72, 0x14, 0xbd, 0x85, 0xf5, 0x86, 0x22, + 0xea, 0x75, 0xc8, 0x74, 0x2b, 0xf1, 0x8f, 0x76, 0x83, 0x11, 0x2b, 0x0d, 0xa8, 0x60, 0x31, 0xaa, + 0xe0, 0xb6, 0xc1, 0x1e, 0x32, 0x62, 0xa9, 0x5f, 0x2a, 0x70, 0xae, 0x1b, 0x4d, 0xf6, 0xf6, 0x88, + 0xc9, 0x9d, 0x26, 0x41, 0x3d, 0x22, 0x41, 0x29, 0x6c, 0x7a, 0x79, 0xd9, 0xf4, 0xd6, 0x87, 0x68, + 0x7a, 0xdb, 0x2e, 0xd7, 0xce, 0x44, 0x37, 0xbe, 0x19, 0xa8, 0x0e, 0xeb, 0x66, 0x67, 0xb0, 0x05, + 0xe2, 0x92, 0x9a, 0x42, 0x57, 0xfa, 0x6a, 0xc4, 0xdb, 0x4b, 0xa5, 0x30, 0xd3, 0x34, 0xaa, 0x0d, + 0xa2, 0x7b, 0xc4, 0x24, 0x8e, 0x7f, 0x96, 0xf0, 0x5a, 0xdc, 0xba, 0x73, 0xcc, 0x8e, 0xfd, 0xcf, + 0xb3, 0xd5, 0x53, 0x87, 0x46, 0xad, 0x7a, 0x2d, 0xd7, 0xa9, 0x2e, 0xa7, 0x4d, 0x23, 0x43, 0x93, + 0xb4, 0xfa, 0x21, 0xc4, 0x19, 0x37, 0x78, 0x43, 0xdc, 0xb2, 0x33, 0xc5, 0xf3, 0x47, 0xb6, 0x36, + 0x31, 0x5c, 0x49, 0xe0, 0x03, 0xc4, 0x68, 0x12, 0xab, 0x9e, 0x83, 0x99, 0xd0, 0x7f, 0x14, 0x94, + 0x17, 0xc8, 0x74, 0xc0, 0x2d, 0xf9, 0x4c, 0xf5, 0x3c, 0xa8, 0xa1, 0x98, 0xdf, 0xf8, 0xc5, 0x11, + 0x4e, 0x60, 0x70, 0xe6, 0x82, 0x95, 0x5d, 0xc6, 0xee, 0xe1, 0x1d, 0xd8, 0xd1, 0x78, 0x93, 0x23, + 0x35, 0xde, 0xb6, 0x23, 0x14, 0xc4, 0x3c, 0x3c, 0x42, 0xdf, 0x4e, 0xc0, 0x8c, 0x5c, 0x93, 0xfd, + 0xb1, 0xcf, 0x09, 0xf2, 0xdb, 0x14, 0x71, 0x2d, 0xe2, 0xc9, 0xe3, 0x23, 0x29, 0x75, 0x1d, 0x66, + 0xc5, 0x93, 0x1e, 0x69, 0x7a, 0xd3, 0x82, 0x5d, 0x92, 0x97, 0x45, 0x06, 0x12, 0x32, 0x05, 0x9e, + 0xbc, 0xd0, 0x43, 0xda, 0x0f, 0x5e, 0xf0, 0x2c, 0x83, 0x37, 0x21, 0x54, 0x04, 0x5c, 0x11, 0xbc, + 0x97, 0x43, 0x5c, 0xfc, 0x95, 0x86, 0x38, 0xdf, 0xcb, 0x1a, 0x61, 0xcc, 0xb0, 0x45, 0xe8, 0x93, + 0x5a, 0x40, 0xfa, 0x37, 0x93, 0xe3, 0xb6, 0x5d, 0x00, 0x49, 0x5c, 0x4e, 0x49, 0x1e, 0x9e, 0xfb, + 0x4d, 0x98, 0x0f, 0x44, 0x3a, 0x4e, 0xbb, 0x38, 0xac, 0xaa, 0x5c, 0x6b, 0x3f, 0xe4, 0x1d, 0xdd, + 0x3a, 0x85, 0x62, 0x61, 0xb7, 0xee, 0xcc, 0xf1, 0xd4, 0x68, 0xc3, 0xd5, 0x32, 0x24, 0x79, 0x4b, + 0xa7, 0x9e, 0x63, 0x3b, 0x6e, 0x7a, 0x5a, 0x04, 0x97, 0xb7, 0xee, 0x23, 0xed, 0xdf, 0xd2, 0x06, + 0x63, 0x84, 0xa7, 0x67, 0x70, 0x41, 0x10, 0xea, 0x2a, 0xa4, 0x48, 0x93, 0xb8, 0x5c, 0x76, 0xbb, + 0x59, 0xb4, 0x0a, 0x90, 0x85, 0x0d, 0x4f, 0xf5, 0x60, 0x09, 0xc7, 0x70, 0x93, 0x56, 0x75, 0x93, + 0xba, 0xdc, 0x33, 0x4c, 0xae, 0x37, 0x89, 0xc7, 0x1c, 0xea, 0xa6, 0xe7, 0xd0, 0xce, 0x2b, 0xf9, + 0xbe, 0xaf, 0x30, 0x7e, 0xeb, 0x45, 0x7c, 0x49, 0xc2, 0x1f, 0x09, 0xb4, 0xb6, 0x58, 0xef, 0xbd, + 0x90, 0x4b, 0xc3, 0x42, 0x67, 0x3d, 0x86, 0xa5, 0x7a, 0x17, 0xe7, 0xb4, 0x1b, 0x15, 0xea, 0xf1, + 0x07, 0xbc, 0x61, 0x1e, 0x94, 0x4a, 0xbb, 0x9f, 0xf6, 0x1f, 0xab, 0xfb, 0x0d, 0x30, 0xcb, 0x38, + 0x21, 0x75, 0x6a, 0x0b, 0xb7, 0x6a, 0xe2, 0x4c, 0xad, 0x91, 0xbd, 0x86, 0x6b, 0xa1, 0x08, 0xb1, + 0x5e, 0x69, 0x37, 0x51, 0xdd, 0xbe, 0xb6, 0x70, 0xe6, 0x12, 0x6d, 0x65, 0x5a, 0x70, 0xe5, 0xd0, + 0x25, 0x67, 0xd5, 0xae, 0x7d, 0x43, 0xbb, 0x7e, 0x52, 0xd0, 0x6a, 0xf1, 0x32, 0xa0, 0x19, 0x9c, + 0xdc, 0x15, 0xef, 0x59, 0xb7, 0xfc, 0xd7, 0xac, 0x3e, 0xd6, 0x99, 0xa0, 0x76, 0xbf, 0x96, 0xa1, + 0x95, 0xa9, 0x62, 0x61, 0x40, 0x06, 0xa3, 0xdb, 0x6c, 0xc5, 0xfc, 0x23, 0xa7, 0xcd, 0x79, 0x11, + 0x7e, 0xee, 0x2c, 0x9c, 0x39, 0xd2, 0xb6, 0xc0, 0x83, 0xe2, 0x6f, 0x53, 0x30, 0x5e, 0x66, 0xb6, + 0xfa, 0x8d, 0x02, 0x6a, 0x8f, 0xe1, 0xf1, 0xf2, 0x00, 0x63, 0x7a, 0xce, 0x5f, 0x99, 0x77, 0x47, + 0x41, 0x85, 0x53, 0xdb, 0xd7, 0x0a, 0x9c, 0xec, 0x7e, 0x7d, 0xba, 0x34, 0x94, 0xce, 0x4e, 0x50, + 0xe6, 0xfa, 0x08, 0xa0, 0xd0, 0x8e, 0xef, 0x15, 0x38, 0xd5, 0x7b, 0x38, 0x7c, 0x7b, 0xb0, 0xda, + 0x9e, 0xc0, 0xcc, 0xfb, 0x23, 0x02, 0x43, 0x9b, 0x9a, 0x30, 0xd5, 0x31, 0x23, 0xe6, 0x07, 0x2b, + 0x6c, 0x97, 0xcf, 0x5c, 0x39, 0x9e, 0x7c, 0x74, 0xdf, 0x70, 0xaa, 0x1b, 0x72, 0xdf, 0x40, 0x7e, + 0xd8, 0x7d, 0xa3, 0xed, 0x50, 0x65, 0x90, 0x6a, 0x6f, 0x85, 0x17, 0x86, 0x53, 0x23, 0xc5, 0x33, + 0x6f, 0x1d, 0x4b, 0x3c, 0xdc, 0xf4, 0x73, 0x98, 0x89, 0xbc, 0x7d, 0x6e, 0x0e, 0x56, 0xd4, 0x89, + 0xc8, 0x5c, 0x3d, 0x2e, 0x22, 0xdc, 0xfd, 0x2b, 0x05, 0xe6, 0xba, 0xbe, 0x56, 0x14, 0x07, 0xab, + 0x8b, 0x62, 0x32, 0xd7, 0x8e, 0x8f, 0x09, 0x8d, 0xf8, 0x02, 0x66, 0xa3, 0xdf, 0x78, 0x2e, 0x0e, + 0x56, 0x17, 0x81, 0x64, 0xde, 0x39, 0x36, 0xa4, 0x3d, 0x07, 0x91, 0xce, 0x32, 0x44, 0x0e, 0x3a, + 0x11, 0xc3, 0xe4, 0xa0, 0x77, 0xbf, 0xc1, 0x2b, 0xa8, 0xbb, 0xdb, 0x5c, 0x1a, 0xe6, 0xf4, 0x46, + 0x40, 0xc3, 0x5c, 0x41, 0x47, 0xf6, 0x17, 0xf5, 0x47, 0x05, 0x16, 0x8e, 0x68, 0x2e, 0x57, 0x87, + 0xcd, 0x6e, 0x14, 0x99, 0xf9, 0x60, 0x54, 0x64, 0x60, 0xd6, 0xd6, 0xc7, 0x4f, 0x9e, 0x67, 0x95, + 0xa7, 0xcf, 0xb3, 0xca, 0x5f, 0xcf, 0xb3, 0xca, 0x77, 0x2f, 0xb2, 0x63, 0x4f, 0x5f, 0x64, 0xc7, + 0xfe, 0x78, 0x91, 0x1d, 0xfb, 0xec, 0x62, 0xdb, 0xd8, 0xe7, 0xeb, 0xbe, 0x10, 0xf9, 0xbe, 0xd8, + 0xea, 0xf8, 0xec, 0xea, 0x4f, 0x81, 0x95, 0x38, 0x4e, 0x1e, 0x97, 0xfe, 0x0d, 0x00, 0x00, 0xff, + 0xff, 0x41, 0x12, 0xd3, 0x41, 0xa4, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2747,6 +2759,13 @@ func (m *MsgVoteInbound) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ProtocolContractVersion != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ProtocolContractVersion)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } if m.EventIndex != 0 { i = encodeVarintTx(dAtA, i, uint64(m.EventIndex)) i-- @@ -3427,6 +3446,9 @@ func (m *MsgVoteInbound) Size() (n int) { if m.EventIndex != 0 { n += 1 + sovTx(uint64(m.EventIndex)) } + if m.ProtocolContractVersion != 0 { + n += 2 + sovTx(uint64(m.ProtocolContractVersion)) + } return n } @@ -5997,6 +6019,25 @@ func (m *MsgVoteInbound) Unmarshal(dAtA []byte) error { break } } + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProtocolContractVersion", wireType) + } + m.ProtocolContractVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProtocolContractVersion |= ProtocolContractVersion(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/fungible/keeper/deposits.go b/x/fungible/keeper/deposits.go index cc3a55f856..20dfbad327 100644 --- a/x/fungible/keeper/deposits.go +++ b/x/fungible/keeper/deposits.go @@ -25,18 +25,18 @@ func (k Keeper) DepositCoinsToFungibleModule(ctx sdk.Context, amount *big.Int) e // ZRC20DepositAndCallContract deposits ZRC20 to the EVM account and calls the contract // returns [txResponse, isContractCall, error] -// isContractCall is true if the receiver is a contract and a contract call was made func (k Keeper) ZRC20DepositAndCallContract( ctx sdk.Context, from []byte, to eth.Address, amount *big.Int, senderChainID int64, - data []byte, + message []byte, coinType coin.CoinType, asset string, + protocolContractVersion crosschaintypes.ProtocolContractVersion, ) (*evmtypes.MsgEthereumTxResponse, bool, error) { - var ZRC20Contract eth.Address + var zrc20Contract eth.Address var foreignCoin types.ForeignCoins var found bool @@ -52,7 +52,7 @@ func (k Keeper) ZRC20DepositAndCallContract( return nil, false, crosschaintypes.ErrForeignCoinNotFound } } - ZRC20Contract = eth.HexToAddress(foreignCoin.Zrc20ContractAddress) + zrc20Contract = eth.HexToAddress(foreignCoin.Zrc20ContractAddress) // check if foreign coin is paused if foreignCoin.Paused { @@ -62,7 +62,7 @@ func (k Keeper) ZRC20DepositAndCallContract( // check foreign coins cap if it has a cap if !foreignCoin.LiquidityCap.IsNil() && !foreignCoin.LiquidityCap.IsZero() { liquidityCap := foreignCoin.LiquidityCap.BigInt() - totalSupply, err := k.TotalSupplyZRC4(ctx, ZRC20Contract) + totalSupply, err := k.TotalSupplyZRC4(ctx, zrc20Contract) if err != nil { return nil, false, err } @@ -72,6 +72,11 @@ func (k Keeper) ZRC20DepositAndCallContract( } } + // handle the deposit for protocol contract version 2 + if protocolContractVersion == crosschaintypes.ProtocolContractVersion_V2 { + return k.ProcessV2Deposit(ctx, zrc20Contract, to, amount, message) + } + // check if the receiver is a contract // if it is, then the hook onCrossChainCall() will be called // if not, the zrc20 are simply transferred to the receiver @@ -82,15 +87,15 @@ func (k Keeper) ZRC20DepositAndCallContract( Sender: eth.Address{}, ChainID: big.NewInt(senderChainID), } - res, err := k.DepositZRC20AndCallContract(ctx, context, ZRC20Contract, to, amount, data) + res, err := k.DepositZRC20AndCallContract(ctx, context, zrc20Contract, to, amount, message) return res, true, err } // if the account is a EOC, no contract call can be made with the data - if len(data) > 0 { + if len(message) > 0 { return nil, false, types.ErrCallNonContract } - res, err := k.DepositZRC20(ctx, ZRC20Contract, to, amount) + res, err := k.DepositZRC20(ctx, zrc20Contract, to, amount) return res, false, err } diff --git a/x/fungible/keeper/deposits_test.go b/x/fungible/keeper/deposits_test.go index e394053edd..2f715bad30 100644 --- a/x/fungible/keeper/deposits_test.go +++ b/x/fungible/keeper/deposits_test.go @@ -44,6 +44,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_Gas, sample.EthAddress().String(), + crosschaintypes.ProtocolContractVersion_V1, ) require.NoError(t, err) require.False(t, contractCall) @@ -76,6 +77,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_ERC20, assetAddress, + crosschaintypes.ProtocolContractVersion_V1, ) require.NoError(t, err) require.False(t, contractCall) @@ -108,6 +110,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte("DEADBEEF"), coin.CoinType_ERC20, assetAddress, + crosschaintypes.ProtocolContractVersion_V1, ) require.ErrorIs(t, err, types.ErrCallNonContract) }) @@ -149,6 +152,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_Gas, sample.EthAddress().String(), + crosschaintypes.ProtocolContractVersion_V1, ) require.NoError(t, err) require.False(t, contractCall) @@ -186,6 +190,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_Gas, sample.EthAddress().String(), + crosschaintypes.ProtocolContractVersion_V1, ) require.ErrorIs(t, err, types.ErrPausedZRC20) }) @@ -227,6 +232,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_Gas, sample.EthAddress().String(), + crosschaintypes.ProtocolContractVersion_V1, ) require.ErrorIs(t, err, types.ErrForeignCoinCapReached) }) @@ -253,6 +259,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_Gas, sample.EthAddress().String(), + crosschaintypes.ProtocolContractVersion_V1, ) require.ErrorIs(t, err, crosschaintypes.ErrGasCoinNotFound) }) @@ -279,6 +286,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_ERC20, assetAddress, + crosschaintypes.ProtocolContractVersion_V1, ) require.ErrorIs(t, err, crosschaintypes.ErrForeignCoinNotFound) }) @@ -309,6 +317,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_Gas, sample.EthAddress().String(), + crosschaintypes.ProtocolContractVersion_V1, ) require.NoError(t, err) require.True(t, contractCall) @@ -347,6 +356,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { []byte{}, coin.CoinType_Gas, sample.EthAddress().String(), + crosschaintypes.ProtocolContractVersion_V1, ) require.Error(t, err) require.True(t, contractCall) @@ -355,6 +365,39 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { require.NoError(t, err) require.EqualValues(t, int64(0), balance.Int64()) }) + + t.Run("can deposit using V2", func(t *testing.T) { + // setup gas coin + k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) + _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + chainList := chains.DefaultChainsList() + chain := chainList[0].ChainId + + // deploy the system contracts + deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", "foobar") + + // deposit + to := sample.EthAddress() + _, contractCall, err := k.ZRC20DepositAndCallContract( + ctx, + sample.EthAddress().Bytes(), + to, + big.NewInt(42), + chain, + []byte{}, + coin.CoinType_Gas, + sample.EthAddress().String(), + crosschaintypes.ProtocolContractVersion_V2, + ) + require.NoError(t, err) + require.False(t, contractCall) + + balance, err := k.BalanceOfZRC4(ctx, zrc20, to) + require.NoError(t, err) + require.Equal(t, big.NewInt(42), balance) + }) } func TestKeeper_DepositCoinZeta(t *testing.T) { diff --git a/x/fungible/keeper/v2_deposits.go b/x/fungible/keeper/v2_deposits.go new file mode 100644 index 0000000000..158442681e --- /dev/null +++ b/x/fungible/keeper/v2_deposits.go @@ -0,0 +1,28 @@ +package keeper + +import ( + "errors" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +// ProcessV2Deposit handles a deposit from an inbound tx with protocol version 2 +// returns [txResponse, isContractCall, error] +// isContractCall is true if the message is non empty +func (k Keeper) ProcessV2Deposit( + ctx sdk.Context, + zrc20Addr ethcommon.Address, + to ethcommon.Address, + amount *big.Int, + message []byte, +) (*evmtypes.MsgEthereumTxResponse, bool, error) { + if len(message) == 0 { + // simple deposit + res, err := k.DepositZRC20(ctx, zrc20Addr, to, amount) + return res, false, err + } + return nil, true, errors.New("not implemented") +} diff --git a/x/fungible/keeper/v2_deposits_test.go b/x/fungible/keeper/v2_deposits_test.go new file mode 100644 index 0000000000..9617f06646 --- /dev/null +++ b/x/fungible/keeper/v2_deposits_test.go @@ -0,0 +1,56 @@ +package keeper_test + +import ( + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/fungible/types" + "math/big" + "testing" +) + +func TestKeeper_ProcessV2Deposit(t *testing.T) { + t.Run("should process no-call deposit", func(t *testing.T) { + // ARRANGE + k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) + _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + chainID := chains.DefaultChainsList()[0].ChainId + receiver := sample.EthAddress() + + // deploy the system contracts + deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + // ACT + _, contractCall, err := k.ProcessV2Deposit(ctx, zrc20, receiver, big.NewInt(42), []byte{}) + + // ASSERT + require.NoError(t, err) + require.False(t, contractCall) + + balance, err := k.BalanceOfZRC4(ctx, zrc20, receiver) + require.NoError(t, err) + require.Equal(t, big.NewInt(42), balance) + }) + + t.Run("should fail if not recognized action", func(t *testing.T) { + // ARRANGE + k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) + _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + chainID := chains.DefaultChainsList()[0].ChainId + receiver := sample.EthAddress() + + // deploy the system contracts + deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + // ACT + _, _, err := k.ProcessV2Deposit(ctx, zrc20, receiver, big.NewInt(42), sample.Bytes()) + + // ASSERT + require.ErrorContains(t, err, "not implemented") + }) +} diff --git a/x/observer/types/chain_params.go b/x/observer/types/chain_params.go index b2cbb63c32..6ea4fc907e 100644 --- a/x/observer/types/chain_params.go +++ b/x/observer/types/chain_params.go @@ -349,6 +349,7 @@ func GetDefaultGoerliLocalnetChainParams() *ChainParams { BallotThreshold: DefaultBallotThreshold, MinObserverDelegation: DefaultMinObserverDelegation, IsSupported: false, + GatewayAddress: "0xF0deebCB0E9C829519C4baa794c5445171973826", } } func GetDefaultZetaPrivnetChainParams() *ChainParams { diff --git a/x/observer/types/chain_params_test.go b/x/observer/types/chain_params_test.go index dff1311a9c..64c27d5757 100644 --- a/x/observer/types/chain_params_test.go +++ b/x/observer/types/chain_params_test.go @@ -68,6 +68,7 @@ func (s *UpdateChainParamsSuite) SetupTest() { BallotThreshold: types.DefaultBallotThreshold, MinObserverDelegation: types.DefaultMinObserverDelegation, IsSupported: false, + GatewayAddress: "0xF0deebCB0E9C829519C4baa794c5445171973826", } s.btcParams = &types.ChainParams{ ConfirmationCount: 1, diff --git a/zetaclient/chains/evm/constant.go b/zetaclient/chains/evm/constant.go index b754d57f30..696eff6340 100644 --- a/zetaclient/chains/evm/constant.go +++ b/zetaclient/chains/evm/constant.go @@ -39,4 +39,10 @@ const ( // [signature, asset] // https://github.com/zeta-chain/protocol-contracts/blob/d65814debf17648a6c67d757ba03646415842790/contracts/evm/ERC20Custody.sol#L42 TopicsDeposited = 2 + + // V2 contracts + + // TopicsGatewayDeposit is the number of topics for a gateway deposit event + // [signature, sender, receiver] + TopicsGatewayDeposit = 3 ) diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index f862c57bb6..9085e3ed6e 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -217,6 +217,16 @@ func (ob *Observer) ObserveInbound(ctx context.Context, sampledLogger zerolog.Lo return errors.Wrap(err, "unable to observe TSSReceive") } + // query the gateway logs + // TODO: refactor in a more declarative design. Example: storing the list of contract and events to listen in an array + // https://github.com/zeta-chain/node/issues/2493 + lastScannedGateway, err := ob.ObserveGateway(ctx, startBlock, toBlock) + if err != nil { + ob.Logger().Inbound.Error(). + Err(err). + Msgf("ObserveInbound: error observing events from Gateway contract") + } + // note: using lowest height for all 3 events is not perfect, but it's simple and good enough lastScannedLowest := lastScannedZetaSent if lastScannedDeposited < lastScannedLowest { @@ -225,6 +235,9 @@ func (ob *Observer) ObserveInbound(ctx context.Context, sampledLogger zerolog.Lo if lastScannedTssRecvd < lastScannedLowest { lastScannedLowest = lastScannedTssRecvd } + if lastScannedGateway < lastScannedLowest { + lastScannedLowest = lastScannedGateway + } // update last scanned block height for all 3 events (ZetaSent, Deposited, TssRecvd), ignore db error if lastScannedLowest > lastScanned { diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index 9051b2d6e5..e5873dc88e 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -18,6 +18,7 @@ import ( "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zeta.non-eth.sol" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.eth.sol" "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.non-eth.sol" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" "github.com/zeta-chain/zetacore/pkg/bg" "github.com/zeta-chain/zetacore/pkg/proofs" @@ -155,6 +156,13 @@ func (ob *Observer) GetERC20CustodyContract() (ethcommon.Address, *erc20custody. return addr, contract, err } +// GetGatewayContract returns the gateway contract address and binder +func (ob *Observer) GetGatewayContract() (ethcommon.Address, *gatewayevm.GatewayEVM, error) { + addr := ethcommon.HexToAddress(ob.GetChainParams().GatewayAddress) + contract, err := gatewayevm.NewGatewayEVM(addr, ob.evmClient) + return addr, contract, err +} + // FetchConnectorContractEth returns the Eth connector address and binder // TODO(revamp): move this to a contract package func FetchConnectorContractEth( diff --git a/zetaclient/chains/evm/observer/v2_inbound.go b/zetaclient/chains/evm/observer/v2_inbound.go new file mode 100644 index 0000000000..697af5096d --- /dev/null +++ b/zetaclient/chains/evm/observer/v2_inbound.go @@ -0,0 +1,180 @@ +package observer + +import ( + "bytes" + "context" + "encoding/hex" + "sort" + + "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" + + "github.com/zeta-chain/zetacore/pkg/coin" + "github.com/zeta-chain/zetacore/pkg/constant" + "github.com/zeta-chain/zetacore/x/crosschain/types" + "github.com/zeta-chain/zetacore/zetaclient/chains/evm" + "github.com/zeta-chain/zetacore/zetaclient/compliance" + "github.com/zeta-chain/zetacore/zetaclient/config" + "github.com/zeta-chain/zetacore/zetaclient/metrics" + "github.com/zeta-chain/zetacore/zetaclient/zetacore" +) + +// ObserveGateway queries the gateway contract for deposit/call events +// returns the last block successfully scanned +func (ob *Observer) ObserveGateway(ctx context.Context, startBlock, toBlock uint64) (uint64, error) { + // filter ERC20CustodyDeposited logs + gatewayAddr, gatewayContract, err := ob.GetGatewayContract() + if err != nil { + // lastScanned is startBlock - 1 + return startBlock - 1, errors.Wrap(err, "can't get gateway contract") + } + + // get iterator for the events for the block range + eventIterator, err := gatewayContract.FilterDeposit(&bind.FilterOpts{ + Start: startBlock, + End: &toBlock, + Context: ctx, + }, []ethcommon.Address{}, []ethcommon.Address{}) + if err != nil { + return startBlock - 1, errors.Wrapf( + err, + "error filtering deposits from block %d to %d for chain %d", + startBlock, + toBlock, + ob.Chain().ChainId, + ) + } + + // parse and validate events + events := ob.parseAndValidateDepositEvents(eventIterator, gatewayAddr) + + // increment prom counter + metrics.GetFilterLogsPerChain.WithLabelValues(ob.Chain().Name).Inc() + + // post to zetacore + lastScanned := uint64(0) + for _, event := range events { + // remember which block we are scanning (there could be multiple events in the same block) + if event.Raw.BlockNumber > lastScanned { + lastScanned = event.Raw.BlockNumber + } + + // check if the event is processable + if !ob.checkEventProcessability(event) { + continue + } + + msg := ob.newDepositInboundVote(event) + + ob.Logger().Inbound.Info(). + Msgf("ObserveGateway: Deposit inbound detected on chain %d tx %s block %d from %s value %s message %s", + ob.Chain(). + ChainId, event.Raw.TxHash.Hex(), event.Raw.BlockNumber, event.Sender.Hex(), event.Amount.String(), hex.EncodeToString(event.Payload)) + + _, err = ob.PostVoteInbound(ctx, &msg, zetacore.PostVoteInboundExecutionGasLimit) + if err != nil { + // decrement the last scanned block so we have to re-scan from this block next time + return lastScanned - 1, errors.Wrap(err, "error posting vote inbound") + } + } + + // successfully processed all events in [startBlock, toBlock] + return toBlock, nil +} + +// parseAndValidateEvents collects and sorts events by block number, tx index, and log index +func (ob *Observer) parseAndValidateDepositEvents( + iterator *gatewayevm.GatewayEVMDepositIterator, + gatewayAddr ethcommon.Address, +) []*gatewayevm.GatewayEVMDeposit { + // collect and sort events by block number, then tx index, then log index (ascending) + events := make([]*gatewayevm.GatewayEVMDeposit, 0) + for iterator.Next() { + events = append(events, iterator.Event) + err := evm.ValidateEvmTxLog(&iterator.Event.Raw, gatewayAddr, "", evm.TopicsGatewayDeposit) + if err == nil { + events = append(events, iterator.Event) + continue + } + ob.Logger().Inbound.Warn(). + Err(err). + Msgf("ObserveGateway: invalid Deposited event in tx %s on chain %d at height %d", + iterator.Event.Raw.TxHash.Hex(), ob.Chain().ChainId, iterator.Event.Raw.BlockNumber) + } + sort.SliceStable(events, func(i, j int) bool { + if events[i].Raw.BlockNumber == events[j].Raw.BlockNumber { + if events[i].Raw.TxIndex == events[j].Raw.TxIndex { + return events[i].Raw.Index < events[j].Raw.Index + } + return events[i].Raw.TxIndex < events[j].Raw.TxIndex + } + return events[i].Raw.BlockNumber < events[j].Raw.BlockNumber + }) + + // filter events from same tx + filtered := make([]*gatewayevm.GatewayEVMDeposit, 0) + guard := make(map[string]bool) + for _, event := range events { + // guard against multiple events in the same tx + if guard[event.Raw.TxHash.Hex()] { + ob.Logger().Inbound.Warn(). + Msgf("ObserveGateway: multiple remote call events detected in same tx %s", event.Raw.TxHash) + continue + } + guard[event.Raw.TxHash.Hex()] = true + filtered = append(filtered, event) + } + + return filtered +} + +// checkEventProcessability checks if the event is processable +func (ob *Observer) checkEventProcessability(event *gatewayevm.GatewayEVMDeposit) bool { + // compliance check + if config.ContainRestrictedAddress(event.Sender.Hex(), event.Receiver.Hex()) { + compliance.PrintComplianceLog( + ob.Logger().Inbound, + ob.Logger().Compliance, + false, + ob.Chain().ChainId, + event.Raw.TxHash.Hex(), + event.Sender.Hex(), + event.Receiver.Hex(), + "Deposit", + ) + return false + } + + // donation check + if bytes.Equal(event.Payload, []byte(constant.DonationMessage)) { + ob.Logger().Inbound.Info(). + Msgf("thank you rich folk for your donation! tx %s chain %d", event.Raw.TxHash.Hex(), ob.Chain().ChainId) + return false + } + + return true +} + +// newDepositInboundVote creates a MsgVoteInbound message for a Deposit event +func (ob *Observer) newDepositInboundVote(event *gatewayevm.GatewayEVMDeposit) types.MsgVoteInbound { + return *types.NewMsgVoteInbound( + ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), + event.Sender.Hex(), + ob.Chain().ChainId, + "", + event.Receiver.Hex(), + ob.ZetacoreClient().Chain().ChainId, + sdkmath.NewUintFromBigInt(event.Amount), + hex.EncodeToString(event.Payload), + event.Raw.TxHash.Hex(), + event.Raw.BlockNumber, + 1_500_000, + coin.CoinType_Gas, + "", + event.Raw.Index, + types.ProtocolContractVersion_V2, + ) +} diff --git a/zetaclient/chains/evm/validation.go b/zetaclient/chains/evm/validation.go index 8c7f9249c5..0f043c9966 100644 --- a/zetaclient/chains/evm/validation.go +++ b/zetaclient/chains/evm/validation.go @@ -14,7 +14,7 @@ import ( // ValidateEvmTxLog checks the basics of an EVM tx log func ValidateEvmTxLog(vLog *ethtypes.Log, wantAddress ethcommon.Address, wantHash string, wantTopics int) error { if vLog.Removed { - return fmt.Errorf("log is removed, chain reorg?") + return fmt.Errorf("log is removed, it might be related to a chain reorganization") } if vLog.Address != wantAddress { return fmt.Errorf("log emitter address mismatch: want %s got %s", wantAddress.Hex(), vLog.Address.Hex()) diff --git a/zetaclient/zetacore/tx.go b/zetaclient/zetacore/tx.go index 90a6b1d136..1122282619 100644 --- a/zetaclient/zetacore/tx.go +++ b/zetaclient/zetacore/tx.go @@ -51,6 +51,7 @@ func GetInboundVoteMessage( coinType, asset, eventIndex, + types.ProtocolContractVersion_V1, ) return msg }