diff --git a/changelog.md b/changelog.md index 18632d0202..bdd9866e84 100644 --- a/changelog.md +++ b/changelog.md @@ -35,6 +35,9 @@ * [1628](https://github.com/zeta-chain/node/pull/1628) optimize return and simplify code +### Refactoring +* [1619](https://github.com/zeta-chain/node/pull/1619) - Add evm fee calculation to tss migration of evm chains + ## Version: v12.0.0 ### Breaking Changes diff --git a/common/gas_limits.go b/common/gas_limits.go new file mode 100644 index 0000000000..bbd1f0a6c5 --- /dev/null +++ b/common/gas_limits.go @@ -0,0 +1,26 @@ +package common + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // EVMSend is the gas limit required to transfer tokens on an EVM based chain + EVMSend = 21000 + // TODO: Move gas limits from zeta-client to this file + // https://github.com/zeta-chain/node/issues/1606 +) + +// MultiplyGasPrice multiplies the median gas price by the given multiplier and returns the truncated value +func MultiplyGasPrice(medianGasPrice sdkmath.Uint, multiplierString string) (sdkmath.Uint, error) { + multiplier, err := sdk.NewDecFromStr(multiplierString) + if err != nil { + return sdkmath.ZeroUint(), err + } + gasPrice, err := sdk.NewDecFromStr(medianGasPrice.String()) + if err != nil { + return sdkmath.ZeroUint(), err + } + return sdkmath.NewUintFromString(gasPrice.Mul(multiplier).TruncateInt().String()), nil +} diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index 081e2d6490..a552d0feb4 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -116,6 +116,19 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s } cctx.InboundTxParams.Sender = ethAddressOld.String() cctx.GetCurrentOutTxParam().Receiver = ethAddressNew.String() + // Tss migration is a send transaction, so the gas limit is set to 21000 + cctx.GetCurrentOutTxParam().OutboundTxGasLimit = common.EVMSend + // Multiple current gas price with standard multiplier to add some buffer + multipliedGasPrice, err := common.MultiplyGasPrice(medianGasPrice, types.TssMigrationGasMultiplierEVM) + if err != nil { + return err + } + cctx.GetCurrentOutTxParam().OutboundTxGasPrice = multipliedGasPrice.String() + evmFee := sdkmath.NewUint(cctx.GetCurrentOutTxParam().OutboundTxGasLimit).Mul(multipliedGasPrice) + if evmFee.GT(amount) { + return errorsmod.Wrap(types.ErrInsufficientFundsTssMigration, fmt.Sprintf("insufficient funds to pay for gas fee, amount: %s, gas fee: %s, chainid: %d", amount.String(), evmFee.String(), chainID)) + } + cctx.GetCurrentOutTxParam().Amount = amount.Sub(evmFee) } // Set the sender and receiver addresses for Bitcoin chain if common.IsBitcoinChain(chainID) { diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go b/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go index 436a6b69c9..4d909abdf0 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go @@ -6,7 +6,7 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" @@ -15,6 +15,33 @@ import ( observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) +func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { + t.Run("test gas price multiplier", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + chain := getValidEthChain(t) + amount := sdkmath.NewUintFromString("10000000000000000000") + indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + gp, found := k.GetMedianGasPriceInUint(ctx, chain.ChainId) + require.True(t, found) + _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ + Creator: admin, + ChainId: chain.ChainId, + Amount: amount, + }) + require.NoError(t, err) + hash := crypto.Keccak256Hash([]byte(indexString)) + index := hash.Hex() + cctx, found := k.GetCrossChainTx(ctx, index) + require.True(t, found) + multipliedValue, err := common.MultiplyGasPrice(gp, crosschaintypes.TssMigrationGasMultiplierEVM) + require.NoError(t, err) + require.Equal(t, multipliedValue.String(), cctx.GetCurrentOutTxParam().OutboundTxGasPrice) + + }) +} func TestMsgServer_MigrateTssFunds(t *testing.T) { t.Run("successfully create tss migration cctx", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) @@ -22,18 +49,40 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) chain := getValidEthChain(t) - amount := sdkmath.NewUint(100) + amount := sdkmath.NewUintFromString("10000000000000000000") + indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) + _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ + Creator: admin, + ChainId: chain.ChainId, + Amount: amount, + }) + require.NoError(t, err) + hash := crypto.Keccak256Hash([]byte(indexString)) + index := hash.Hex() + cctx, found := k.GetCrossChainTx(ctx, index) + require.True(t, found) + feeCalculated := sdk.NewUint(cctx.GetCurrentOutTxParam().OutboundTxGasLimit). + Mul(sdkmath.NewUintFromString(cctx.GetCurrentOutTxParam().OutboundTxGasPrice)) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount.String(), amount.Sub(feeCalculated).String()) + }) + t.Run("not enough funds in tss address for migration", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin) + msgServer := keeper.NewMsgServerImpl(*k) + chain := getValidEthChain(t) + amount := sdkmath.NewUintFromString("100") indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, ChainId: chain.ChainId, Amount: amount, }) - assert.NoError(t, err) + require.ErrorContains(t, err, crosschaintypes.ErrCannotMigrateTssFunds.Error()) hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() _, found := k.GetCrossChainTx(ctx, index) - assert.True(t, found) + require.False(t, found) }) t.Run("unable to migrate funds if new TSS is not created ", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) @@ -41,19 +90,18 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) chain := getValidEthChain(t) - amount := sdkmath.NewUint(100) + amount := sdkmath.NewUintFromString("10000000000000000000") indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, false, true) _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, ChainId: chain.ChainId, Amount: amount, }) - assert.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) - assert.ErrorContains(t, err, "no new tss address has been generated") + require.ErrorContains(t, err, "no new tss address has been generated") hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() _, found := k.GetCrossChainTx(ctx, index) - assert.False(t, found) + require.False(t, found) }) t.Run("unable to migrate funds when nonce low does not match nonce high", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) @@ -61,7 +109,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) chain := getValidEthChain(t) - amount := sdkmath.NewUint(100) + amount := sdkmath.NewUintFromString("10000000000000000000") indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) k.GetObserverKeeper().SetPendingNonces(ctx, observertypes.PendingNonces{ NonceLow: 1, @@ -74,12 +122,12 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { ChainId: chain.ChainId, Amount: amount, }) - assert.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) - assert.ErrorContains(t, err, "cannot migrate funds when there are pending nonces") + require.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) + require.ErrorContains(t, err, "cannot migrate funds when there are pending nonces") hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() _, found := k.GetCrossChainTx(ctx, index) - assert.False(t, found) + require.False(t, found) }) t.Run("unable to migrate funds when a pending cctx is presnt in migration info", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) @@ -87,7 +135,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) chain := getValidEthChain(t) - amount := sdkmath.NewUint(100) + amount := sdkmath.NewUintFromString("10000000000000000000") indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) k.GetObserverKeeper().SetPendingNonces(ctx, observertypes.PendingNonces{ NonceLow: 1, @@ -107,14 +155,14 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { ChainId: chain.ChainId, Amount: amount, }) - assert.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) - assert.ErrorContains(t, err, "cannot migrate funds while there are pending migrations") + require.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) + require.ErrorContains(t, err, "cannot migrate funds while there are pending migrations") hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() _, found := k.GetCrossChainTx(ctx, index) - assert.False(t, found) + require.False(t, found) _, found = k.GetCrossChainTx(ctx, existingCctx.Index) - assert.True(t, found) + require.True(t, found) }) t.Run("unable to migrate funds if current TSS is not present in TSSHistory and no new TSS has been generated", func(t *testing.T) { @@ -123,10 +171,10 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { setAdminPolicies(ctx, zk, admin) msgServer := keeper.NewMsgServerImpl(*k) chain := getValidEthChain(t) - amount := sdkmath.NewUint(100) + amount := sdkmath.NewUintFromString("10000000000000000000") indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, false, false) currentTss, found := k.GetObserverKeeper().GetTSS(ctx) - assert.True(t, found) + require.True(t, found) newTss := sample.Tss() newTss.FinalizedZetaHeight = currentTss.FinalizedZetaHeight - 10 newTss.KeyGenZetaHeight = currentTss.KeyGenZetaHeight - 10 @@ -136,12 +184,12 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { ChainId: chain.ChainId, Amount: amount, }) - assert.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) - assert.ErrorContains(t, err, "current tss is the latest") + require.ErrorIs(t, err, crosschaintypes.ErrCannotMigrateTssFunds) + require.ErrorContains(t, err, "current tss is the latest") hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() _, found = k.GetCrossChainTx(ctx, index) - assert.False(t, found) + require.False(t, found) }) } func setupTssMigrationParams( @@ -192,7 +240,7 @@ func setupTssMigrationParams( ChainId: chain.ChainId, Signers: nil, BlockNums: nil, - Prices: []uint64{1, 1, 1}, + Prices: []uint64{100000, 100000, 100000}, MedianIndex: 1, }) k.GetObserverKeeper().SetChainNonces(ctx, observertypes.ChainNonces{ diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index 8dc589e878..12bbd4ad84 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -43,4 +43,6 @@ var ( ErrReceiverIsEmpty = errorsmod.Register(ModuleName, 1142, "receiver is empty") ErrUnsupportedStatus = errorsmod.Register(ModuleName, 1143, "unsupported status") ErrObservedTxAlreadyFinalized = errorsmod.Register(ModuleName, 1144, "observed tx already finalized") + + ErrInsufficientFundsTssMigration = errorsmod.Register(ModuleName, 1145, "insufficient funds for TSS migration") ) diff --git a/x/crosschain/types/keys.go b/x/crosschain/types/keys.go index 8777d8df0c..4adac4d73f 100644 --- a/x/crosschain/types/keys.go +++ b/x/crosschain/types/keys.go @@ -25,6 +25,8 @@ const ( MemStoreKey = "mem_metacore" ProtocolFee = 2000000000000000000 + //TssMigrationGasMultiplierEVM is multiplied to the median gas price to get the gas price for the tss migration . This is done to avoid the tss migration tx getting stuck in the mempool + TssMigrationGasMultiplierEVM = "2.5" ) func GetProtocolFee() sdk.Uint { diff --git a/zetaclient/evm_signer.go b/zetaclient/evm_signer.go index c961a627e0..204ff75cc7 100644 --- a/zetaclient/evm_signer.go +++ b/zetaclient/evm_signer.go @@ -294,7 +294,7 @@ func (signer *EVMSigner) SignCommandTx( return tx, nil } if cmd == common.CmdMigrateTssFunds { - tx := ethtypes.NewTransaction(outboundParams.OutboundTxTssNonce, to, outboundParams.Amount.BigInt(), 21000, gasPrice, nil) + tx := ethtypes.NewTransaction(outboundParams.OutboundTxTssNonce, to, outboundParams.Amount.BigInt(), outboundParams.OutboundTxGasLimit, gasPrice, nil) hashBytes := signer.ethSigner.Hash(tx).Bytes() sig, err := signer.tssSigner.Sign(hashBytes, height, outboundParams.OutboundTxTssNonce, signer.chain, "") if err != nil { @@ -318,7 +318,7 @@ func (signer *EVMSigner) SignCommandTx( } func (signer *EVMSigner) TryProcessOutTx( - send *types.CrossChainTx, + cctx *types.CrossChainTx, outTxMan *OutTxProcessorManager, outTxID string, chainclient ChainClient, @@ -327,10 +327,10 @@ func (signer *EVMSigner) TryProcessOutTx( ) { logger := signer.logger.With(). Str("outTxID", outTxID). - Str("SendHash", send.Index). + Str("SendHash", cctx.Index). Logger() logger.Info().Msgf("start processing outTxID %s", outTxID) - logger.Info().Msgf("EVM Chain TryProcessOutTx: %s, value %d to %s", send.Index, send.GetCurrentOutTxParam().Amount.BigInt(), send.GetCurrentOutTxParam().Receiver) + logger.Info().Msgf("EVM Chain TryProcessOutTx: %s, value %d to %s", cctx.Index, cctx.GetCurrentOutTxParam().Amount.BigInt(), cctx.GetCurrentOutTxParam().Receiver) defer func() { outTxMan.EndTryProcess(outTxID) @@ -339,23 +339,23 @@ func (signer *EVMSigner) TryProcessOutTx( var to ethcommon.Address var toChain *common.Chain - if send.CctxStatus.Status == types.CctxStatus_PendingRevert { - to = ethcommon.HexToAddress(send.InboundTxParams.Sender) - toChain = common.GetChainFromChainID(send.InboundTxParams.SenderChainId) + if cctx.CctxStatus.Status == types.CctxStatus_PendingRevert { + to = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) + toChain = common.GetChainFromChainID(cctx.InboundTxParams.SenderChainId) if toChain == nil { - logger.Error().Msgf("Unknown chain: %d", send.InboundTxParams.SenderChainId) + logger.Error().Msgf("Unknown chain: %d", cctx.InboundTxParams.SenderChainId) return } logger.Info().Msgf("Abort: reverting inbound") - } else if send.CctxStatus.Status == types.CctxStatus_PendingOutbound { - to = ethcommon.HexToAddress(send.GetCurrentOutTxParam().Receiver) - toChain = common.GetChainFromChainID(send.GetCurrentOutTxParam().ReceiverChainId) + } else if cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound { + to = ethcommon.HexToAddress(cctx.GetCurrentOutTxParam().Receiver) + toChain = common.GetChainFromChainID(cctx.GetCurrentOutTxParam().ReceiverChainId) if toChain == nil { - logger.Error().Msgf("Unknown chain: %d", send.GetCurrentOutTxParam().ReceiverChainId) + logger.Error().Msgf("Unknown chain: %d", cctx.GetCurrentOutTxParam().ReceiverChainId) return } } else { - logger.Info().Msgf("Transaction doesn't need to be processed status: %d", send.CctxStatus.Status) + logger.Info().Msgf("Transaction doesn't need to be processed status: %d", cctx.CctxStatus.Status) return } evmClient, ok := chainclient.(*EVMChainClient) @@ -365,8 +365,8 @@ func (signer *EVMSigner) TryProcessOutTx( } // Early return if the cctx is already processed - nonce := send.GetCurrentOutTxParam().OutboundTxTssNonce - included, confirmed, err := evmClient.IsSendOutTxProcessed(send.Index, nonce, send.GetCurrentOutTxParam().CoinType, logger) + nonce := cctx.GetCurrentOutTxParam().OutboundTxTssNonce + included, confirmed, err := evmClient.IsSendOutTxProcessed(cctx.Index, nonce, cctx.GetCurrentOutTxParam().CoinType, logger) if err != nil { logger.Error().Err(err).Msg("IsSendOutTxProcessed failed") } @@ -376,27 +376,27 @@ func (signer *EVMSigner) TryProcessOutTx( } var message []byte - if send.GetCurrentOutTxParam().CoinType != common.CoinType_Cmd { - message, err = base64.StdEncoding.DecodeString(send.RelayedMessage) + if cctx.GetCurrentOutTxParam().CoinType != common.CoinType_Cmd { + message, err = base64.StdEncoding.DecodeString(cctx.RelayedMessage) if err != nil { - logger.Err(err).Msgf("decode CCTX.Message %s error", send.RelayedMessage) + logger.Err(err).Msgf("decode CCTX.Message %s error", cctx.RelayedMessage) } } - gasLimit := send.GetCurrentOutTxParam().OutboundTxGasLimit + gasLimit := cctx.GetCurrentOutTxParam().OutboundTxGasLimit if gasLimit < 100_000 { gasLimit = 100_000 - logger.Warn().Msgf("gasLimit %d is too low; set to %d", send.GetCurrentOutTxParam().OutboundTxGasLimit, gasLimit) + logger.Warn().Msgf("gasLimit %d is too low; set to %d", cctx.GetCurrentOutTxParam().OutboundTxGasLimit, gasLimit) } if gasLimit > 1_000_000 { gasLimit = 1_000_000 - logger.Warn().Msgf("gasLimit %d is too high; set to %d", send.GetCurrentOutTxParam().OutboundTxGasLimit, gasLimit) + logger.Warn().Msgf("gasLimit %d is too high; set to %d", cctx.GetCurrentOutTxParam().OutboundTxGasLimit, gasLimit) } - logger.Info().Msgf("chain %s minting %d to %s, nonce %d, finalized zeta bn %d", toChain, send.InboundTxParams.Amount, to.Hex(), nonce, send.InboundTxParams.InboundTxFinalizedZetaHeight) - sendHash, err := hex.DecodeString(send.Index[2:]) // remove the leading 0x + logger.Info().Msgf("chain %s minting %d to %s, nonce %d, finalized zeta bn %d", toChain, cctx.InboundTxParams.Amount, to.Hex(), nonce, cctx.InboundTxParams.InboundTxFinalizedZetaHeight) + sendHash, err := hex.DecodeString(cctx.Index[2:]) // remove the leading 0x if err != nil || len(sendHash) != 32 { - logger.Error().Err(err).Msgf("decode CCTX %s error", send.Index) + logger.Error().Err(err).Msgf("decode CCTX %s error", cctx.Index) return } var sendhash [32]byte @@ -408,7 +408,7 @@ func (signer *EVMSigner) TryProcessOutTx( // The code below is a fix for https://github.com/zeta-chain/node/issues/1085 // doesn't close directly the issue because we should determine if we want to keep using SuggestGasPrice if no OutboundTxGasPrice // we should possibly remove it completely and return an error if no OutboundTxGasPrice is provided because it means no fee is processed on ZetaChain - specified, ok := new(big.Int).SetString(send.GetCurrentOutTxParam().OutboundTxGasPrice, 10) + specified, ok := new(big.Int).SetString(cctx.GetCurrentOutTxParam().OutboundTxGasPrice, 10) if !ok { if common.IsEthereumChain(toChain.ChainId) { suggested, err := signer.client.SuggestGasPrice(context.Background()) @@ -418,7 +418,7 @@ func (signer *EVMSigner) TryProcessOutTx( } gasprice = roundUpToNearestGwei(suggested) } else { - logger.Error().Err(err).Msgf("cannot convert gas price %s ", send.GetCurrentOutTxParam().OutboundTxGasPrice) + logger.Error().Err(err).Msgf("cannot convert gas price %s ", cctx.GetCurrentOutTxParam().OutboundTxGasPrice) return } } else { @@ -444,138 +444,138 @@ func (signer *EVMSigner) TryProcessOutTx( var tx *ethtypes.Transaction - if send.GetCurrentOutTxParam().CoinType == common.CoinType_Cmd { // admin command - to := ethcommon.HexToAddress(send.GetCurrentOutTxParam().Receiver) + if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Cmd { // admin command + to := ethcommon.HexToAddress(cctx.GetCurrentOutTxParam().Receiver) if to == (ethcommon.Address{}) { - logger.Error().Msgf("invalid receiver %s", send.GetCurrentOutTxParam().Receiver) + logger.Error().Msgf("invalid receiver %s", cctx.GetCurrentOutTxParam().Receiver) return } - msg := strings.Split(send.RelayedMessage, ":") + msg := strings.Split(cctx.RelayedMessage, ":") if len(msg) != 2 { logger.Error().Msgf("invalid message %s", msg) return } - tx, err = signer.SignCommandTx(msg[0], msg[1], to, send.GetCurrentOutTxParam(), gasLimit, gasprice, height) - } else if send.InboundTxParams.SenderChainId == zetaBridge.ZetaChain().ChainId && send.CctxStatus.Status == types.CctxStatus_PendingOutbound && flags.IsOutboundEnabled { - if send.GetCurrentOutTxParam().CoinType == common.CoinType_Gas { - logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) + tx, err = signer.SignCommandTx(msg[0], msg[1], to, cctx.GetCurrentOutTxParam(), gasLimit, gasprice, height) + } else if cctx.InboundTxParams.SenderChainId == zetaBridge.ZetaChain().ChainId && cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound && flags.IsOutboundEnabled { + if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Gas { + logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignWithdrawTx( to, - send.GetCurrentOutTxParam().Amount.BigInt(), - send.GetCurrentOutTxParam().OutboundTxTssNonce, + cctx.GetCurrentOutTxParam().Amount.BigInt(), + cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice, height, ) } - if send.GetCurrentOutTxParam().CoinType == common.CoinType_ERC20 { - asset := ethcommon.HexToAddress(send.InboundTxParams.Asset) - logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) + if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_ERC20 { + asset := ethcommon.HexToAddress(cctx.InboundTxParams.Asset) + logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignERC20WithdrawTx( to, asset, - send.GetCurrentOutTxParam().Amount.BigInt(), + cctx.GetCurrentOutTxParam().Amount.BigInt(), gasLimit, - send.GetCurrentOutTxParam().OutboundTxTssNonce, + cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice, height, ) } - if send.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { - logger.Info().Msgf("SignOutboundTx: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) + if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + logger.Info().Msgf("SignOutboundTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignOutboundTx( - ethcommon.HexToAddress(send.InboundTxParams.Sender), - big.NewInt(send.InboundTxParams.SenderChainId), + ethcommon.HexToAddress(cctx.InboundTxParams.Sender), + big.NewInt(cctx.InboundTxParams.SenderChainId), to, - send.GetCurrentOutTxParam().Amount.BigInt(), + cctx.GetCurrentOutTxParam().Amount.BigInt(), gasLimit, message, sendhash, - send.GetCurrentOutTxParam().OutboundTxTssNonce, + cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice, height, ) } - } else if send.CctxStatus.Status == types.CctxStatus_PendingRevert && send.OutboundTxParams[0].ReceiverChainId == zetaBridge.ZetaChain().ChainId { - if send.GetCurrentOutTxParam().CoinType == common.CoinType_Gas { - logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) + } else if cctx.CctxStatus.Status == types.CctxStatus_PendingRevert && cctx.OutboundTxParams[0].ReceiverChainId == zetaBridge.ZetaChain().ChainId { + if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Gas { + logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignWithdrawTx( to, - send.GetCurrentOutTxParam().Amount.BigInt(), - send.GetCurrentOutTxParam().OutboundTxTssNonce, + cctx.GetCurrentOutTxParam().Amount.BigInt(), + cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice, height, ) } - if send.GetCurrentOutTxParam().CoinType == common.CoinType_ERC20 { - asset := ethcommon.HexToAddress(send.InboundTxParams.Asset) - logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) + if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_ERC20 { + asset := ethcommon.HexToAddress(cctx.InboundTxParams.Asset) + logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignERC20WithdrawTx( to, asset, - send.GetCurrentOutTxParam().Amount.BigInt(), + cctx.GetCurrentOutTxParam().Amount.BigInt(), gasLimit, - send.GetCurrentOutTxParam().OutboundTxTssNonce, + cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice, height, ) } - } else if send.CctxStatus.Status == types.CctxStatus_PendingRevert { - logger.Info().Msgf("SignRevertTx: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) + } else if cctx.CctxStatus.Status == types.CctxStatus_PendingRevert { + logger.Info().Msgf("SignRevertTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignRevertTx( - ethcommon.HexToAddress(send.InboundTxParams.Sender), - big.NewInt(send.OutboundTxParams[0].ReceiverChainId), + ethcommon.HexToAddress(cctx.InboundTxParams.Sender), + big.NewInt(cctx.OutboundTxParams[0].ReceiverChainId), to.Bytes(), - big.NewInt(send.GetCurrentOutTxParam().ReceiverChainId), - send.GetCurrentOutTxParam().Amount.BigInt(), + big.NewInt(cctx.GetCurrentOutTxParam().ReceiverChainId), + cctx.GetCurrentOutTxParam().Amount.BigInt(), gasLimit, message, sendhash, - send.GetCurrentOutTxParam().OutboundTxTssNonce, + cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice, height, ) - } else if send.CctxStatus.Status == types.CctxStatus_PendingOutbound { - logger.Info().Msgf("SignOutboundTx: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) + } else if cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound { + logger.Info().Msgf("SignOutboundTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignOutboundTx( - ethcommon.HexToAddress(send.InboundTxParams.Sender), - big.NewInt(send.InboundTxParams.SenderChainId), + ethcommon.HexToAddress(cctx.InboundTxParams.Sender), + big.NewInt(cctx.InboundTxParams.SenderChainId), to, - send.GetCurrentOutTxParam().Amount.BigInt(), + cctx.GetCurrentOutTxParam().Amount.BigInt(), gasLimit, message, sendhash, - send.GetCurrentOutTxParam().OutboundTxTssNonce, + cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice, height, ) } if err != nil { - logger.Warn().Err(err).Msgf("signer SignOutbound error: nonce %d chain %d", send.GetCurrentOutTxParam().OutboundTxTssNonce, send.GetCurrentOutTxParam().ReceiverChainId) + logger.Warn().Err(err).Msgf("signer SignOutbound error: nonce %d chain %d", cctx.GetCurrentOutTxParam().OutboundTxTssNonce, cctx.GetCurrentOutTxParam().ReceiverChainId) return } - logger.Info().Msgf("Key-sign success: %d => %s, nonce %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce) + logger.Info().Msgf("Key-sign success: %d => %s, nonce %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) _, err = zetaBridge.GetObserverList() if err != nil { - logger.Warn().Err(err).Msgf("unable to get observer list: chain %d observation %s", send.GetCurrentOutTxParam().OutboundTxTssNonce, observertypes.ObservationType_OutBoundTx.String()) + logger.Warn().Err(err).Msgf("unable to get observer list: chain %d observation %s", cctx.GetCurrentOutTxParam().OutboundTxTssNonce, observertypes.ObservationType_OutBoundTx.String()) } if tx != nil { outTxHash := tx.Hash().Hex() - logger.Info().Msgf("on chain %s nonce %d, outTxHash %s signer %s", signer.chain, send.GetCurrentOutTxParam().OutboundTxTssNonce, outTxHash, myID) + logger.Info().Msgf("on chain %s nonce %d, outTxHash %s signer %s", signer.chain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, outTxHash, myID) //if len(signers) == 0 || myid == signers[send.OutboundTxParams.Broadcaster] || myid == signers[int(send.OutboundTxParams.Broadcaster+1)%len(signers)] { backOff := 1000 * time.Millisecond // retry loop: 1s, 2s, 4s, 8s, 16s in case of RPC error for i := 0; i < 5; i++ { - logger.Info().Msgf("broadcasting tx %s to chain %s: nonce %d, retry %d", outTxHash, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, i) + logger.Info().Msgf("broadcasting tx %s to chain %s: nonce %d, retry %d", outTxHash, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, i) // #nosec G404 randomness is not a security issue here time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond) // FIXME: use backoff err := signer.Broadcast(tx) if err != nil { log.Warn().Err(err).Msgf("OutTx Broadcast error") - retry, report := HandleBroadcastError(err, strconv.FormatUint(send.GetCurrentOutTxParam().OutboundTxTssNonce, 10), toChain.String(), outTxHash) + retry, report := HandleBroadcastError(err, strconv.FormatUint(cctx.GetCurrentOutTxParam().OutboundTxTssNonce, 10), toChain.String(), outTxHash) if report { signer.reportToOutTxTracker(zetaBridge, toChain.ChainId, tx.Nonce(), outTxHash, logger) } @@ -585,7 +585,7 @@ func (signer *EVMSigner) TryProcessOutTx( backOff *= 2 continue } - logger.Info().Msgf("Broadcast success: nonce %d to chain %s outTxHash %s", send.GetCurrentOutTxParam().OutboundTxTssNonce, toChain, outTxHash) + logger.Info().Msgf("Broadcast success: nonce %d to chain %s outTxHash %s", cctx.GetCurrentOutTxParam().OutboundTxTssNonce, toChain, outTxHash) signer.reportToOutTxTracker(zetaBridge, toChain.ChainId, tx.Nonce(), outTxHash, logger) break // successful broadcast; no need to retry }