Skip to content
Merged
5 changes: 5 additions & 0 deletions src/pages/developers/tutorials/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
"readTime": "60 min",
"description": "Deposit assets and call universal apps from Sui"
},
"sui-withdraw-and-call": {
"title": "Sui Withdraw & Call",
"readTime": "60 min",
"description": "Withdraw assets and call contracts on Sui"
},
"swap": {
"title": "Swap",
"readTime": "30 min",
Expand Down
226 changes: 226 additions & 0 deletions src/pages/developers/tutorials/sui-withdraw-and-call.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
Interacting with ZetaChain universal apps from the Sui blockchain includes the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence is incomplete.

This tutorial demonstrates how to withdraw tokens to Sui while calling a Sui
contract in the same transaction—enabling seamless cross-chain operations and
powerful DeFi flows.

You'll learn how to:

- Set up a localnet environment with ZetaChain and Sui
- Deploy and configure a Sui contract that responds to ZetaChain calls
- Execute withdrawAndCall() to send tokens and trigger contract logic on Sui

## Prerequisites

Ensure you have installed and configured the following tools before starting:

- [Sui CLI](https://docs.sui.io/references/cli): Required for starting a local
Sui node and interacting with it.
- [Foundry](https://getfoundry.sh/): Needed for encoding payload data using ABI.
- [jq](https://stedolan.github.io/jq/): Required for parsing JSON output from
Sui CLI.

## Contract Overview

The example contract demonstrates how to handle cross-chain interactions between
ZetaChain and Sui. The contract implements a `connected` module that:

- Receives tokens from ZetaChain through the `on_call` function
- Performs a token swap using a mock Cetus DEX implementation
- Transfers the swapped tokens to a specified receiver address

The Sui contract uses `0x2::coin` and a custom `token::TOKEN` type to represent
the transferred asset.

## Clone the Example Project

Begin by cloning the example contracts repository and installing its
dependencies:

```bash
npx zetachain@next new --project call
cd call
yarn
```

## Launch Localnet

Start your local development environment, which sets up instances of ZetaChain
and Sui:

```bash
npx zetachain localnet start
```

Keep this terminal window open. You should see a table displaying the deployment
details, including Gateway module and object IDs.

## Deploy a Contract on Sui
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be moved to a bash script for ease of use. Too many manual pieces for end users

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this. It can be automated for sure, but a user would not get to see the whole process. Just run this script and a list of things a script does.


Navigate to the Sui contract directory and deploy the contract:

```bash
cd sui
```

```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably use ```bash for all CLI snippets.

sui move build --force
```

Get some Sui tokens from the faucet:

```
sui client faucet
```

```
PUBLISHED=$(sui client publish --skip-dependency-verification --json)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No clear explanation of what this is before it's used in multiple commands.

```

```
PACKAGE=$(echo $PUBLISHED | jq -r '.objectChanges[] | select(.type == "published") | .packageId') && echo $PACKAGE
```

This will deploy the contract and store the package ID in the `$PACKAGE`
variable.

## Set Up the Pool

After deployment, you'll need to set up the pool by minting tokens and creating
the initial liquidity.

Get the treasury cap:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here


```bash
TREASURY=$(echo $PUBLISHED | jq -r --arg pkg "$PACKAGE" '.objectChanges[] | select(.type == "created" and .objectType == "0x2::coin::TreasuryCap<\($pkg)::token::TOKEN>") | .objectId') && echo $TREASURY
```

Get the pool ID:

```
POOL=$(echo $PUBLISHED | jq -r --arg pkg "$PACKAGE" '.objectChanges[] | select(.type == "created" and .objectType == "\($pkg)::cetusmock::Pool<0x2::sui::SUI, \($pkg)::token::TOKEN>") | .objectId') && echo $POOL
```

Mint tokens to your address:

```
RECIPIENT=$(sui client active-address) && echo $RECIPIENT
```

```
sui client call \
--package "$PACKAGE" \
--module token \
--function mint_and_transfer \
--args "$TREASURY" 1000000 "$RECIPIENT"
```

Get the token ID:

```
TOKEN=$(sui client objects --json | jq -r --arg pkg "$PACKAGE" '.[].data | select(.type == "0x2::coin::Coin<\($pkg)::token::TOKEN>") | .objectId') && echo $TOKEN
```

Deposit tokens into the pool:

```
sui client call \
--package "$PACKAGE" \
--module cetusmock \
--function deposit \
--type-args "0x2::sui::SUI" "$PACKAGE::token::TOKEN" \
--args "$POOL" "$TOKEN"
```

## Deposit SUI to Gateway

To enable cross-chain operations, you need to deposit SUI tokens to the
ZetaChain gateway. First, get your SUI coin ID:

```
COIN=$(sui client gas --json | jq -r '.[0].gasCoinId') && echo $COIN
```

```
ETH_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
GATEWAY_PACKAGE=0xa3ce10f68ed22d2cbbc31eaa709ee15e2e30348bfc6ff97b7d128d03b679c5c2
GATEWAY_OBJECT=0xe925d4059435083b70bc504ce912202214edd06f693bdc3f9573a996292780c7
```

Then, deposit SUI to the gateway using the gateway addresses from your localnet
output:

```
sui client call \
--package "$GATEWAY_PACKAGE" \
--module gateway \
--function deposit \
--type-args 0x2::sui::SUI \
--args "$GATEWAY_OBJECT" "$COIN" "$ETH_ADDRESS"
```

> **Note**: Make sure to replace the `GATEWAY_PACKAGE` and `GATEWAY_OBJECT`
> values with the ones from your localnet output. These addresses are displayed
> in the table when you start the localnet.

## Prepare Withdraw and Call

Now you can execute the withdraw and call operation. This will withdraw tokens
from ZetaChain to Sui and simultaneously call a contract on Sui.

Get the required contract IDs:

```bash
CONFIG=$(echo $PUBLISHED | jq -r --arg pkg "$PACKAGE" '.objectChanges[] | select(.type == "created" and .objectType == "\($pkg)::cetusmock::GlobalConfig") | .objectId') && echo $CONFIG
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And maybe this as well.

```

```
CLOCK=$(echo $PUBLISHED | jq -r --arg pkg "$PACKAGE" '.objectChanges[] | select(.type == "created" and .objectType == "\($pkg)::cetusmock::Clock") | .objectId') && echo $CLOCK
```

```
PARTNER=$(echo $PUBLISHED | jq -r --arg pkg "$PACKAGE" '.objectChanges[] | select(.type == "created" and .objectType == "\($pkg)::cetusmock::Partner") | .objectId') && echo $PARTNER
```

Prepare the payload:

```
MESSAGE=$RECIPIENT
```

```
TOKEN_TYPE="$PACKAGE::token::TOKEN" && echo $TOKEN_TYPE
```

```
PAYLOAD=$(npx ts-node ./setup/encodeCallArgs.ts "$TOKEN_TYPE" "$CONFIG,$POOL,$PARTNER,$CLOCK" "$MESSAGE") && echo $PAYLOAD
```

## Execute the withdraw and call

Approve Gateway to spend ZRC-20 Sui:

```
cast send 0xd97B1de3619ed2c6BEb3860147E30cA8A7dC9891 "approve(address,uint256)" 0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6 1000000000000000000000000 --private-key ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
```

Withdraw and call:

```
cast send 0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6 "withdrawAndCall(bytes,uint256,address,bytes,(uint256,bool),(address,bool,address,bytes,uint256))" \
"$PACKAGE" \
"1000000" \
"0xd97B1de3619ed2c6BEb3860147E30cA8A7dC9891" \
"$PAYLOAD" \
"(10000,false)" \
"(0xB0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,true,0xC0b86991c6218b36c1d19D4a2e9Eb0cE3606eB49,0xdeadbeef,50000)" \
--private-key ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
```

This transaction will:

1. Withdraw tokens from ZetaChain to Sui
2. Call a Sui contract with the specified parameters

The operation demonstrates how to perform complex cross-chain operations that
combine asset withdrawals with contract calls, enabling sophisticated DeFi
interactions between ZetaChain and Sui.