Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 26 additions & 0 deletions common/gas_limits.go
Original file line number Diff line number Diff line change
@@ -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
}
13 changes: 13 additions & 0 deletions x/crosschain/keeper/msg_server_migrate_tss_funds.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
94 changes: 71 additions & 23 deletions x/crosschain/keeper/msg_server_migrate_tss_funds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -15,53 +15,101 @@ 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)
admin := sample.AccAddress()
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)
admin := sample.AccAddress()
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)
admin := sample.AccAddress()
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,
Expand All @@ -74,20 +122,20 @@ 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)
admin := sample.AccAddress()
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,
Expand All @@ -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) {
Expand All @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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{
Expand Down
2 changes: 2 additions & 0 deletions x/crosschain/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
)
2 changes: 2 additions & 0 deletions x/crosschain/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading