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
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Features

* [2578](https://github.com/zeta-chain/node/pull/2578) - add Gateway address in protocol contract list
* [2630](https://github.com/zeta-chain/node/pull/2630) - implement `MsgMigrateERC20CustodyFunds` to migrate the funds from the ERC20Custody to a new contracts (to be used for the new ERC20Custody contract for smart contract V2)
* [2578](https://github.com/zeta-chain/node/pull/2578) - Add Gateway address in protocol contract list
* [2634](https://github.com/zeta-chain/node/pull/2634) - add support for EIP-1559 gas fees
* [2597](https://github.com/zeta-chain/node/pull/2597) - Add generic rpc metrics to zetaclient
Expand Down
1 change: 1 addition & 0 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
e2etests.TestUpdateBytecodeConnectorName,
e2etests.TestDepositEtherLiquidityCapName,
e2etests.TestCriticalAdminTransactionsName,
e2etests.TestMigrateERC20CustodyFundsName,

// TestMigrateChainSupportName tests EVM chain migration. Currently this test doesn't work with Anvil because pre-EIP1559 txs are not supported
// See issue below for details
Expand Down
5 changes: 5 additions & 0 deletions docs/openapi/openapi.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57231,6 +57231,11 @@ definitions:
is_removed:
type: boolean
title: if the tx was removed from the tracker due to no pending cctx
crosschainMsgMigrateERC20CustodyFundsResponse:
type: object
properties:
cctx_index:
type: string
crosschainMsgMigrateTssFundsResponse:
type: object
crosschainMsgRefundAbortedCCTXResponse:
Expand Down
14 changes: 14 additions & 0 deletions docs/spec/crosschain/messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,17 @@ message MsgUpdateRateLimiterFlags {
}
```

## MsgMigrateERC20CustodyFunds

MigrateERC20CustodyFunds migrates the funds from the current ERC20Custody contract to the new ERC20Custody contract

```proto
message MsgMigrateERC20CustodyFunds {
string creator = 1;
int64 chain_id = 2;
string new_custody_address = 3;
string erc20_address = 4;
string amount = 5;
}
```

7 changes: 7 additions & 0 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ const (
TestUpdateBytecodeConnectorName = "update_bytecode_connector"
TestRateLimiterName = "rate_limiter"
TestCriticalAdminTransactionsName = "critical_admin_transactions"
TestMigrateERC20CustodyFundsName = "migrate_erc20_custody_funds"

TestMigrateTSSName = "migrate_TSS"

Expand Down Expand Up @@ -572,6 +573,12 @@ var AllE2ETests = []runner.E2ETest{
[]runner.ArgDefinition{},
TestCriticalAdminTransactions,
),
runner.NewE2ETest(
TestMigrateERC20CustodyFundsName,
"migrate ERC20 custody funds",
[]runner.ArgDefinition{},
TestMigrateERC20CustodyFunds,
),
/*
Special tests
*/
Expand Down
61 changes: 61 additions & 0 deletions e2e/e2etests/test_migrate_erc20_custody_funds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package e2etests

import (
sdkmath "cosmossdk.io/math"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"

"github.com/zeta-chain/zetacore/e2e/runner"
"github.com/zeta-chain/zetacore/e2e/txserver"
"github.com/zeta-chain/zetacore/e2e/utils"
"github.com/zeta-chain/zetacore/testutil/sample"
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"
)

// TestMigrateERC20CustodyFunds tests the migration of ERC20 custody funds
func TestMigrateERC20CustodyFunds(r *runner.E2ERunner, _ []string) {
// get erc20 balance on ERC20 custody contract
balance, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.ERC20CustodyAddr)
require.NoError(r, err)

// get EVM chain ID
chainID, err := r.EVMClient.ChainID(r.Ctx)
require.NoError(r, err)

newAddr := sample.EthAddress()

// send MigrateERC20CustodyFunds command
// NOTE: we currently use a random address for the destination as a sufficient way to check migration
// TODO: makes the test more complete and perform a withdraw to new custody once the contract V2 architecture is integrated
// https://github.com/zeta-chain/node/issues/2474
msg := crosschaintypes.NewMsgMigrateERC20CustodyFunds(
r.ZetaTxServer.MustGetAccountAddressFromName(utils.AdminPolicyName),
chainID.Int64(),
newAddr.Hex(),
r.ERC20Addr.Hex(),
sdkmath.NewUintFromBigInt(balance),
)
res, err := r.ZetaTxServer.BroadcastTx(utils.AdminPolicyName, msg)
require.NoError(r, err)

// fetch cctx index from tx response
cctxIndex, err := txserver.FetchAttributeFromTxResponse(res, "cctx_index")
require.NoError(r, err)

cctxRes, err := r.CctxClient.Cctx(r.Ctx, &crosschaintypes.QueryGetCctxRequest{Index: cctxIndex})
require.NoError(r, err)

cctx := cctxRes.CrossChainTx
r.Logger.CCTX(*cctx, "migration")

// wait for the cctx to be mined
r.WaitForMinedCCTXFromIndex(cctxIndex)

// check ERC20 balance on new address
newAddrBalance, err := r.ERC20.BalanceOf(&bind.CallOpts{}, newAddr)
require.NoError(r, err)
require.Equal(r, balance, newAddrBalance)

// artificially set the ERC20 Custody address to the new address to prevent accounting check from failing
r.ERC20CustodyAddr = newAddr
}
3 changes: 3 additions & 0 deletions pkg/constant/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const (
// CmdWhitelistERC20 is used for CCTX of type cmd to give the instruction to the TSS to whitelist an ERC20 on an exeternal chain
CmdWhitelistERC20 = "cmd_whitelist_erc20"

// CmdMigrateERC20CustodyFunds is used for CCTX of type cmd to give the instruction to the TSS to transfer its funds on a new address
CmdMigrateERC20CustodyFunds = "cmd_migrate_erc20_custody_funds"

// CmdMigrateTssFunds is used for CCTX of type cmd to give the instruction to the TSS to transfer its funds on a new address
CmdMigrateTssFunds = "cmd_migrate_tss_funds"

Expand Down
7 changes: 7 additions & 0 deletions proto/zetachain/zetacore/crosschain/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,10 @@ message EventERC20Whitelist {
string whitelist_cctx_index = 1;
string zrc20_address = 2;
}

message EventERC20CustodyFundsMigration {
string new_custody_address = 1;
string erc20_address = 2;
string amount = 3;
string cctx_index = 4;
}
16 changes: 16 additions & 0 deletions proto/zetachain/zetacore/crosschain/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ service Msg {

rpc UpdateRateLimiterFlags(MsgUpdateRateLimiterFlags)
returns (MsgUpdateRateLimiterFlagsResponse);

rpc MigrateERC20CustodyFunds(MsgMigrateERC20CustodyFunds)
returns (MsgMigrateERC20CustodyFundsResponse);
}

message MsgMigrateTssFunds {
Expand Down Expand Up @@ -188,3 +191,16 @@ message MsgUpdateRateLimiterFlags {
}

message MsgUpdateRateLimiterFlagsResponse {}

message MsgMigrateERC20CustodyFunds {
string creator = 1;
int64 chain_id = 2;
string new_custody_address = 3;
string erc20_address = 4;
string amount = 5 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint",
(gogoproto.nullable) = false
];
}

message MsgMigrateERC20CustodyFundsResponse { string cctx_index = 1; }
13 changes: 13 additions & 0 deletions testutil/sample/crosschain.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,19 @@ func GasPrice(t *testing.T, index string) *types.GasPrice {
}
}

func GasPriceWithChainID(t *testing.T, chainID int64) types.GasPrice {
r := newRandFromStringSeed(t, fmt.Sprintf("%d", chainID))

return types.GasPrice{
Creator: AccAddress(),
ChainId: chainID,
Signers: []string{AccAddress(), AccAddress()},
BlockNums: []uint64{r.Uint64(), r.Uint64()},
Prices: []uint64{r.Uint64(), r.Uint64()},
MedianIndex: 0,
}
}

func InboundParams(r *rand.Rand) *types.InboundParams {
return &types.InboundParams{
Sender: EthAddress().String(),
Expand Down
39 changes: 39 additions & 0 deletions typescript/zetachain/zetacore/crosschain/events_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,3 +354,42 @@ export declare class EventERC20Whitelist extends Message<EventERC20Whitelist> {
static equals(a: EventERC20Whitelist | PlainMessage<EventERC20Whitelist> | undefined, b: EventERC20Whitelist | PlainMessage<EventERC20Whitelist> | undefined): boolean;
}

/**
* @generated from message zetachain.zetacore.crosschain.EventERC20CustodyFundsMigration
*/
export declare class EventERC20CustodyFundsMigration extends Message<EventERC20CustodyFundsMigration> {
/**
* @generated from field: string new_custody_address = 1;
*/
newCustodyAddress: string;

/**
* @generated from field: string erc20_address = 2;
*/
erc20Address: string;

/**
* @generated from field: string amount = 3;
*/
amount: string;

/**
* @generated from field: string cctx_index = 4;
*/
cctxIndex: string;

constructor(data?: PartialMessage<EventERC20CustodyFundsMigration>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.crosschain.EventERC20CustodyFundsMigration";
static readonly fields: FieldList;

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): EventERC20CustodyFundsMigration;

static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): EventERC20CustodyFundsMigration;

static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): EventERC20CustodyFundsMigration;

static equals(a: EventERC20CustodyFundsMigration | PlainMessage<EventERC20CustodyFundsMigration> | undefined, b: EventERC20CustodyFundsMigration | PlainMessage<EventERC20CustodyFundsMigration> | undefined): boolean;
}

68 changes: 68 additions & 0 deletions typescript/zetachain/zetacore/crosschain/tx_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -826,3 +826,71 @@ export declare class MsgUpdateRateLimiterFlagsResponse extends Message<MsgUpdate
static equals(a: MsgUpdateRateLimiterFlagsResponse | PlainMessage<MsgUpdateRateLimiterFlagsResponse> | undefined, b: MsgUpdateRateLimiterFlagsResponse | PlainMessage<MsgUpdateRateLimiterFlagsResponse> | undefined): boolean;
}

/**
* @generated from message zetachain.zetacore.crosschain.MsgMigrateERC20CustodyFunds
*/
export declare class MsgMigrateERC20CustodyFunds extends Message<MsgMigrateERC20CustodyFunds> {
/**
* @generated from field: string creator = 1;
*/
creator: string;

/**
* @generated from field: int64 chain_id = 2;
*/
chainId: bigint;

/**
* @generated from field: string new_custody_address = 3;
*/
newCustodyAddress: string;

/**
* @generated from field: string erc20_address = 4;
*/
erc20Address: string;

/**
* @generated from field: string amount = 5;
*/
amount: string;

constructor(data?: PartialMessage<MsgMigrateERC20CustodyFunds>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.crosschain.MsgMigrateERC20CustodyFunds";
static readonly fields: FieldList;

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): MsgMigrateERC20CustodyFunds;

static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): MsgMigrateERC20CustodyFunds;

static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): MsgMigrateERC20CustodyFunds;

static equals(a: MsgMigrateERC20CustodyFunds | PlainMessage<MsgMigrateERC20CustodyFunds> | undefined, b: MsgMigrateERC20CustodyFunds | PlainMessage<MsgMigrateERC20CustodyFunds> | undefined): boolean;
}

/**
* @generated from message zetachain.zetacore.crosschain.MsgMigrateERC20CustodyFundsResponse
*/
export declare class MsgMigrateERC20CustodyFundsResponse extends Message<MsgMigrateERC20CustodyFundsResponse> {
/**
* @generated from field: string cctx_index = 1;
*/
cctxIndex: string;

constructor(data?: PartialMessage<MsgMigrateERC20CustodyFundsResponse>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.crosschain.MsgMigrateERC20CustodyFundsResponse";
static readonly fields: FieldList;

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): MsgMigrateERC20CustodyFundsResponse;

static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): MsgMigrateERC20CustodyFundsResponse;

static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): MsgMigrateERC20CustodyFundsResponse;

static equals(a: MsgMigrateERC20CustodyFundsResponse | PlainMessage<MsgMigrateERC20CustodyFundsResponse> | undefined, b: MsgMigrateERC20CustodyFundsResponse | PlainMessage<MsgMigrateERC20CustodyFundsResponse> | undefined): boolean;
}

1 change: 1 addition & 0 deletions x/authority/types/authorization_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var (
}
// AdminPolicyMessages keeps track of the message URLs that can, by default, only be executed by admin policy address
AdminPolicyMessages = []string{
"/zetachain.zetacore.crosschain.MsgMigrateERC20CustodyFunds",
"/zetachain.zetacore.crosschain.MsgMigrateTssFunds",
"/zetachain.zetacore.crosschain.MsgUpdateTssAddress",
"/zetachain.zetacore.crosschain.MsgWhitelistERC20",
Expand Down
1 change: 1 addition & 0 deletions x/authority/types/authorization_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ func TestDefaultAuthorizationsList(t *testing.T) {

// AdminPolicyMessageList is a list of messages that can be authorized by the admin policy
var AdminPolicyMessageList = []string{
sdk.MsgTypeURL(&crosschaintypes.MsgMigrateERC20CustodyFunds{}),
sdk.MsgTypeURL(&crosschaintypes.MsgMigrateTssFunds{}),
sdk.MsgTypeURL(&crosschaintypes.MsgUpdateTssAddress{}),
sdk.MsgTypeURL(&crosschaintypes.MsgWhitelistERC20{}),
Expand Down
4 changes: 2 additions & 2 deletions x/crosschain/keeper/cctx_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ import (
"github.com/zeta-chain/zetacore/pkg/coin"
"github.com/zeta-chain/zetacore/x/crosschain/types"
fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types"
zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
)

// SetObserverOutboundInfo sets the CCTX outbound nonce to the next available nonce for the TSS address, and updates the nonce of blockchain state.
// It also updates the PendingNonces that is used to track the unfulfilled outbound txs.
func (k Keeper) SetObserverOutboundInfo(ctx sdk.Context, receiveChainID int64, cctx *types.CrossChainTx) error {
chain, found := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, receiveChainID)
if !found {
return zetaObserverTypes.ErrSupportedChains
return observertypes.ErrSupportedChains
}

nonce, found := k.GetObserverKeeper().GetChainNonces(ctx, receiveChainID)
Expand Down
Loading