Skip to content

Commit

Permalink
feat(fungible): implement MsgUpdateZRC20Name (#3541)
Browse files Browse the repository at this point in the history
* initialize message

* implement message

* add migration authorization

* e2e test

* update changelog

* change order admin test

* complete test

* fix test

* comments
  • Loading branch information
lumtis authored Feb 18, 2025
1 parent d9b7aa0 commit 9092054
Show file tree
Hide file tree
Showing 20 changed files with 1,375 additions and 78 deletions.
3 changes: 2 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
* [3506](https://github.com/zeta-chain/node/pull/3506) - define `ConfirmationMode` enum and add it to `InboundParams`, `OutboundParams`, `MsgVoteInbound` and `MsgVoteOutbound`
* [3469](https://github.com/zeta-chain/node/pull/3469) - add `MsgRemoveInboundTracker` to remove inbound trackers. This message can be triggered by the emergency policy.
* [3450](https://github.com/zeta-chain/node/pull/3450) - SOL withdraw and call integration
* [3520] (https://github.com/zeta-chain/node/pull/3520) - SPL withdraw and call integration
* [3541](https://github.com/zeta-chain/node/pull/3541) - implement `MsgUpdateZRC20Name` to update the name or symbol of a ZRC20 token
* [3520](https://github.com/zeta-chain/node/pull/3520) - SPL withdraw and call integration

### Refactor

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 @@ -330,6 +330,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) {

if testAdmin {
eg.Go(adminTestRoutine(conf, deployerRunner, verbose,
e2etests.TestUpdateZRC20NameName,
e2etests.TestZetaclientSignerOffsetName,
e2etests.TestZetaclientRestartHeightName,
e2etests.TestWhitelistERC20Name,
Expand Down
2 changes: 2 additions & 0 deletions docs/openapi/openapi.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59562,6 +59562,8 @@ definitions:
type: object
fungibleMsgUpdateZRC20LiquidityCapResponse:
type: object
fungibleMsgUpdateZRC20NameResponse:
type: object
fungibleMsgUpdateZRC20WithdrawFeeResponse:
type: object
fungibleQueryAllForeignCoinsResponse:
Expand Down
13 changes: 13 additions & 0 deletions docs/spec/fungible/messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,16 @@ message MsgUpdateGatewayContract {
}
```

## MsgUpdateZRC20Name

UpdateZRC20Name updates the name and/or the symbol of a zrc20 token

```proto
message MsgUpdateZRC20Name {
string creator = 1;
string zrc20_address = 2;
string name = 3;
string symbol = 4;
}
```

8 changes: 8 additions & 0 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ const (
TestMigrateERC20CustodyFundsName = "migrate_erc20_custody_funds"
TestMigrateTSSName = "migrate_tss"
TestSolanaWhitelistSPLName = "solana_whitelist_spl"
TestUpdateZRC20NameName = "update_zrc20_name"
TestZetaclientRestartHeightName = "zetaclient_restart_height"
TestZetaclientSignerOffsetName = "zetaclient_signer_offset"

Expand Down Expand Up @@ -971,6 +972,13 @@ var AllE2ETests = []runner.E2ETest{
[]runner.ArgDefinition{},
TestMigrateERC20CustodyFunds,
),
runner.NewE2ETest(
TestUpdateZRC20NameName,
"update ZRC20 name and symbol",
[]runner.ArgDefinition{},
TestUpdateZRC20Name,
runner.WithMinimumVersion("v28.0.0"),
),
runner.NewE2ETest(
TestZetaclientRestartHeightName,
"zetaclient scheduled restart height",
Expand Down
54 changes: 54 additions & 0 deletions e2e/e2etests/test_update_zrc20_name.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package e2etests

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

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
fungibletypes "github.com/zeta-chain/node/x/fungible/types"
)

// TestUpdateZRC20Name tests updating name and symbol of a ZRC20
func TestUpdateZRC20Name(r *runner.E2ERunner, _ []string) {
msg := fungibletypes.NewMsgUpdateZRC20Name(
r.ZetaTxServer.MustGetAccountAddressFromName(utils.AdminPolicyName),
r.ETHZRC20Addr.Hex(),
"New ETH",
"ETH.NEW",
)
res, err := r.ZetaTxServer.BroadcastTx(utils.AdminPolicyName, msg)
require.NoError(r, err)

r.Logger.Info("Update eth zrc20 bytecode tx hash: %s", res.TxHash)

// Get new info of the ZRC20
newName, err := r.ETHZRC20.Name(&bind.CallOpts{})
require.NoError(r, err)
require.Equal(r, "New ETH", newName)

newSymbol, err := r.ETHZRC20.Symbol(&bind.CallOpts{})
require.NoError(r, err)
require.Equal(r, "ETH.NEW", newSymbol)

// try another zrc20
msg = fungibletypes.NewMsgUpdateZRC20Name(
r.ZetaTxServer.MustGetAccountAddressFromName(utils.AdminPolicyName),
r.ERC20ZRC20Addr.Hex(),
"New USDT",
"USDT.NEW",
)
res, err = r.ZetaTxServer.BroadcastTx(utils.AdminPolicyName, msg)
require.NoError(r, err)

r.Logger.Info("Update erc20 zrc20 bytecode tx hash: %s", res.TxHash)

// Get new info of the ZRC20
newName, err = r.ERC20ZRC20.Name(&bind.CallOpts{})
require.NoError(r, err)
require.Equal(r, "New USDT", newName)

newSymbol, err = r.ERC20ZRC20.Symbol(&bind.CallOpts{})
require.NoError(r, err)
require.Equal(r, "USDT.NEW", newSymbol)
}
13 changes: 12 additions & 1 deletion proto/zetachain/zetacore/fungible/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ service Msg {
rpc UnpauseZRC20(MsgUnpauseZRC20) returns (MsgUnpauseZRC20Response);
rpc UpdateGatewayContract(MsgUpdateGatewayContract)
returns (MsgUpdateGatewayContractResponse);
rpc UpdateZRC20Name(MsgUpdateZRC20Name) returns (MsgUpdateZRC20NameResponse);
}

message MsgDeploySystemContracts {
Expand Down Expand Up @@ -136,4 +137,14 @@ message MsgUpdateGatewayContract {
string new_gateway_contract_address = 2;
}

message MsgUpdateGatewayContractResponse {}
message MsgUpdateGatewayContractResponse {}

message MsgUpdateZRC20Name {
option (cosmos.msg.v1.signer) = "creator";
string creator = 1;
string zrc20_address = 2;
string name = 3;
string symbol = 4;
}

message MsgUpdateZRC20NameResponse {}
58 changes: 58 additions & 0 deletions typescript/zetachain/zetacore/fungible/tx_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,61 @@ export declare class MsgUpdateGatewayContractResponse extends Message<MsgUpdateG
static equals(a: MsgUpdateGatewayContractResponse | PlainMessage<MsgUpdateGatewayContractResponse> | undefined, b: MsgUpdateGatewayContractResponse | PlainMessage<MsgUpdateGatewayContractResponse> | undefined): boolean;
}

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

/**
* @generated from field: string zrc20_address = 2;
*/
zrc20Address: string;

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

/**
* @generated from field: string symbol = 4;
*/
symbol: string;

constructor(data?: PartialMessage<MsgUpdateZRC20Name>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.fungible.MsgUpdateZRC20Name";
static readonly fields: FieldList;

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

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

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

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

/**
* @generated from message zetachain.zetacore.fungible.MsgUpdateZRC20NameResponse
*/
export declare class MsgUpdateZRC20NameResponse extends Message<MsgUpdateZRC20NameResponse> {
constructor(data?: PartialMessage<MsgUpdateZRC20NameResponse>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.fungible.MsgUpdateZRC20NameResponse";
static readonly fields: FieldList;

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

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

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

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

7 changes: 6 additions & 1 deletion x/authority/migrations/v3/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ func MigrateStore(
) error {
//
var (
authorizationList = types.DefaultAuthorizationsList()
authorizationList = types.DefaultAuthorizationsList()
updateZRC20NameAuthorization = types.Authorization{
MsgUrl: "/zetachain.zetacore.fungible.MsgUpdateZRC20Name",
AuthorizedPolicy: types.PolicyType_groupAdmin,
}
removeInboundAuthorization = types.Authorization{
MsgUrl: "/zetachain.zetacore.crosschain.MsgRemoveInboundTracker",
AuthorizedPolicy: types.PolicyType_groupEmergency,
Expand All @@ -32,6 +36,7 @@ func MigrateStore(
}

// Add the new authorization
authorizationList.SetAuthorization(updateZRC20NameAuthorization)
authorizationList.SetAuthorization(removeInboundAuthorization)

// Validate the authorization list
Expand Down
1 change: 1 addition & 0 deletions x/authority/migrations/v3/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func TestMigrateStore(t *testing.T) {
k, ctx := keepertest.AuthorityKeeper(t)

list := types.DefaultAuthorizationsList()
list.RemoveAuthorization("/zetachain.zetacore.fungible.MsgUpdateZRC20Name")
list.RemoveAuthorization("/zetachain.zetacore.crosschain.MsgRemoveInboundTracker")
k.SetAuthorizationList(ctx, list)

Expand Down
1 change: 1 addition & 0 deletions x/authority/types/authorization_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
"/zetachain.zetacore.fungible.MsgUpdateGatewayContract",
"/zetachain.zetacore.fungible.MsgRemoveForeignCoin",
"/zetachain.zetacore.fungible.MsgDeployFungibleCoinZRC20",
"/zetachain.zetacore.fungible.MsgUpdateZRC20Name",
"/zetachain.zetacore.observer.MsgUpdateObserver",
"/zetachain.zetacore.observer.MsgAddObserver",
"/zetachain.zetacore.observer.MsgRemoveChainParams",
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 @@ -426,6 +426,7 @@ func TestDefaultAuthorizationsList(t *testing.T) {
sdk.MsgTypeURL(&fungibletypes.MsgUpdateSystemContract{}),
sdk.MsgTypeURL(&fungibletypes.MsgUpdateGatewayContract{}),
sdk.MsgTypeURL(&fungibletypes.MsgRemoveForeignCoin{}),
sdk.MsgTypeURL(&fungibletypes.MsgUpdateZRC20Name{}),
sdk.MsgTypeURL(&observertypes.MsgUpdateObserver{}),
sdk.MsgTypeURL(&observertypes.MsgAddObserver{}),
sdk.MsgTypeURL(&observertypes.MsgRemoveChainParams{}),
Expand Down
62 changes: 62 additions & 0 deletions x/fungible/keeper/msg_server_update_zrc20_name.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package keeper

import (
"context"

cosmoserrors "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ethcommon "github.com/ethereum/go-ethereum/common"

authoritytypes "github.com/zeta-chain/node/x/authority/types"
"github.com/zeta-chain/node/x/fungible/types"
)

// UpdateZRC20Name updates the name and/or the symbol of a zrc20 token
func (k msgServer) UpdateZRC20Name(
goCtx context.Context,
msg *types.MsgUpdateZRC20Name,
) (*types.MsgUpdateZRC20NameResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

// check signer permission
err := k.GetAuthorityKeeper().CheckAuthorization(ctx, msg)
if err != nil {
return nil, cosmoserrors.Wrap(authoritytypes.ErrUnauthorized, err.Error())
}

// check the zrc20 is valid
zrc20Addr := ethcommon.HexToAddress(msg.Zrc20Address)
if zrc20Addr == (ethcommon.Address{}) {
return nil, cosmoserrors.Wrapf(
sdkerrors.ErrInvalidAddress,
"invalid zrc20 contract address (%s)",
msg.Zrc20Address,
)
}

// check the zrc20 exists
_, found := k.GetForeignCoins(ctx, msg.Zrc20Address)
if !found {
return nil, cosmoserrors.Wrapf(
types.ErrForeignCoinNotFound,
"no foreign coin match requested zrc20 address (%s)",
msg.Zrc20Address,
)
}

// call the contract methods
if msg.Name != "" {
if err := k.ZRC20SetName(ctx, zrc20Addr, msg.Name); err != nil {
return nil, cosmoserrors.Wrapf(types.ErrContractCall, "failed to update zrc20 name (%s)", err.Error())
}
}

if msg.Symbol != "" {
if err = k.ZRC20SetSymbol(ctx, zrc20Addr, msg.Symbol); err != nil {
return nil, cosmoserrors.Wrapf(types.ErrContractCall, "failed to update zrc20 symbol (%s)", err.Error())
}
}

return &types.MsgUpdateZRC20NameResponse{}, nil
}
Loading

0 comments on commit 9092054

Please sign in to comment.