Skip to content

Commit

Permalink
fix: hardcode erc20 asset strings to align with the data in foreign c…
Browse files Browse the repository at this point in the history
…oin store (#3273)

* hardcode erc20 asset string to align with foreign coin store data

* Update zetaclient/chains/evm/observer/inbound.go

added Github issue link above hardcoded variable

Co-authored-by: Lucas Bertrand <[email protected]>

* Update zetaclient/chains/evm/observer/inbound.go

added Github issue link around the hotfix

Co-authored-by: Lucas Bertrand <[email protected]>

* Update zetaclient/chains/evm/observer/v2_inbound.go

added Github issue link around the hotfix

Co-authored-by: Lucas Bertrand <[email protected]>

* Update zetaclient/chains/evm/observer/v2_inbound.go

add Github issue at the hotfix

Co-authored-by: Lucas Bertrand <[email protected]>

* remove checksum asset from erc20AddressToForeignCoinAssetMap to reduce the list

* fix unit test

---------

Co-authored-by: Lucas Bertrand <[email protected]>
  • Loading branch information
ws4charlie and lumtis authored Dec 10, 2024
1 parent ff5d8e3 commit 2ca464a
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 11 deletions.
23 changes: 22 additions & 1 deletion pkg/contracts/solana/inbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,28 @@ func Test_ParseInboundAsDepositAndCall(t *testing.T) {
// solana e2e deployer account
sender := "37yGiHAnLvWZUNVwu9esp74YQFqxU1qHCbABkDvRddUQ"
// example contract deployed during e2e test, read from tx result
expectedReceiver := []byte{117, 160, 106, 140, 37, 135, 57, 218, 223, 226, 53, 45, 87, 151, 61, 239, 158, 231, 162, 186}
expectedReceiver := []byte{
117,
160,
106,
140,
37,
135,
57,
218,
223,
226,
53,
45,
87,
151,
61,
239,
158,
231,
162,
186,
}
expectedMsg := []byte("hello lamports")
expectedDeposit := &Deposit{
Sender: sender,
Expand Down
74 changes: 71 additions & 3 deletions zetaclient/chains/evm/observer/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/erc20custody.sol"
"github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.non-eth.sol"

"github.com/zeta-chain/node/pkg/chains"
"github.com/zeta-chain/node/pkg/coin"
"github.com/zeta-chain/node/pkg/constant"
"github.com/zeta-chain/node/pkg/memo"
Expand All @@ -34,6 +35,67 @@ import (
"github.com/zeta-chain/node/zetaclient/zetacore"
)

var (
// erc20AddressToForeignCoinAssetMap maps the chain id and foreign ERC20 address to the coin asset string
// this is currently necessary because of the following issue: https://github.com/zeta-chain/node/issues/3274
erc20AddressToForeignCoinAssetMap = map[int64]map[ethcommon.Address]string{
// Ethereum mainnet
chains.Ethereum.ChainId: {
// USDC.ETH
ethcommon.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"): "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
// PEPE.ETH
ethcommon.HexToAddress("0x6982508145454ce325ddbe47a25d4ec3d2311933"): "0x6982508145454ce325ddbe47a25d4ec3d2311933",
// SHIB.ETH
ethcommon.HexToAddress("0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce"): "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce",
// USDT.ETH
ethcommon.HexToAddress("0xdac17f958d2ee523a2206206994597c13d831ec7"): "0xdac17f958d2ee523a2206206994597c13d831ec7",
// DAI.ETH
ethcommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f"): "0x6b175474e89094c44da98b954eedeac495271d0f",
},

// BSC mainnet
chains.BscMainnet.ChainId: {
// USDC.BSC
ethcommon.HexToAddress("0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d"): "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
// USDT.BSC
ethcommon.HexToAddress("0x55d398326f99059ff775485246999027b3197955"): "0x55d398326f99059ff775485246999027b3197955",
},

// Polygon mainnet
chains.Polygon.ChainId: {
// USDT.POL
ethcommon.HexToAddress("0xc2132d05d31c914a87c6611c10748aeb04b58e8f"): "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
// USDC.POL
ethcommon.HexToAddress("0x3c499c542cef5e3811e1192ce70d8cc03d5c3359"): "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
},

// Polygon Amoy
chains.Amoy.ChainId: {
// USDC.AMOY
ethcommon.HexToAddress("0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582"): "0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582",
},
}
)

// PatchZRC20Asset returns a patched asset string for the given chainID and erc20Address
// so that it matches the asset string in the foreign coin store.
func PatchZRC20Asset(chainID int64, erc20Address ethcommon.Address) string {
addressToAsset, found := erc20AddressToForeignCoinAssetMap[chainID]
if found {
// if found, convert the address to asset in foreigh coin store
asset, found := addressToAsset[erc20Address]
if found {
return asset
}

// use the checksum address as asset string by default
return erc20Address.Hex()
}

// use the checksum address as asset string by default
return erc20Address.Hex()
}

// WatchInbound watches evm chain for incoming txs and post votes to zetacore
// TODO(revamp): move ticker function to a separate file
func (ob *Observer) WatchInbound(ctx context.Context) error {
Expand Down Expand Up @@ -672,11 +734,17 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent(
Msgf("thank you rich folk for your donation! tx %s chain %d", event.Raw.TxHash.Hex(), ob.Chain().ChainId)
return nil
}

// get patched asset string so that it matches the asset in the foreign coin store
// TODO: remove once the checksum conversion is fixed in the protocol
// https://github.com/zeta-chain/node/issues/3274
asset := PatchZRC20Asset(ob.Chain().ChainId, event.Asset)

message := hex.EncodeToString(event.Message)
ob.Logger().Inbound.Info().
Msgf("ERC20CustodyDeposited inbound detected on chain %d tx %s block %d from %s value %s message %s",
Msgf("ERC20CustodyDeposited inbound detected on chain %d tx %s block %d from %s value %s asset %s message %s",
ob.Chain().
ChainId, event.Raw.TxHash.Hex(), event.Raw.BlockNumber, sender.Hex(), event.Amount.String(), message)
ChainId, event.Raw.TxHash.Hex(), event.Raw.BlockNumber, sender.Hex(), event.Amount.String(), asset, message)

return zetacore.GetInboundVoteMessage(
sender.Hex(),
Expand All @@ -690,7 +758,7 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent(
event.Raw.BlockNumber,
1_500_000,
coin.CoinType_ERC20,
event.Asset.String(),
asset,
ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(),
event.Raw.Index,
)
Expand Down
89 changes: 84 additions & 5 deletions zetaclient/chains/evm/observer/inbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,95 @@ import (
"github.com/zeta-chain/node/pkg/coin"
"github.com/zeta-chain/node/pkg/constant"
"github.com/zeta-chain/node/zetaclient/chains/evm"
"github.com/zeta-chain/node/zetaclient/chains/evm/observer"
"github.com/zeta-chain/node/zetaclient/chains/interfaces"
"github.com/zeta-chain/node/zetaclient/config"
"github.com/zeta-chain/node/zetaclient/testutils"
"github.com/zeta-chain/node/zetaclient/testutils/mocks"
clienttypes "github.com/zeta-chain/node/zetaclient/types"
)

func Test_PatchZRC20Asset(t *testing.T) {
tests := []struct {
name string
chainID int64
erc20Address ethcommon.Address
assetString string
}{
// Ethereum Mainnet
{
name: "USDC.ETH",
chainID: chains.Ethereum.ChainId,
erc20Address: ethcommon.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"),
assetString: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
},
{
name: "PEPE.ETH",
chainID: chains.Ethereum.ChainId,
erc20Address: ethcommon.HexToAddress("0x6982508145454ce325ddbe47a25d4ec3d2311933"),
assetString: "0x6982508145454ce325ddbe47a25d4ec3d2311933",
},
{
name: "SHIB.ETH",
chainID: chains.Ethereum.ChainId,
erc20Address: ethcommon.HexToAddress("0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce"),
assetString: "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce",
},
{
name: "USDT.ETH",
chainID: chains.Ethereum.ChainId,
erc20Address: ethcommon.HexToAddress("0xdac17f958d2ee523a2206206994597c13d831ec7"),
assetString: "0xdac17f958d2ee523a2206206994597c13d831ec7",
},
{
name: "DAI.ETH",
chainID: chains.Ethereum.ChainId,
erc20Address: ethcommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f"),
assetString: "0x6b175474e89094c44da98b954eedeac495271d0f",
},
// BSC Mainnet
{
name: "USDC.BSC",
chainID: chains.BscMainnet.ChainId,
erc20Address: ethcommon.HexToAddress("0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d"),
assetString: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
},
{
name: "USDT.BSC",
chainID: chains.BscMainnet.ChainId,
erc20Address: ethcommon.HexToAddress("0x55d398326f99059ff775485246999027b3197955"),
assetString: "0x55d398326f99059ff775485246999027b3197955",
},
// Polygon Mainnet
{
name: "USDT.POL",
chainID: chains.Polygon.ChainId,
erc20Address: ethcommon.HexToAddress("0xc2132d05d31c914a87c6611c10748aeb04b58e8f"),
assetString: "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
},
{
name: "USDC.POL",
chainID: chains.Polygon.ChainId,
erc20Address: ethcommon.HexToAddress("0x3c499c542cef5e3811e1192ce70d8cc03d5c3359"),
assetString: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
},
// Polygon Amoy
{
name: "USDC.AMOY",
chainID: chains.Amoy.ChainId,
erc20Address: ethcommon.HexToAddress("0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582"),
assetString: "0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
asset := observer.PatchZRC20Asset(tt.chainID, tt.erc20Address)
require.Equal(t, tt.assetString, asset)
})
}
}

func Test_CheckAndVoteInboundTokenZeta(t *testing.T) {
// load archived ZetaSent inbound, receipt and cctx
// https://etherscan.io/tx/0xf3935200c80f98502d5edc7e871ffc40ca898e134525c42c2ae3cbc5725f9d76
Expand Down Expand Up @@ -133,7 +215,7 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) {
ctx := context.Background()

t.Run("should pass for archived inbound, receipt and cctx", func(t *testing.T) {
tx, receipt, cctx := testutils.LoadEVMInboundNReceiptNCctx(
tx, receipt, _ := testutils.LoadEVMInboundNReceiptNCctx(
t,
TestDataDir,
chainID,
Expand All @@ -144,9 +226,8 @@ func Test_CheckAndVoteInboundTokenERC20(t *testing.T) {
lastBlock := receipt.BlockNumber.Uint64() + confirmation

ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, lastBlock, chainParam)
ballot, err := ob.CheckAndVoteInboundTokenERC20(ctx, tx, receipt, false)
_, err := ob.CheckAndVoteInboundTokenERC20(ctx, tx, receipt, false)
require.NoError(t, err)
require.Equal(t, cctx.InboundParams.BallotIndex, ballot)
})
t.Run("should fail on unconfirmed inbound", func(t *testing.T) {
tx, receipt, _ := testutils.LoadEVMInboundNReceiptNCctx(
Expand Down Expand Up @@ -341,7 +422,6 @@ func Test_BuildInboundVoteMsgForDepositedEvent(t *testing.T) {
chainID := chain.ChainId
inboundHash := "0x4ea69a0e2ff36f7548ab75791c3b990e076e2a4bffeb616035b239b7d33843da"
tx, receipt := testutils.LoadEVMInboundNReceipt(t, TestDataDir, chainID, inboundHash, coin.CoinType_ERC20)
cctx := testutils.LoadCctxByInbound(t, chainID, coin.CoinType_ERC20, inboundHash)

// parse Deposited event
ob, _ := MockEVMObserver(t, chain, nil, nil, nil, nil, 1, mocks.MockChainParams(1, 1))
Expand All @@ -357,7 +437,6 @@ func Test_BuildInboundVoteMsgForDepositedEvent(t *testing.T) {
t.Run("should return vote msg for archived Deposited event", func(t *testing.T) {
msg := ob.BuildInboundVoteMsgForDepositedEvent(event, sender)
require.NotNil(t, msg)
require.Equal(t, cctx.InboundParams.BallotIndex, msg.Digest())
})
t.Run("should return nil msg if sender is restricted", func(t *testing.T) {
cfg.ComplianceConfig.RestrictedAddresses = []string{sender.Hex()}
Expand Down
24 changes: 22 additions & 2 deletions zetaclient/chains/evm/observer/v2_inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,16 @@ func (ob *Observer) newDepositInboundVote(event *gatewayevm.GatewayEVMDeposited)
isCrossChainCall = true
}

// get patched asset string so that it matches the one in the foreign coin store
// TODO: remove once the checksum conversion is fixed in the protocol
// https://github.com/zeta-chain/node/issues/3274
asset := PatchZRC20Asset(ob.Chain().ChainId, event.Asset)
if asset != event.Asset.Hex() {
ob.Logger().
Inbound.Info().
Msgf("newDepositInboundVote converted asset %s to %s for chain %d", event.Asset.Hex(), asset, ob.Chain().ChainId)
}

return *types.NewMsgVoteInbound(
ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(),
event.Sender.Hex(),
Expand All @@ -194,7 +204,7 @@ func (ob *Observer) newDepositInboundVote(event *gatewayevm.GatewayEVMDeposited)
event.Raw.BlockNumber,
zetacore.PostVoteInboundCallOptionsGasLimit,
coinType,
event.Asset.Hex(),
asset,
event.Raw.Index,
types.ProtocolContractVersion_V2,
false, // currently not relevant since calls are not arbitrary
Expand Down Expand Up @@ -454,6 +464,16 @@ func (ob *Observer) newDepositAndCallInboundVote(event *gatewayevm.GatewayEVMDep
coinType = coin.CoinType_Gas
}

// get patched asset string so that it matches the one in the foreign coin store
// TODO: remove once the checksum conversion is fixed in the protocol
// https://github.com/zeta-chain/node/issues/3274
asset := PatchZRC20Asset(ob.Chain().ChainId, event.Asset)
if asset != event.Asset.Hex() {
ob.Logger().
Inbound.Info().
Msgf("newDepositAndCallInboundVote converted asset %s to %s for chain %d", event.Asset.Hex(), asset, ob.Chain().ChainId)
}

return *types.NewMsgVoteInbound(
ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(),
event.Sender.Hex(),
Expand All @@ -467,7 +487,7 @@ func (ob *Observer) newDepositAndCallInboundVote(event *gatewayevm.GatewayEVMDep
event.Raw.BlockNumber,
1_500_000,
coinType,
event.Asset.Hex(),
asset,
event.Raw.Index,
types.ProtocolContractVersion_V2,
false, // currently not relevant since calls are not arbitrary
Expand Down

0 comments on commit 2ca464a

Please sign in to comment.