Build
Universal EVM
Cross-Chain Transactions

Cross-chain transactions (CCTXs) can be classified into two main types: incoming and outgoing.

Incoming transactions (connected chain → ZetaChain) are initiated on a connected chain and result in a transaction on ZetaChain. An incoming transaction consists of two transactions:

  • Inbound: a transaction is initiated and observed on the connected chain.
  • Outbound: the corresponding transaction is broadcasted and executed on ZetaChain.

Outgoing transactions (ZetaChain → connected chain) are initiated on ZetaChain and result in a transaction on a connected chain. An outgoing transaction consists of two transactions:

  • Inbound: A transaction is initiated and observed on ZetaChain.
  • Outbound: The corresponding transaction is broadcasted and executed on the connected chain.

Tracking a CCTX involves querying ZetaChain's Cosmos SDK HTTP API with an inbound transaction hash to get a CCTX hash. If a CCTX results in another CCTX (for example, an incoming results in an outgoing), the first CCTX hash can be used as a inbound hash to get the second CCTX hash.

Consider an example of making a call from Ethereum Sepolia to a universal app contract on ZetaChain, which triggers an outgoing call from ZetaChain to Polygon Amoy.

In this example a user calls EVM Gateway's depositAndCall to call a universal swap contract on ZetaChain, which swaps incoming tokens for target ZRC-20 tokens and calls ZetaChain's Gateway withdraw function, which triggers a token transfer on Polygon Amoy.

This example involves two CCTXs:

  1. Ethereum Sepolia → ZetaChain Testnet
  2. ZetaChain Testnet → Polygon Amoy

An inbound transaction on Ethereum Sepolia:

https://sepolia.etherscan.io/tx/0x8e925fa63c69bd27a3aa8e30f4c0f1e67e5fd3fedb23339b387b51b1543e55af (opens in a new tab)

Use the inbound transaction hash to get the CCTX 1 hash:

https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x8e925fa63c69bd27a3aa8e30f4c0f1e67e5fd3fedb23339b387b51b1543e55af (opens in a new tab)

Use the CCTX 1 hash (0x542b...11da) as an inbound hash to get CCTX 2 hash:

https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x542b6bd80004f4013b725c2170b9ed01731b8af9dc61bfb5c0534dc2f0d511da (opens in a new tab)

Outbound hash on Polygon Amoy:

https://amoy.polygonscan.com/tx/0x49f67ece0c0b59d58312df91342d46b14496abf2d8a52a1a5ce9f4c6136e8d75 (opens in a new tab)

You can use ZetaChain CLI to track a transaction:

zetachain query cctx --hash 0x8e925fa63c69bd27a3aa8e30f4c0f1e67e5fd3fedb23339b387b51b1543e55af
11155111 → 7001 ✅ OutboundMined
CCTX:     0x542b6bd80004f4013b725c2170b9ed01731b8af9dc61bfb5c0534dc2f0d511da
Tx Hash:  0x8e925fa63c69bd27a3aa8e30f4c0f1e67e5fd3fedb23339b387b51b1543e55af (on chain 11155111)
Tx Hash:  0x08e10a86711981a90715a0d91c05b1a3f940142049d7a57181510375c997f34b (on chain 7001)
Sender:   0x4955a3F38ff86ae92A914445099caa8eA2B9bA32
Receiver: 0x93491dF3516B795321b52Bf0d8F62dc6d7Bf1A57
Message:  000000000000000000000000777915d031d1e8144c90d025c594b3b8bf07a08d0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000144955a3f38ff86ae92a914445099caa8ea2b9ba32000000000000000000000000
Amount:   100000000000000000 Gas tokens
Status:   OutboundMined, Status changed from PendingOutbound to OutboundMined
 
7001 → 80002 ✅ OutboundMined
CCTX:     0x36f41b8ca20bd615b1211de1ff5ec67ea58313a9145628cb25922399472dcc14
Tx Hash:  0x542b6bd80004f4013b725c2170b9ed01731b8af9dc61bfb5c0534dc2f0d511da (on chain 7001)
Tx Hash:  0x49f67ece0c0b59d58312df91342d46b14496abf2d8a52a1a5ce9f4c6136e8d75 (on chain 80002)
Sender:   0x93491dF3516B795321b52Bf0d8F62dc6d7Bf1A57
Receiver: 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32
Amount:   926697400447853988 Gas tokens
Status:   OutboundMined, Status changed from PendingOutbound to OutboundMined

