Skip to content

Commit

Permalink
feat: implement MsgUpdateERC20CustodyPauseStatus to pause or unpaus…
Browse files Browse the repository at this point in the history
…e ERC20 Custody (#2681)

* refactor cmd cctx creation

* initialize migrate funds message

* implement migrate message

* zetaclient implementation

* fix event

* fix params

* add e2e test

* generate

* changelog

* zetaclient test

* fix message test

* initialize cctx test

* cmd cctx type tests

* message test

* Update zetaclient/chains/evm/signer/admin_cmd.go

Co-authored-by: skosito <skostic9242@gmail.com>

* tanmay comments

* stefan comments

* admin commands

* make generate

* initialize message

* some message fixes

* implement logic on ZetaClient

* update pause status

* add in authorization list

* E2E test

* add test in admin workflow

* add event for pausing

* changelogs

* Update x/crosschain/types/cmd_cctxs.go

Co-authored-by: skosito <skostic9242@gmail.com>

* Update x/crosschain/types/cmd_cctxs.go

Co-authored-by: skosito <skostic9242@gmail.com>

* fix

* remove rate limiter test

---------

Co-authored-by: skosito <skostic9242@gmail.com>
  • Loading branch information
lumtis and skosito authored Aug 15, 2024
1 parent e2351ce commit 7039dcc
Show file tree
Hide file tree
Showing 24 changed files with 2,032 additions and 162 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* [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
* [2538](https://github.com/zeta-chain/node/pull/2538) - add background worker routines to shutdown zetaclientd when needed for tss migration
* [2681](https://github.com/zeta-chain/node/pull/2681) - implement `MsgUpdateERC20CustodyPauseStatus` to pause or unpause ERC20 Custody contract (to be used for the migration process for smart contract V2)
* [2644](https://github.com/zeta-chain/node/pull/2644) - add created_timestamp to cctx status

### Refactor
Expand Down
8 changes: 7 additions & 1 deletion cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,14 +296,20 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
if testAdmin {
eg.Go(adminTestRoutine(conf, deployerRunner, verbose,
e2etests.TestWhitelistERC20Name,
e2etests.TestRateLimiterName,
e2etests.TestPauseZRC20Name,
e2etests.TestUpdateBytecodeZRC20Name,
e2etests.TestUpdateBytecodeConnectorName,
e2etests.TestDepositEtherLiquidityCapName,
e2etests.TestCriticalAdminTransactionsName,
e2etests.TestPauseERC20CustodyName,
e2etests.TestMigrateERC20CustodyFundsName,

// Test the rate limiter functionalities
// this test is currently incomplete and takes 10m to run
// TODO: define assertion, and make more optimized
// https://github.com/zeta-chain/node/issues/2090
//e2etests.TestRateLimiterName,

// 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
// TODO: renenable this test as per the issue below
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 @@ -57242,6 +57242,11 @@ definitions:
type: object
crosschainMsgRemoveOutboundTrackerResponse:
type: object
crosschainMsgUpdateERC20CustodyPauseStatusResponse:
type: object
properties:
cctx_index:
type: string
crosschainMsgUpdateRateLimiterFlagsResponse:
type: object
crosschainMsgUpdateTssAddressResponse:
Expand Down
12 changes: 12 additions & 0 deletions docs/spec/crosschain/messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,15 @@ message MsgMigrateERC20CustodyFunds {
}
```

## MsgUpdateERC20CustodyPauseStatus

UpdateERC20CustodyPauseStatus creates a admin cmd cctx to update the pause status of the ERC20 custody contract

```proto
message MsgUpdateERC20CustodyPauseStatus {
string creator = 1;
int64 chain_id = 2;
bool pause = 3;
}
```

10 changes: 8 additions & 2 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ const (
TestUpdateBytecodeConnectorName = "update_bytecode_connector"
TestRateLimiterName = "rate_limiter"
TestCriticalAdminTransactionsName = "critical_admin_transactions"
TestPauseERC20CustodyName = "pause_erc20_custody"
TestMigrateERC20CustodyFundsName = "migrate_erc20_custody_funds"

TestMigrateTSSName = "migrate_TSS"
TestMigrateTSSName = "migrate_TSS"

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

import (
"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"
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"
)

// TestPauseERC20Custody tests the pausing and unpausing of ERC20 custody contracts on the EVM chain
func TestPauseERC20Custody(r *runner.E2ERunner, _ []string) {
// get EVM chain ID
chainID, err := r.EVMClient.ChainID(r.Ctx)
require.NoError(r, err)

// check ERC20 custody contract is not paused
paused, err := r.ERC20Custody.Paused(&bind.CallOpts{})
require.NoError(r, err)
require.False(r, paused)

// Part 1: Pause ERC20 custody contract

// send command for pausing ERC20 custody contract
msg := crosschaintypes.NewMsgUpdateERC20CustodyPauseStatus(
r.ZetaTxServer.MustGetAccountAddressFromName(utils.AdminPolicyName),
chainID.Int64(),
true,
)
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, "pausing")

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

// check ERC20 custody contract is paused
paused, err = r.ERC20Custody.Paused(&bind.CallOpts{})
require.NoError(r, err)
require.True(r, paused)

// Part 2: Unpause ERC20 custody contract

// send command for unpausing ERC20 custody contract
msg = crosschaintypes.NewMsgUpdateERC20CustodyPauseStatus(
r.ZetaTxServer.MustGetAccountAddressFromName(utils.AdminPolicyName),
chainID.Int64(),
false,
)
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, "unpausing")

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

// check ERC20 custody contract is unpaused
paused, err = r.ERC20Custody.Paused(&bind.CallOpts{})
require.NoError(r, err)
require.False(r, paused)
}
9 changes: 9 additions & 0 deletions pkg/constant/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const (
// 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"

// CmdUpdateERC20CustodyPauseStatus is used for CCTX of type cmd to give the instruction to the TSS to update the pause status of the ERC20 custody contract
CmdUpdateERC20CustodyPauseStatus = "cmd_update_erc20_custody_pause_status"

// 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 All @@ -28,4 +31,10 @@ const (
// The Solana protocol sets minimum rent exempt to 890880 lamports but we set it to 1_000_000 lamports (0.001 SOL)
// The number 890880 comes from CLI command `solana rent 0` and has been verified on devnet gateway program
SolanaWalletRentExempt = 1_000_000

// OptionPause is the argument used in CmdUpdateERC20CustodyPauseStatus to pause the ERC20 custody contract
OptionPause = "pause"

// OptionUnpause is the argument used in CmdUpdateERC20CustodyPauseStatus to unpause the ERC20 custody contract
OptionUnpause = "unpause"
)
6 changes: 6 additions & 0 deletions proto/zetachain/zetacore/crosschain/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,9 @@ message EventERC20CustodyFundsMigration {
string amount = 3;
string cctx_index = 4;
}

message EventERC20CustodyPausing {
int64 chain_id = 1;
bool pause = 2;
string cctx_index = 3;
}
14 changes: 14 additions & 0 deletions proto/zetachain/zetacore/crosschain/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ service Msg {

rpc MigrateERC20CustodyFunds(MsgMigrateERC20CustodyFunds)
returns (MsgMigrateERC20CustodyFundsResponse);

rpc UpdateERC20CustodyPauseStatus(MsgUpdateERC20CustodyPauseStatus)
returns (MsgUpdateERC20CustodyPauseStatusResponse);
}

message MsgMigrateTssFunds {
Expand Down Expand Up @@ -204,3 +207,14 @@ message MsgMigrateERC20CustodyFunds {
}

message MsgMigrateERC20CustodyFundsResponse { string cctx_index = 1; }

message MsgUpdateERC20CustodyPauseStatus {
string creator = 1;
int64 chain_id = 2;

// pause or unpause
// true = pause, false = unpause
bool pause = 3;
}

message MsgUpdateERC20CustodyPauseStatusResponse { string cctx_index = 1; }
34 changes: 34 additions & 0 deletions typescript/zetachain/zetacore/crosschain/events_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,37 @@ export declare class EventERC20CustodyFundsMigration extends Message<EventERC20C
static equals(a: EventERC20CustodyFundsMigration | PlainMessage<EventERC20CustodyFundsMigration> | undefined, b: EventERC20CustodyFundsMigration | PlainMessage<EventERC20CustodyFundsMigration> | undefined): boolean;
}

/**
* @generated from message zetachain.zetacore.crosschain.EventERC20CustodyPausing
*/
export declare class EventERC20CustodyPausing extends Message<EventERC20CustodyPausing> {
/**
* @generated from field: int64 chain_id = 1;
*/
chainId: bigint;

/**
* @generated from field: bool pause = 2;
*/
pause: boolean;

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

constructor(data?: PartialMessage<EventERC20CustodyPausing>);

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

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

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

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

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

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

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

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

/**
* pause or unpause
* true = pause, false = unpause
*
* @generated from field: bool pause = 3;
*/
pause: boolean;

constructor(data?: PartialMessage<MsgUpdateERC20CustodyPauseStatus>);

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

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

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

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

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

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

constructor(data?: PartialMessage<MsgUpdateERC20CustodyPauseStatusResponse>);

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

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

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

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

static equals(a: MsgUpdateERC20CustodyPauseStatusResponse | PlainMessage<MsgUpdateERC20CustodyPauseStatusResponse> | undefined, b: MsgUpdateERC20CustodyPauseStatusResponse | PlainMessage<MsgUpdateERC20CustodyPauseStatusResponse> | 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.MsgUpdateERC20CustodyPauseStatus",
"/zetachain.zetacore.crosschain.MsgMigrateERC20CustodyFunds",
"/zetachain.zetacore.crosschain.MsgMigrateTssFunds",
"/zetachain.zetacore.crosschain.MsgUpdateTssAddress",
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.MsgUpdateERC20CustodyPauseStatus{}),
sdk.MsgTypeURL(&crosschaintypes.MsgMigrateERC20CustodyFunds{}),
sdk.MsgTypeURL(&crosschaintypes.MsgMigrateTssFunds{}),
sdk.MsgTypeURL(&crosschaintypes.MsgUpdateTssAddress{}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/zetacore/pkg/coin"
"github.com/zeta-chain/zetacore/pkg/constant"
testkeeper "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/testutil/sample"
authoritytypes "github.com/zeta-chain/zetacore/x/authority/types"
Expand Down Expand Up @@ -58,6 +59,7 @@ func TestKeeper_MigrateERC20CustodyFunds(t *testing.T) {
cctx, found := k.GetCrossChainTx(ctx, res.CctxIndex)
require.True(t, found)
require.Equal(t, coin.CoinType_Cmd, cctx.InboundParams.CoinType)
require.Contains(t, cctx.RelayedMessage, constant.CmdMigrateERC20CustodyFunds)
require.Len(t, cctx.OutboundParams, 1)
require.EqualValues(
t,
Expand Down
Loading

0 comments on commit 7039dcc

Please sign in to comment.