Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: hardcode erc20 asset strings to align with the data in foreign coin store #3273

Merged
merged 7 commits into from
Dec 10, 2024
81 changes: 78 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,76 @@ import (
"github.com/zeta-chain/node/zetaclient/zetacore"
)

var (
// erc20AddressToForeignCoinAssetMap maps the chain id and foreign ERC20 address to the coin asset string
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
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",
// ULTI.ETH
ethcommon.HexToAddress("0x0E7779e698052f8fe56C415C3818FCf89de9aC6D"): "0x0E7779e698052f8fe56C415C3818FCf89de9aC6D",
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
},

// BSC mainnet
chains.BscMainnet.ChainId: {
// USDC.BSC
ethcommon.HexToAddress("0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d"): "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
// USDT.BSC
ethcommon.HexToAddress("0x55d398326f99059ff775485246999027b3197955"): "0x55d398326f99059ff775485246999027b3197955",
// ULTI.BSC
ethcommon.HexToAddress("0x0E7779e698052f8fe56C415C3818FCf89de9aC6D"): "0x0E7779e698052f8fe56C415C3818FCf89de9aC6D",
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
},

// 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",
},

// Base mainnet
chains.BaseMainnet.ChainId: {
// USDC.BASE
ethcommon.HexToAddress("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"): "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
},
}
)

// ERC20AddressToForeignCoinAsset
func ERC20AddressToForeignCoinAsset(chainID int64, erc20Address ethcommon.Address) string {
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
addressToAsset, found := erc20AddressToForeignCoinAssetMap[chainID]
switch {
case found:
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
// 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()
default:
// 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 +743,15 @@ 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
}

// convert erc20Address to asset in foreign coin store to avoid checksum mismatch
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
asset := ERC20AddressToForeignCoinAsset(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 +765,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
101 changes: 101 additions & 0 deletions zetaclient/chains/evm/observer/inbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,114 @@ 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_ERC20AddressToForeignCoinAsset(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",
},
{
name: "ULTI.ETH",
chainID: chains.Ethereum.ChainId,
erc20Address: ethcommon.HexToAddress("0x0E7779e698052f8fe56C415C3818FCf89de9aC6D"),
assetString: "0x0E7779e698052f8fe56C415C3818FCf89de9aC6D",
},
// 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",
},
{
name: "ULTI.BSC",
chainID: chains.BscMainnet.ChainId,
erc20Address: ethcommon.HexToAddress("0x0E7779e698052f8fe56C415C3818FCf89de9aC6D"),
assetString: "0x0E7779e698052f8fe56C415C3818FCf89de9aC6D",
},
// 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",
},
// Base Mainnet
{
name: "USDC.BASE",
chainID: chains.BaseMainnet.ChainId,
erc20Address: ethcommon.HexToAddress("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"),
assetString: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
asset := observer.ERC20AddressToForeignCoinAsset(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
20 changes: 18 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,14 @@ func (ob *Observer) newDepositInboundVote(event *gatewayevm.GatewayEVMDeposited)
isCrossChainCall = true
}

// convert erc20Address to asset in foreign coin store to avoid checksum mismatch
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
asset := ERC20AddressToForeignCoinAsset(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 +202,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 +462,14 @@ func (ob *Observer) newDepositAndCallInboundVote(event *gatewayevm.GatewayEVMDep
coinType = coin.CoinType_Gas
}

// convert erc20Address to asset in foreign coin store to avoid checksum mismatch
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
asset := ERC20AddressToForeignCoinAsset(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 +483,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
Loading