Zetachain — deploy and interact with your own omnichain contract
Zetachain is a PoS blockchain developed using the Cosmos SDK that hosts Ethereum Virtual Machine (zEVM) which is capable of running omnichain smartcontracts. Those contracts allow you to execute transactions from any supported source to destination networks. Let’s explore how this is done in practice
Download or clone example repository from github
https://github.com/stanisloe/zetachain-swap-example.git
Navigate to the folder and you should see the following structure
I’ve highlighted core files that we’ll go through to better understand what is happening here:
hardhat.config.ts
: This is the configuration file for the Ethereum development environment called Hardhat. It allows you to easily deploy and interact with smart contracts using JavaScript code. If you were to do it from scratch, you would need to configure RPC providers, chain settings, etc. However, in this example, everything is already pre-configured for you, so you don't need to add anything there..env
file ( it won’t be in the downloaded project, but we will create it later ): This is where you will insert your EVM account private key, which Hardhat will use for contract deployment and interaction. Please ensure that this account has some native tokens to cover gas costs.tasks/deploy.ts
andtasks/interact.ts
: These are Hardhat tasks for deploying and interacting with theSwap.sol
smart contract. Later, you'll execute commands to trigger those tasks.Swap.sol
file: This contains the Ethereum Virtual Machine (EVM) compatible smart contract code that will perform cross-chain swap transactions.
Now, let’s prepare our environment for contract deployment.
First, let’s install npm and Node.js if you haven’t done so already. You can follow any of the following guides:
After this is done let’s navigate to downloaded example repository in the command line and run
npm install yarn && yarn && yarn add --dev @uniswap/v2-periphery @uniswap/v2-core
Next, you’ll need to create a file named .env
in the project directory and place the private key from an account that holds Matic Mumbai testnet tokens.
PRIVATE_KEY=<your private key here>
Run
npx hardhat balances
and you should see similar output
EVM: 0xA72745c17596E4Bd4E4424e8d827176087F5870a
BTC: tb1qgxuumr0ctan0x4u8jthcw4gvxz0q5pfhemyazs
┌─────────┬──────────────────┬────────┬─────────┬───────┐
│ (index) │ networkName │ native │ zeta │ zrc20 │
├─────────┼──────────────────┼────────┼─────────┼───────┤
│ 0 │ 'mumbai_testnet' │ '0.58' │ '57.00' │ │
│ 1 │ 'zeta_testnet' │ '5.82' │ '0.00' │ '' │
│ 2 │ 'bsc_testnet' │ '0.10' │ '0.98' │ │
│ 3 │ 'goerli_testnet' │ '0.16' │ '30.00' │ │
│ 4 │ 'btc_testnet' │ '0' │ │ │
└─────────┴──────────────────┴────────┴─────────┴───────┘
Pay attention to your Mumbai and Goerli native balances. If you don’t have matic tokens request them here.
Next compile smart contracts
npx hardhat compile --force
Once everything is compiled we are ready to deploy our contract by running:
npx hardhat deploy --network zeta_testnet
Note the naming for the deploy
task — it’s the same as the task file tasks/deploy.ts
we discussed previously. interact
task will be called in a similar manner later, but with different arguements.
You should see similar output with your account and contract addresses. They will be different from mine.
🔑 Using account: 0xA72745c17596E4Bd4E4424e8d827176087F5870a
🚀 Successfully deployed contract on ZetaChain.
📜 Contract address: 0xFAfE767BB2AbC2B68AE4466FCcbd8afc9d1B7079
🌍 Explorer: https://athens3.explorer.zetachain.com/address/0xFAfE767BB2AbC2B68AE4466FCcbd8afc9d1B7079
Once the contract is deployed it’s time to interact with it. Run the following command
npx hardhat interact --contract 0xFAfE767BB2AbC2B68AE4466FCcbd8afc9d1B7079 --amount 0.2 --network mumbai_testnet --destination goerli_testnet --recipient 0xA72745c17596E4Bd4E4424e8d827176087F5870a
Note that you need to replace contract and recipient arguments. You should see the following output after few minutes
🔑 Using account: 0xA72745c17596E4Bd4E4424e8d827176087F5870a
🚀 Successfully broadcasted a token transfer transaction on mumbai_testnet network.
📝 Transaction hash: 0x6a85f07eef914ddd7eae76355e9d6c12e4d72082f22bbedcbfee56ccfadf5a84
✔ CCTX hash found: 0xabd5a19e33a772086680403028a2a0a4bd528321e64755eb5c9b84c89641754c
ℹ Status updated to "OutboundMined": Remote omnichain contract call completed
✔ CCTX has been finalized on ZetaChain
Let’s inspect what was done byinteract
task and it’s output in more detail.
Transaction hash
📝 Transaction hash: 0x6a85f07eef914ddd7eae76355e9d6c12e4d72082f22bbedcbfee56ccfadf5a84
corresponds to a transfer made from your mumbai test network account to zetachain account on mumbai blockchain called the TSS ( Threshold Signature Scheme ) On every connected network there is such TSS ( actuall addresses for supported chains could be found here ) owned by zetachain team. Typically, you’ll send some tokens and metadata about your desired actions with those tokens to the TSS. In this exeample you have send 0.2 matic tokens and told zetachain to withdraw what is left after fees to your wallet in goerli network.
By sending this Mumbai blockchain transaction you have triggered transaction on the Zetachain blockchain, known as a cross-chain transaction (CCTX), which you can find in the output as well.
✔ CCTX hash found: 0xabd5a19e33a772086680403028a2a0a4bd528321e64755eb5c9b84c89641754c
Now lets investigate it a little bit further. Navigate to ( don’t forget to use your CCTX hash in explorer )
https://athens3.explorer.zetachain.com/cc/tx/0xabd5a19e33a772086680403028a2a0a4bd528321e64755eb5c9b84c89641754c
to explore this CCTX in detail. You should see the following screen.
From it you should be able to see how your omnichain swap was performed:
- This your initial transaction on polygon mumbai blockchain where you interacted with TSS and sent your tokens with metadata about recipient and destination chain
- This is another CCTX on zetachain that will initiate tokens withdrawal from goerli TSS to recipient account
- Deposit transaction hash on destination network
After some time, when zetachain processes your transaction, you will receive tokens in your destination network
To check the balance
npx hardhat balances
Notice that goerli_testnet
native
value increased by 0.01 from the previous run. The rest was payed for the interchain transaction commission to zetachain protocol.
EVM: 0xA72745c17596E4Bd4E4424e8d827176087F5870a
BTC: tb1qgxuumr0ctan0x4u8jthcw4gvxz0q5pfhemyazs
┌─────────┬──────────────────┬────────┬─────────┬───────┐
│ (index) │ networkName │ native │ zeta │ zrc20 │
├─────────┼──────────────────┼────────┼─────────┼───────┤
│ 0 │ 'mumbai_testnet' │ '0.38' │ '57.00' │ │
│ 1 │ 'zeta_testnet' │ '5.82' │ '0.00' │ '' │
│ 2 │ 'bsc_testnet' │ '0.10' │ '0.98' │ │
│ 3 │ 'goerli_testnet' │ '0.17' │ '30.00' │ │
│ 4 │ 'btc_testnet' │ '0' │ │ │
└─────────┴──────────────────┴────────┴─────────┴───────┘
And that’s it. By simply running
npx hardhat deploy --network zeta_testnet
you have deployed your own smart contract that is reusing audited and battle-tested uniswap code base. You do not need to implement all the complex multichain swap logic from scratch.
And by running
npx hardhat interact --contract 0xFAfE767BB2AbC2B68AE4466FCcbd8afc9d1B7079 --amount 0.2 --network mumbai_testnet --destination goerli_testnet --recipient 0xA72745c17596E4Bd4E4424e8d827176087F5870a
you’ve bridged your native mumbai polygon tokens to goerli eth tokens.
One cool feature of omnichain contracts is that they eliminate the need for smart contracts on both source and destination networks. Smart contracts are only deployed on Zetachain. To initiate a cross-chain transaction, you simply send data to the TSS address on the supported source chain. The advantage of TSS being just an account is that it enables the triggering of smart contracts even on chains like Bitcoin/Dogecoin, which lack the capacity or efficiency to support general-purpose smart contracts.
Feel free to explore more from the official docs.