The MsgDeployFungibleCoinZRC20
message overwrites current ZRC-20 mapping
Description
The MsgDeployFungibleCoinZRC20
message is used to deploy a new ZRC-20 contract and map it to an ERC-20 or gas token on a foreign chain.
In the ERC-20 token case, the code fails to check to ensure that the ERC-20 token contract address that is passed in (for the foreign chain) does not already have a mapping to a deployed ZRC-20 token contract.
In the gas-token case, the code fails to check to ensure that the foreign chain does not already have a ZRC-20 token contract mapped to it.
Impact
This issue would lead to an already mapped ZRC-20 contract being replaced by a newly deployed one, which would in turn brick the old contract as there currently exists no alternative method to modify the mapping.
Since this message requires a policy type 2 admin account (i.e., a multi-sig) to execute, we have decided that the likelihood of this occurring is low, and thus the impact is also "Low".
Recommendations
In the gas-token case, implement a check in the message handler to ensure that the foreign chain's gas token is not already mapped to a ZRC-20 token contract address.
In the ERC-20 token case, consider removing this functionality entirely, as it is handled by the MsgWhitelistERC20
message already. Alternatively, consider adding a similar check to the above.
Remediation
ZetaChain implemented the suggested fix for this issue in Pull Request #13↗. The checks all follow the below structure.
// Check if gas coin already exists
_, found := k.GetGasCoinForForeignCoin(ctx, chainID)
if found {
return ethcommon.Address{}, types.ErrForeignCoinAlreadyExist
}