Sending ZETA to a Bitcoin network results in BTC being sent instead
Description
There are three different types of coin that can be sent via outgoing transactions, which are CoinType_Zeta
, CoinType_Gas
, and CoinType_ERC20
.
The observer will call go signer.TryProcessOutTx(send, outTxMan, outTxID, chainClient, co.bridge)
on each of the current out transactions, and it is up to the signer implementation for each chain to handle the different coin types. The EVMSigner
correctly handles all the coin types, but the BTCSigner
assumes that all the transactions are of type CoinType_Gas
.
func (signer *BTCSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *OutTxProcessorManager, outTxID string, chainclient ChainClient, zetaBridge *ZetaCoreBridge) {
// [ ... ]
// Zellic: - incorrect assumption of CoinType_Gas here
included, confirmed, _ := btcClient.IsSendOutTxProcessed(send.Index, int(send.GetCurrentOutTxParam().OutboundTxTssNonce), common.CoinType_Gas)
if included || confirmed {
logger.Info().Msgf("CCTX already processed; exit signer")
return
}
// [ ... ]
Impact
If you try to send ZETA to a Bitcoin chain using ZetaConnectorZEVM.send
on the zEVM, it will generate an outgoing CCTX with a coin type of CoinType_Zeta
and an Amount
of the ZETA that was burnt. This will then get picked up by the BTCSigner
and processed as if it was a CoinType_Gas
, which directly sends Amount / 1e8
(the BTC gas coin has decimals of 8 in zEVM) of BTC to the receiver.
This allows someone to burn a tiny fraction of a ZETA (1/1e10) and receive one BTC in return.
Recommendations
The BTCSigner
should reject any transactions that are not of type CoinType_Gas
. The EvmHooks
could check to ensure that the destination chain supports CoinType_Zeta
and could reject any transactions before they reach the inbound tracker.
Remediation
This issue has been acknowledged by ZetaChain, and a fix was implemented in commit 630c515f↗.