Skip to content

Commit 30ecdfb

Browse files
authored
Update tutorials to use the new streamlined abstract UniversalContract-based examples (#755)
1 parent 650dee9 commit 30ecdfb

5 files changed

Lines changed: 27 additions & 71 deletions

File tree

src/pages/developers/standards/nft.mdx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,11 @@ RPC_BASE=$(zetachain q chains show --chain-id 84532 -f rpc)
5959
RPC_ZETACHAIN=$(zetachain q chains show --chain-id 7001 -f rpc)
6060
6161
ZRC20_ETHEREUM=$(zetachain q tokens show -s ETH.ETHSEP -f zrc20)
62-
ZRC20_BASE=$(zetachain q tokens show -s ETH.BASESEP -f zrc20)
62+
ZRC20_BASE=$(zetachain q tokens show -s ETH.BASESEP -f zrc20)
6363
6464
GATEWAY_ETHEREUM=0x0c487a766110c85d301d96e33579c5b317fa4995
6565
GATEWAY_BASE=0x0c487a766110c85d301d96e33579c5b317fa4995
6666
GATEWAY_ZETACHAIN=0x6c533f7fe93fae114d0954697069df33c9b74fd7
67-
UNISWAP_ROUTER=0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe
6867
6968
GAS_LIMIT=1000000
7069
```
@@ -80,8 +79,6 @@ NFT_ZETACHAIN=$(npx tsx commands deploy \
8079
--rpc $RPC_ZETACHAIN \
8180
--private-key $PRIVATE_KEY \
8281
--name ZetaChainUniversalNFT \
83-
--uniswap-router $UNISWAP_ROUTER \
84-
--gateway $GATEWAY_ZETACHAIN \
8582
--gas-limit $GAS_LIMIT | jq -r .contractAddress) && echo $NFT_ZETACHAIN
8683
```
8784

src/pages/developers/standards/token.mdx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,11 @@ RPC_BASE=$(zetachain q chains show --chain-id 84532 -f rpc)
5858
RPC_ZETACHAIN=$(zetachain q chains show --chain-id 7001 -f rpc)
5959
6060
ZRC20_ETHEREUM=$(zetachain q tokens show -s ETH.ETHSEP -f zrc20)
61-
ZRC20_BASE=$(zetachain q tokens show -s ETH.BASESEP -f zrc20)
61+
ZRC20_BASE=$(zetachain q tokens show -s ETH.BASESEP -f zrc20)
6262
6363
GATEWAY_ETHEREUM=0x0c487a766110c85d301d96e33579c5b317fa4995
6464
GATEWAY_BASE=0x0c487a766110c85d301d96e33579c5b317fa4995
6565
GATEWAY_ZETACHAIN=0x6c533f7fe93fae114d0954697069df33c9b74fd7
66-
UNISWAP_ROUTER=0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe
6766
6867
GAS_LIMIT=1000000
6968
```
@@ -79,8 +78,6 @@ ZETACHAIN_TOKEN=$(npx tsx commands deploy \
7978
--rpc $RPC_ZETACHAIN \
8079
--private-key $PRIVATE_KEY \
8180
--name ZetaChainUniversalToken \
82-
--uniswap-router $UNISWAP_ROUTER \
83-
--gateway $GATEWAY_ZETACHAIN \
8481
--gas-limit $GAS_LIMIT | jq -r .contractAddress) && echo $ZETACHAIN_TOKEN
8582
```
8683

src/pages/developers/tutorials/call.mdx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,13 @@ function onCall(
8888

8989
### Making outgoing calls
9090

91-
To call a contract on a connected chain from your Universal App, you must first
92-
approve the Gateway to spend the gas token:
91+
To call a contract on a connected chain from your Universal App, first quote the
92+
destination gas fee for your intended gas limit, pull that fee from the caller,
93+
and approve the Gateway to spend it:
9394

9495
```solidity
96+
(, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(callOptions.gasLimit);
97+
IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee);
9598
IZRC20(zrc20).approve(address(gateway), gasFee);
9699
```
97100

@@ -267,7 +270,6 @@ your connected EVM testnet (for example, Base Sepolia) and the Gateway addresses
267270
for each chain.
268271

269272
```bash
270-
GATEWAY_ZETACHAIN=0x6c533f7fe93fae114d0954697069df33c9b74fd7
271273
GATEWAY_BASE=0x0c487a766110c85d301d96e33579c5b317fa4995
272274

273275
RPC_ZETACHAIN=https://zetachain-athens-evm.blockpi.network/v1/rpc/public
@@ -281,8 +283,7 @@ UNIVERSAL=$(forge create Universal \
281283
--rpc-url $RPC_ZETACHAIN \
282284
--private-key $PRIVATE_KEY \
283285
--broadcast \
284-
--json \
285-
--constructor-args $GATEWAY_ZETACHAIN | jq -r .deployedTo) && echo $UNIVERSAL
286+
--json | jq -r .deployedTo) && echo $UNIVERSAL
286287
```
287288

288289
### Deploy Connected to Base Sepolia
@@ -451,10 +452,9 @@ from the localnet registry:
451452

452453
```bash
453454
RPC=http://localhost:8545
454-
ZRC20_ETHEREUM=$(jq -r '."11155112".chainInfo.gasZRC20' ~/.zetachain/localnet/registry.json) && echo $ZRC20_ETHEREUM
455+
ZRC20_ETHEREUM=$(jq -r '."11155112".zrc20Tokens[] | select(.coinType == "gas" and .originChainId == "11155112") | .address' ~/.zetachain/localnet/registry.json) && echo $ZRC20_ETHEREUM
455456
PRIVATE_KEY=$(jq -r '.private_keys[0]' ~/.zetachain/localnet/anvil.json) && echo $PRIVATE_KEY
456457
GATEWAY_ETHEREUM=$(jq -r '.["11155112"].contracts[] | select(.contractType == "gateway") | .address' ~/.zetachain/localnet/registry.json) && echo $GATEWAY_ETHEREUM
457-
GATEWAY_ZETACHAIN=$(jq -r '.["31337"].contracts[] | select(.contractType == "gateway") | .address' ~/.zetachain/localnet/registry.json) && echo $GATEWAY_ZETACHAIN
458458
```
459459

460460
Deploy the Universal App:
@@ -464,8 +464,7 @@ UNIVERSAL=$(forge create Universal \
464464
--rpc-url $RPC \
465465
--private-key $PRIVATE_KEY \
466466
--broadcast \
467-
--json \
468-
--constructor-args $GATEWAY_ZETACHAIN | jq -r .deployedTo) && echo $UNIVERSAL
467+
--json | jq -r .deployedTo) && echo $UNIVERSAL
469468
```
470469

471470
Deploy the Connected contract:

src/pages/developers/tutorials/hello.mdx

Lines changed: 7 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,10 @@ A Universal App is a contract that implements the `UniversalContract` interface.
5757
// SPDX-License-Identifier: MIT
5858
pragma solidity 0.8.26;
5959
60-
import "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol";
60+
import "@zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol";
6161
6262
contract Universal is UniversalContract {
63-
GatewayZEVM public immutable gateway;
64-
6563
event HelloEvent(string, string);
66-
error Unauthorized();
67-
68-
modifier onlyGateway() {
69-
if (msg.sender != address(gateway)) revert Unauthorized();
70-
_;
71-
}
72-
73-
constructor(address payable gatewayAddress) {
74-
gateway = GatewayZEVM(gatewayAddress);
75-
}
7664
7765
function onCall(
7866
MessageContext calldata context,
@@ -86,10 +74,6 @@ contract Universal is UniversalContract {
8674
}
8775
```
8876

89-
The constructor takes ZetaChain’s Gateway address and stores it in a state
90-
variable. The Gateway is used for making outbound contract calls and token
91-
withdrawals.
92-
9377
A universal contract must implement the `onCall` function. This function is
9478
triggered when the contract receives a call from a connected chain via the
9579
Gateway. The function processes incoming data, which includes:
@@ -109,7 +93,8 @@ In this example, `onCall` decodes the message into a string and emits an event.
10993

11094
`onCall` should only be called by the Gateway to ensure that it is only called
11195
as a response to a call on a connected chain and that you can trust the values
112-
of the function parameters.
96+
of the function parameters. This is enforced by the `onlyGateway` modifier,
97+
which is inherited from `UniversalContract`.
11398

11499
## Option 1: Deploy on Localnet
115100

@@ -160,48 +145,21 @@ The `forge build` command tells Foundry to compile all Solidity smart contracts
160145
within your project, ensuring you're working with the latest compiled versions.
161146
Successful compilation will generate bytecode for your contracts.
162147

163-
To deploy and interact with contracts on the ZetaChain localnet, you'll need the
164-
address of the ZetaChain Gateway contract. This contract acts as the entry point
165-
for cross-chain interactions on ZetaChain.
166-
167-
- While your localnet is still running in its dedicated terminal, carefully
168-
examine its output.
169-
- Copy the Gateway contract address from the localnet terminal output. Look for
170-
the row labeled `gateway` under the `ZETACHAIN` section. It will typically
171-
appear in a format similar to this:
172-
173-
```
174-
| gateway │ '0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6' |
175-
```
176-
177-
Copy only the hexadecimal address (e.g.,
178-
`0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6`). Do not include the single quotes
179-
or any other surrounding text.
180-
181-
Alternatively, run the following command to get the Gateway address
182-
programmatically:
183-
184-
```
185-
GATEWAY_ZETACHAIN=$(jq -r '.["31337"].contracts[] | select(.contractType == "gateway") | .address' ~/.zetachain/localnet/registry.json) && echo $GATEWAY_ZETACHAIN
186-
```
187-
188148
Fetch a private key with pre-funded tokens on the connected chain:
189149

190150
```
191151
PRIVATE_KEY=$(jq -r '.private_keys[0]' ~/.zetachain/localnet/anvil.json) && echo $PRIVATE_KEY
192152
```
193153

194-
Deploy the universal contract and provide the Gateway address in the
195-
constructor:
154+
Deploy the universal contract:
196155

197156
```
198157
UNIVERSAL=$(forge create Universal \
199158
--rpc-url http://localhost:8545 \
200159
--private-key $PRIVATE_KEY \
201160
--evm-version paris \
202161
--broadcast \
203-
--json \
204-
--constructor-args $GATEWAY_ZETACHAIN | jq -r .deployedTo) && echo $UNIVERSAL
162+
--json | jq -r .deployedTo) && echo $UNIVERSAL
205163
```
206164

207165
### Make a Call to the Universal App
@@ -263,16 +221,14 @@ string.
263221

264222
### Deploy the Contract on ZetaChain
265223

266-
Deploy the contract to ZetaChain’s testnet using the Gateway address from the
267-
[Contract Addresses page](/reference/network/contracts/):
224+
Deploy the contract to ZetaChain’s testnet:
268225

269226
```
270227
UNIVERSAL=$(forge create Universal \
271228
--rpc-url https://zetachain-athens-evm.blockpi.network/v1/rpc/public \
272229
--private-key $PRIVATE_KEY \
273230
--broadcast \
274-
--json \
275-
--constructor-args 0x6c533f7fe93fae114d0954697069df33c9b74fd7 | jq -r .deployedTo)
231+
--json | jq -r .deployedTo)
276232
```
277233

278234
### Call a Universal Contract from Base

src/pages/developers/tutorials/swap.mdx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ The Swap contract performs the following steps:
3232

3333
3. Queries the withdrawal gas fee required to send the target token back to the
3434
destination chain.
35-
4. Swaps a portion of the incoming tokens for ZRC-20 gas tokens to cover the
36-
withdrawal fee using Uniswap v2 pools.
35+
4. If withdrawing to a connected chain, swaps a portion of the incoming tokens
36+
for ZRC-20 gas tokens to cover the withdrawal fee using Uniswap v2 pools.
3737
5. Swaps the remaining balance into the target token.
3838
6. Withdraws the swapped tokens to the recipient on the destination chain.
3939

@@ -93,7 +93,7 @@ to perform token swaps across blockchains with a single cross-chain call. Tokens
9393
are received as ZRC-20s, optionally swapped using Uniswap v2 liquidity, and
9494
withdrawn back to a connected chain.
9595

96-
### Universal App entrypoint: on_call
96+
### Universal App entrypoint: onCall
9797

9898
The contract is deployed on ZetaChain and implements `UniversalContract`,
9999
exposing a single entrypoint. Cross-chain deliveries are executed only via the
@@ -145,6 +145,10 @@ gateway.withdraw(
145145
);
146146
```
147147

148+
If the destination gas token (`gasZRC20`) is the same as the target token, the
149+
contract approves a single combined allowance of `out + gasFee` for the Gateway
150+
instead of two separate approvals.
151+
148152
### Funding destination execution from the user’s input
149153

150154
The app provisions destination gas out of the input, so users don’t need to
@@ -260,6 +264,9 @@ SwapHelperLib.swapExactTokensForTokens(
260264
);
261265
```
262266

267+
Note: If `inputToken == gasZRC20`, the contract uses `gasFee` directly (no swap
268+
for gas is required) and only swaps the remaining balance to the target token.
269+
263270
You’re free to replace uniswapRouter and the helper calls with any DEX interface
264271
or custom routing logic—only the ZRC-20 token flow and the Gateway withdraw
265272
semantics are assumed by the rest of the contract.

0 commit comments

Comments
 (0)