Consider an example of making call from Ethereum Sepolia to a universal app contract on ZetaChain.

In this example a user calls EVM Gateway's depositAndCall to call a universal swap contract on ZetaChain, which swaps incoming tokens for target ZRC-20 tokens, which are transferred to the recipient on ZetaChain.

This example results in a single CCTX: Ethereum Sepolia → ZetaChain Testnet.

An inbound transaction on Ethereum Sepolia:

https://sepolia.etherscan.io/tx/0xfacdad3d12988e1065e32b757d1bbc7e868fb8cbae51c909b3f178027d233f79 (opens in a new tab)

CCTX:

https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0xfacdad3d12988e1065e32b757d1bbc7e868fb8cbae51c909b3f178027d233f79 (opens in a new tab)

If you try querying the API with the CCTX hash as an inbound hash, the API responds with HTTP 404 response, because this CCTX does not trigger another CCTX.

zetachain query cctx --hash 0xfacdad3d12988e1065e32b757d1bbc7e868fb8cbae51c909b3f178027d233f79
11155111 → 7001 ✅ OutboundMined
CCTX:     0x87047470bc90d5bce042c3b375e4b5e0dfdbce3b881421fe37299c0c8dfd27b9
Tx Hash:  0xfacdad3d12988e1065e32b757d1bbc7e868fb8cbae51c909b3f178027d233f79 (on chain 11155111)
Tx Hash:  0x55dfec4c6fa38b1eadd479ea63fabf7481d6857b2e8a54b375ef6a264a00ddb7 (on chain 7001)
Sender:   0x4955a3F38ff86ae92A914445099caa8eA2B9bA32
Receiver: 0x93491dF3516B795321b52Bf0d8F62dc6d7Bf1A57
Message:  000000000000000000000000777915d031d1e8144c90d025c594b3b8bf07a08d0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000144955a3f38ff86ae92a914445099caa8ea2b9ba32000000000000000000000000
Amount:   100000000000000000 Gas tokens
Status:   OutboundMined, Status changed from PendingOutbound to OutboundMined

Consider an example of making call from Ethereum Sepolia to a universal app contract on ZetaChain, which aborts.

In this example a user calls EVM Gateway's depositAndCall to call a universal swap contract on ZetaChain, which swaps incoming tokens for target ZRC-20 tokens, but the amount of supplied tokens is not enough to cover the withdraw gas fee to Polygon Amoy, so the transaction reverts. The amount of tokens is also not sufficient to cover a revert transaction to Ethereum Sepolia, so the transaction aborts.

An inbound transaction on Ethereum Sepolia:

https://sepolia.etherscan.io/tx/0x254d687404ff8f1cd481d2b25866e8c0a68c5d7fde08deaa60e61577752e1466 (opens in a new tab)

CCTX:

https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x254d687404ff8f1cd481d2b25866e8c0a68c5d7fde08deaa60e61577752e1466 (opens in a new tab)

zetachain query cctx --hash 0x254d687404ff8f1cd481d2b25866e8c0a68c5d7fde08deaa60e61577752e1466
11155111 → 7001 ❌ Aborted
CCTX:     0x506981772e198160bbffde947b4c0475861e27adedc60322397db4723eb1db55
Tx Hash:  0x254d687404ff8f1cd481d2b25866e8c0a68c5d7fde08deaa60e61577752e1466 (on chain 11155111)
Tx Hash:  0x89d7f5bd0301bf19724e0257afabdd5df5fc97f967ab796ab4c988be10ef0479 (on chain 7001)
Sender:   0x4955a3F38ff86ae92A914445099caa8eA2B9bA32
Receiver: 0x93491dF3516B795321b52Bf0d8F62dc6d7Bf1A57
Message:  000000000000000000000000777915d031d1e8144c90d025c594b3b8bf07a08d0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000144955a3f38ff86ae92a914445099caa8ea2b9ba32000000000000000000000000
Amount:   1000000 Gas tokens
Status:   Aborted, Status changed from PendingOutbound to Aborted: revert failed
Error:    deposit error: contract call failed: method 'depositAndCall0', contract '0x6c533f7fE93fAE114d0954697069Df33C9B74fD7', args: [{[] 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32 11155111} 0x05BA149A7bd6dC1F937fA9046A9e05C05f3b18b0 1000000 0x93491dF3516B795321b52Bf0d8F62dc6d7Bf1A57 [0 0 0 0 0 0 0 0 0 0 0 0 119 121 21 208 49 209 232 20 76 144 208 37 197 148 179 184 191 7 160 141 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 73 85 163 243 143 248 106 233 42 145 68 69 9 156 170 142 162 185 186 50 0 0 0 0 0 0 0 0 0 0 0 0]]: execution reverted: ret 0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000027556e69737761705632526f757465723a204558434553534956455f494e5055545f414d4f554e5400000000000000000000000000000000000000000000000000: evm transaction execution failed, processing error: outTxGasFee(845181378930000) more than available gas for tx (1000000) | Identifiers : 0x4955a3F38ff86ae92A914445099caa8eA2B9bA32-11155111-11155111-0 : not enough gas
 
