Zeta Swap
Overview
High-level overview: In this tutorial you will write a contract that allows users to swap native tokens from one connected chain to another through ZetaChain.
- A
ZetaSwapV2.sol
contract is created and deployed to ZetaChain. - A user wants to swap tMATIC from Polygon Mumbai to gETH on Goerli.
- A user transfers a native gas token (in this example, gETH) to a specific
address (called TSS) on Goerli. The
data
value of the token transfer transaction contains the following information:- address of the ZetaSwapV2 contract on Zetachain
- recipients address (defaults to the sender's address)
- destination token address
- minimal output amount (not covered in this tutorial, set to 0)
- ZetaChain detects the token transfer transaction and triggers the
onCrossChainCall()
function of the ZetaSwapV2 contract. onCrossChainCall()
does the following:- calls the UniswapV2 router contract (Uniswap acontracts already have been
deployed to ZetaChain), specifically
swapExactTokensForTokens
to swap tMATIC represented on ZetaChain as a ZRC20 for gETH also represented as a ZRC20. - calls ZetaChain's
withdraw
to withdraw native gas token (tMATIC) on the destination chain (Polygon Mumbai).
- calls the UniswapV2 router contract (Uniswap acontracts already have been
deployed to ZetaChain), specifically
Set up your environment
This tutorial assumes that you have already completed the setup tutorial or cloned the template Hardhat project.
Install the dependencies:
yarn add --dev @zetachain/zevm-protocol-contracts @zetachain/zevm-example-contracts @uniswap/v2-periphery @uniswap/v2-core
Create a new wallet and request tokens from the testnet faucet if you haven't done so already:
npx hardhat account --save
npx hardhat faucet
Create the contract
loading...
Configure the Hardhat environment
The ZetaSwap contract expects a specific version of the Solidity compiler. Modify the Hardhat config to ensure that the correct version is used.
const config: HardhatUserConfig = {
solidity: "0.8.7",
// ...
};
npx hardhat compile
Write a test for the contract
loading...
Implement helper functions
The test uses a helper function to encode the parameters for the
onCrossChainCall
function. The helper function is defined in the helpers.ts
file.
loading...
The test also uses a helper function to set up the environment for the test. The
helper function is defined in the test.helpers.ts
file.
loading...
Import contracts
The test depends on types from external contracts. Import these contracts to enable Hardhat to compile their types.
loading...
loading...
Configure the Hardhat environment
Take note that the Uniswap contracts require a specific version of Solidity, which differs from the version used for the remaining contracts. Update the Hardhat configuration to include both versions of Solidity.
const config: HardhatUserConfig = {
solidity: {
compilers: [{ version: "0.6.6" /** For uniswap v2 */ }, { version: "0.8.7" }],
},
};
Run the test
npx hardhat test
ZetaSwap tests
zetaSwapV2
Getting uniswapV2Router02 address from mainnet: eth-mainnet.
Getting uniswapV2Factory address from mainnet: eth-mainnet.
Getting weth9 address from mainnet: eth-mainnet.
✔ Should do swap (60ms)
1 passing (9s)
Create a deployment task
loading...
Deploy the contract to the ZetaChain testnet
npx hardhat deploy --network athens
Execute a swap
import { task } from "hardhat/config";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { parseEther } from "@ethersproject/units";
import { getAddress } from "@zetachain/addresses";
import { BigNumber } from "@ethersproject/bignumber";
const ZRC20Addresses = {
goerli: "0x91d18e54DAf4F677cB28167158d6dd21F6aB3921",
"bsc-testnet": "0x13A0c5930C028511Dc02665E7285134B6d11A5f4",
"bitcoin-testnet": "0x48f80608B672DC30DC7e3dbBd0343c5F02C738Eb",
"polygon-mumbai": "0xd97B1de3619ed2c6BEb3860147E30cA8A7dC9891",
};
const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
const [signer] = await hre.ethers.getSigners();
console.log(`🔑 Using account: ${signer.address}\n`);
const prepareData = (zetaSwapContract: string, recipient: string, destinationToken: string, minOutput: BigNumber) => {
const paddedRecipient = hre.ethers.utils.hexlify(hre.ethers.utils.zeroPad(recipient, 32));
const abiCoder = hre.ethers.utils.defaultAbiCoder;
const params = abiCoder.encode(["address", "bytes32", "uint256"], [destinationToken, paddedRecipient, minOutput]);
return `${zetaSwapContract}${params.slice(2)}`;
};
const destinationToken = ZRC20Addresses[args.destination as keyof typeof ZRC20Addresses];
const network = hre.network.name;
const data = prepareData(args.contract, signer.address, destinationToken, BigNumber.from("0"));
const to = getAddress({
address: "tss",
networkName: network,
zetaNetwork: "athens",
});
const value = parseEther(args.amount);
const tx = await signer.sendTransaction({ data, to, value });
console.log(`
🚀 Successfully broadcasted a token transfer transaction on ${network} network.
📝 Transaction hash: ${tx.hash}
💰 Amount: ${args.amount} native ${network} gas tokens
This transaction has been submitted to ${network}, but it may take some time
for it to be processed on ZetaChain. Please refer to ZetaChain's explorer
for updates on the progress of the cross-chain transaction.
🌍 Explorer: https://explorer.zetachain.com/address/${args.contract}?tab=ccTxs
`);
};
task("swap", "Swap tokens")
.addParam("contract", "The address of the swap contract on ZetaChain")
.addParam("amount", "Amount to send to the recipient")
.addParam("destination", "Destination network, like 'goerli'")
.setAction(main);
import "./tasks/swap";
npx hardhat swap --contract 0x74f8e77E9E8AC20B25a2bd358C618494107207De --amount 0.001 --network polygon-mumbai --destination goerli
🔑 Using account: 0x16CeE2D01957e24e6AdE918ce76D5e74a1817EE5
Getting tss address from athens: polygon-mumbai.
🚀 Successfully broadcasted a token transfer transaction on polygon-mumbai network.
📝 Transaction hash: 0xfd723f66d19652b8badd9f6029b2289c744990e6c9986474030e0bf343c8eea5
💰 Amount: 0.001 native polygon-mumbai gas tokens
This transaction has been submitted to polygon-mumbai, but it may take some time
for it to be processed on ZetaChain. Please refer to ZetaChain's explorer
for updates on the progress of the cross-chain transaction.
🌍 Explorer: https://explorer.zetachain.com/address/0x74f8e77E9E8AC20B25a2bd358C618494107207De?tab=ccTxs