ucs03-zkgm Asset Transfer Tutorial - Solidity
Prerequisites
This tutorial assumes that you have experience creating contracts in Solidity.
The Union team uses Nix to manage developer environments. While this tutorial may mention different developer tools, it will not guide you through setting each one up.
This tutorial uses foundry to create and manage the solidity contract.
This tutorial assumes ucs03-zkgm has been deployed to the EVM you’re deploying your contract to.
Transfer
To demonstrate asset transfers with ucs03, this tutorial will walk you through creating a simple contract that sends UNO to Union.
Project Bootstrapping
Initialize a new foundry project to house the Solidity contract.
forge init ucs03-asset-transfer
This will create a project with the following folder structure.
Directoryucs03-asset-transfer
- foundry.toml
Directorylib
- forge-std
- README.md
Directoryscript
- Counter.s.sol
Directorysrc
- Counter.sol
Directorytest
- Counter.t.sol
- Rename
script/Counter.s.sol
->script/Transfer.s.sol
- Rename
src/Counter.sol
->src/Transfer.sol
. - Delete the
test/
folder as it won’t be used in this example.
Contract Source
This demonstrates creating an interface, Ucs03
to expose the transfer function from the already deployed ucs03-zkgm contract. Using the exposed interface of ucs03-zkgm, this contract has a function transferAsset
to conduct a set transfer of 1 UNO.
This tutorial only takes advantage of the transfer
function from ucs03-zkgm. To see a full list of functions made available by ucs03-zkgm, refer to the solidity contract in our repository
pragma solidity ^0.8.27;
import {IERC20} from "forge-std/interfaces/IERC20.sol";
interface Ucs03 { function transfer( uint32 channelId, bytes calldata receiver, address baseToken, uint256 baseAmount, bytes calldata quoteToken, uint256 quoteAmount, uint64 timeoutHeight, uint64 timeoutTimestamp, bytes32 salt ) external;}
contract Transfer { address public constant zkgm = 0x7B7872fEc715C787A1BE3f062AdeDc82b3B06144; address public constant muno = 0xF2865969cF99A28Bb77e25494fE12D5180fE0efD; bytes32 public constant salt = bytes32("0xF2865969cF99A28Bb77e25494fE1");
function transferAsset() public { IERC20(muno).approve(zkgm, 1000000);
Ucs03(zkgm).transfer( 90, hex"1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", muno, 1000000, "muno", 1000000, 1000000000000, 2737670312, salt ); }}
Contract Running Script
pragma solidity ^0.8.27;
import {Script, console} from "forge-std/Script.sol";import {Transfer} from "../src/Transfer.sol";import {IERC20} from "forge-std/interfaces/IERC20.sol";
contract TransferScript is Script { address public constant UNO = 0xF2865969cF99A28Bb77e25494fE12D5180fE0efD;
function run() public { uint256 privateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(privateKey); Transfer transfer = new Transfer();
IERC20(UNO).transfer(address(transfer), 1500000);
console.log("transferring"); transfer.transferAsset(); console.log("complete"); vm.stopBroadcast(); }}
Deploying the contract
The contract can then be deployed to Holesky as follows.
forge script script/Transfer.s.sol:TransferScript \ --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ --broadcast