7001 ✅ Abort executed
Revert Address:   Reverted to sender address, because revert address is not set
Call on Revert:   false
Abort Address:    0x0000000000000000000000000000000000000000
Revert Message:   3078
Revert Gas Limit: 7000000

An example of making call from Base Sepolia to a universal app contract on ZetaChain, which reverts.

In this example a user calls EVM Gateway's depositAndCall to call a universal swap contract on ZetaChain, which swaps incoming tokens for target ZRC-20 tokens, but the amount of supplied tokens is not enough to cover the withdraw gas fee to Polygon Amoy, so the transaction reverts.

An inbound transaction on Base Sepolia:

https://sepolia.basescan.org/tx/0x9fcff3ff5ec57b7198543e6a204f08447d6dd8dc54d33100e3e79f6deb8dc407 (opens in a new tab)

https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x9fcff3ff5ec57b7198543e6a204f08447d6dd8dc54d33100e3e79f6deb8dc407 (opens in a new tab)

Revert transaction back on Base Sepolia:

https://sepolia.basescan.org/tx/0xd86a5babfb7c3297b98d05d145707010aa8f7b690af151729035c3e2d0567eae (opens in a new tab)

A single transaction can trigger more than one CCTXs.

In this example a single function call on ZetaChain makes multiple Gateway calls to different chains.

https://zetachain-athens.blockpi.network/lcd/v1/public/zeta-chain/crosschain/inboundHashToCctxData/0x3d56898690abb98a514b0b05b799c0d61c0e305a5f962504f3b301adf01b1b34 (opens in a new tab)

zetachain query cctx --hash 0x3d56898690abb98a514b0b05b799c0d61c0e305a5f962504f3b301adf01b1b34
7001 → 11155111 ❌ Reverted
CCTX:     0x177f2aca4a22a217b33e73892cff071383156c0b7099bc2ee5523fc71cdecb39
Tx Hash:  0x3d56898690abb98a514b0b05b799c0d61c0e305a5f962504f3b301adf01b1b34 (on chain 7001)
Tx Hash:  0xd63b0a1e89b761b2fc69af9f9f52a92201a6b21454be3280ff246df93f76e4da (on chain 11155111)
Sender:   0xf4DDF8e6E95ED1faf9B4fCB4C0D81F773E84C79D
Receiver: 0xA3BDB19131133B84B6eF24FdaE16391F236eFaD0
Message:  a777d0dc0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000
Status:   Reverted, Status changed from PendingRevert to Reverted
Error:    outbound failed
 
11155111 → 7001 ✅ Revert executed
Revert Address:   Reverted to sender address, because revert address is not set
Call on Revert:   false
Abort Address:    0x0000000000000000000000000000000000000000
Revert Message:   3078
Revert Gas Limit: 500000
Tx Hash:          0xb195674ab1397c244a17c471834199998f4b0389f52e20276b4adc5dd09cfd2d (on chain 7001)
 
7001 → 80002 ✅ OutboundMined
CCTX:     0xe74667e2c7aea7b9204d73a5a4609fa51e11fafb0c5fa03a8f3e20554f180f95
Tx Hash:  0x3d56898690abb98a514b0b05b799c0d61c0e305a5f962504f3b301adf01b1b34 (on chain 7001)
Tx Hash:  0x131b0a6f197c345c71c9006a95ceeca1b21dcb5252ce1eac73660af107bedd6e (on chain 80002)
Sender:   0xf4DDF8e6E95ED1faf9B4fCB4C0D81F773E84C79D
Receiver: 0xA3BDB19131133B84B6eF24FdaE16391F236eFaD0
Message:  a777d0dc0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000
Status:   OutboundMined, Status changed from PendingOutbound to OutboundMined