Skip to content

Commit bc1bd17

Browse files
committed
fix(docs): improve clarity and structure of USDT0 to FXRP swap guide
1 parent 4648d88 commit bc1bd17

File tree

3 files changed

+136
-103
lines changed

3 files changed

+136
-103
lines changed

docs/fassets/developer-guides/usdt0-fxrp-swap.mdx

Lines changed: 42 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Swap USDT0 to FXRP
33
tags: [intermediate, fassets]
44
slug: usdt0-fxrp-swap
5-
description: Swap USDT0 to FXRP tokens using Uniswap V3 router
5+
description: Swap USDT0 to FXRP using Uniswap V3 router
66
keywords: [fassets, flare-network]
77
---
88

@@ -13,20 +13,22 @@ import Remix from "@site/src/components/remix";
1313

1414
## Overview
1515

16-
In this guide, you will learn how to swap USDT0 to FXRP tokens using the Uniswap V3 router (SparkDEX).
16+
In this guide, you will learn how to swap USDT0 to FXRP using the Uniswap V3 router (SparkDEX).
1717
FXRP is the ERC-20 representation of XRP used by [FAssets](/fassets/overview).
1818

1919
## Prerequisites
2020

2121
Before starting, make sure you have:
2222

2323
- Basic understanding of the [FAssets system](/fassets/overview).
24-
- [Flare Network Periphery Contracts](https://www.npmjs.com/package/@flarenetwork/flare-periphery-contracts) package.
24+
- [Flare Network Periphery Contracts](https://www.npmjs.com/package/@flarenetwork/flare-periphery-contracts) package installed.
2525
- Familiarity with [Uniswap V3 swaps](https://docs.uniswap.org/contracts/v3/guides/swaps/single-swaps).
26-
- Addresses on Flare Mainnet:
27-
- V3 SwapRouter (SparkDEX): [0x8a1E35F5c98C4E85B36B7B253222eE17773b2781](https://flarescan.com/address/0x8a1E35F5c98C4E85B36B7B253222eE17773b2781/contract/14/code).
28-
- USDT0: [0xe7cd86e13AC4309349F30B3435a9d337750fC82D](https://flarescan.com/address/0xe7cd86e13AC4309349F30B3435a9d337750fC82D).
29-
- FXRP: [resolved dynamically from the Asset Manager](/fassets/developer-guides/fassets-fxrp-address).
26+
27+
## Required Addresses on Flare Mainnet
28+
29+
- V3 SwapRouter (SparkDEX): [0x8a1E35F5c98C4E85B36B7B253222eE17773b2781](https://flarescan.com/address/0x8a1E35F5c98C4E85B36B7B253222eE17773b2781/contract/14/code).
30+
- USDT0: [0xe7cd86e13AC4309349F30B3435a9d337750fC82D](https://flarescan.com/address/0xe7cd86e13AC4309349F30B3435a9d337750fC82D).
31+
- FXRP: [resolved dynamically from the Asset Manager](/fassets/developer-guides/fassets-fxrp-address).
3032

3133
## Solidity Uniswap V3 Wrapper Contract
3234

@@ -42,45 +44,42 @@ This Solidity contract wraps the Uniswap V3 router, providing safe token transfe
4244

4345
### Code Explanation
4446

45-
1. Defines the Uniswap V3 router function for swaps, which allows interaction with the Uniswap V3 protocol.
46-
47-
2. `exactInputSingle` function used for direct swaps between two tokens in a single pool.
47+
1. Define the Uniswap V3 router function for swaps, which allows interaction with the Uniswap V3 protocol.
48+
It comes from the [Uniswap V3 periphery](https://github.com/Uniswap/v3-periphery).
4849

49-
3. Uniswap V3 factory interface that returns the factory address responsible for creating pools.
50+
2. Use the Uniswap V3 factory interface to locate a specific pool for a token pair and the fee tier.
5051

51-
4. Uniswap V3 factory interface, used to locate a specific pool for a given token pair and fee tier.
52+
3. Define the Uniswap V3 pool interface that provides liquidity and token details for a given pool.
5253

53-
5. The Uniswap V3 pool interface provides liquidity and token details for a given pool.
54+
4. Create the `UniswapV3Wrapper` contract, which acts as a wrapper around Uniswap V3 to simplify swaps and add safety checks.
5455

55-
6. `UniswapV3Wrapper` contract, which acts as a wrapper around Uniswap V3 to simplify swaps and add safety checks.
56+
5. Use the existing Uniswap V3 SwapRouter on Flare (SparkDEX) as the main entry point for executing swaps.
5657

57-
7. Existing Uniswap V3 SwapRouter on Flare (SparkDEX), used as the main entry point for executing swaps.
58+
6. Store the Uniswap V3 factory in the contract for looking up pools.
5859

59-
8. The Uniswap V3 factory is stored in the contract for looking up pools.
60+
7. Define events that log important actions such as swaps executed, pools checked, and tokens approved.
6061

61-
9. Events, which log important actions such as swaps executed, pools checked, and tokens approved.
62+
8. Create a constructor that initializes the swap router and factory.
6263

63-
10. Constructor that initializes the swap router and factory, ensuring both references are immutable.
64+
9. Check if the pool exists and has liquidity, preventing the swaps execution in empty or non-existent pools.
6465

65-
11. Check if the pool exists and has liquidity, preventing execution of swaps in empty or non-existent pools.
66+
10. Create a swap exact input single function that executes a single-hop swap through the Uniswap V3 router protocol.
6667

67-
12. Swap exact input single function, which executes a single-hop swap through the Uniswap V3 router protocol.
68+
10.1. Check if pool exists, ensuring a valid pool address is returned.
6869

69-
12.1. Check if pool exists, ensuring a valid pool address is returned.
70+
10.2. Check if the pool has liquidity, requiring the available liquidity is greater than zero.
7071

71-
12.2. Check if the pool has liquidity, requiring that the available liquidity is greater than zero.
72+
10.3. Transfer tokens from the user to this contract, using SafeERC20 for secure transfers.
7273

73-
12.3. Transfer tokens from user to this contract, using SafeERC20 for secure transfers.
74+
10.4. Approve the router to spend tokens using the `SafeERC20` library, allowing the router to perform the swap.
7475

75-
12.4. Approve router to spend tokens using the `SafeERC20` library, allowing the router to perform the swap.
76+
10.5. Prepare swap parameters, filling the `ExactInputSingleParams` struct with all necessary details.
7677

77-
12.5. Prepare swap parameters, filling the `ExactInputSingleParams` struct with all necessary details.
78+
10.6. Execute the swap, calling the `swapRouter.exactInputSingle` function to perform the transaction.
7879

79-
12.6. Execute swap, calling `swapRouter.exactInputSingle` function to perform the transaction.
80+
10.7. Emit the swap executed event, logging details about the user, tokens, and amounts.
8081

81-
12.7. Emit swap executed event, logging details about the user, tokens, and amounts.
82-
83-
## Execute the Swap
82+
## Execute the Swap with Hardhat
8483

8584
To execute a swap, you need to deploy the wrapper contract and call `swapExactInputSingle` with the swap parameters.
8685

@@ -93,41 +92,29 @@ To execute a swap, you need to deploy the wrapper contract and call `swapExactIn
9392

9493
### Code Breakdown
9594

96-
1. Contract artifacts are imported, including `IAssetManager`, `UniswapV3Wrapper`, and `ERC20`, which provide access to the deployed contracts.
95+
1. Import contract artifacts, including `IAssetManager`, `UniswapV3Wrapper`, and `ERC20`, which provide access to the deployed contracts.
9796

98-
2. Flare Uniswap V3 addresses (SparkDEX) are defined, specifying the SwapRouter address used for executing swaps.
97+
2. Define Flare Uniswap V3 addresses (SparkDEX), specifying the SwapRouter address used for executing swaps.
9998

100-
3. USDT0 token address on Flare Mainnet, which represents the stablecoin used as the input asset for the swap.
99+
3. Set the USDT0 token address on Flare Mainnet, which represents the stablecoin used as the input asset for the swap.
101100

102-
4. Pool fee tier is set to 500 (0.05%), which defines the fee level of the pool to use on the Uniswap V3 router (SparkDEX).
101+
4. Set the pool fee tier to 500 (0.05%), which defines the fee level of the pool to use on the Uniswap V3 router (SparkDEX).
103102

104-
5. Swap parameters are defined.
103+
5. Define swap parameters.
105104

106105
6. Define the function `deployAndVerifyContract()` that deploys the UniswapV3Wrapper contract and verifies it on the blockchain explorer.
107106

108-
7. The `main()` function is the entry point to execute the complete swap logic.
109-
110-
8. Deploy and verify the `UniswapV3Wrapper` smart contract, retrieving its deployed address for later use.
111-
112-
9. Get the deployer account using `web3.eth.getAccounts()`.
113-
114-
10. Retrieve the FXRP token address dynamically from the Asset Manager contract.
115-
116-
11. Define USDT0 and FXRP contract instances.
117-
118-
12. Check the deployer account's initial balances of USDT0 and FXRP.
119-
120-
13. Verify that there is enough USDT0 to perform the swap.
107+
7. Create the `setupAndInitializeTokens()` function that prepares accounts and ERC20 contracts.
121108

122-
14. Check the Uniswap V3 pool using the wrapper contract to ensure that the USDT0/FXRP pool exists and has liquidity.
109+
8. Define the `verifyPoolAndLiquidity()` function which ensures the USDT0/FXRP pool exists and is usable.
123110

124-
15. Approve the USDT0 token to the wrapper contract, allowing it to spend the tokens on behalf of the deployer.
111+
9. Create the `approveUsdt0ForSwap()` function that approves the wrapper contract to spend USDT0 on behalf of the deployer.
125112

126-
16. Execute the swap using the UniswapV3Wrapper contract's `swapExactInputSingle` method.
113+
10. Create the `executeSparkDexSwap()` function that executes the swap on SparkDEX using the Uniswap V3 wrapper.
127114

128-
17. Extract the swap result by checking the new FXRP balance and calculating the difference from the initial balance.
115+
11. Create the `checkFinalBalances()` function that verifies the swap results.
129116

130-
18. Check final balances after the swap to verify execution.
117+
12. Create the `main()` function that orchestrates the entire flow of the swap.
131118

132119
### Run the Script
133120

@@ -145,11 +132,12 @@ This script is included in the [Flare Hardhat Starter Kit](/network/guides/hardh
145132

146133
In this guide, you learned how to swap USDT0 to FXRP using the Uniswap V3 router (SparkDEX).
147134

148-
:::tip[What's next]
135+
:::tip
149136

150137
To continue your FAssets development journey, you can:
151138

152-
- Learn how to [mint FAssets using the executor](/fassets/developer-guides/fassets-mint-executor).
139+
- Learn how to [mint FXRP](/fassets/developer-guides/fassets-mint).
153140
- Understand how to [redeem FXRP](/fassets/developer-guides/fassets-redeem).
141+
- Explore [FAssets system settings](/fassets/operational-parameters).
154142

155143
:::

examples/developer-hub-javascript/uniswapV3Wrapper.ts

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ async function deployAndVerifyContract() {
4040
address: uniswapV3WrapperAddress,
4141
constructorArguments: args,
4242
});
43-
} catch (e: unknown) {
43+
} catch (e: any) {
4444
console.log(e);
4545
}
4646

@@ -49,21 +49,15 @@ async function deployAndVerifyContract() {
4949
return uniswapV3Wrapper;
5050
}
5151

52-
// 7. The main function to execute the swap
53-
async function main() {
54-
// 8. Deploy and verify the UniswapV3 wrapper smart contract and get its address
55-
const uniswapV3Wrapper: UniswapV3WrapperInstance =
56-
await deployAndVerifyContract();
57-
const uniswapV3WrapperAddress = await uniswapV3Wrapper.address;
58-
59-
// 9. Get the deployer account
52+
// 7. Function to setup and initialize tokens
53+
async function setupAndInitializeTokens() {
6054
const accounts = await web3.eth.getAccounts();
6155
const deployer = accounts[0];
6256

6357
console.log("Deployer:", deployer);
6458
console.log("Total accounts available:", accounts.length);
6559

66-
// 10. Get the FXRP address on Flare (from the Asset Manager)
60+
// FXRP address on Flare (from asset manager)
6761
const assetManager = await getAssetManagerFXRP();
6862
const FXRP = await assetManager.fAsset();
6963

@@ -74,11 +68,10 @@ async function main() {
7468
console.log("Amount Out Min:", AMOUNT_OUT_MIN.toString());
7569
console.log("");
7670

77-
// 11. Define the USDT0 and FXRP token addresses
7871
const usdt0: ERC20Instance = await ERC20.at(USDT0);
7972
const fxrp: ERC20Instance = await ERC20.at(FXRP);
8073

81-
// 12. Check initial balances
74+
// Check initial balances
8275
const initialUsdt0Balance = BigInt(
8376
(await usdt0.balanceOf(deployer)).toString(),
8477
);
@@ -89,7 +82,7 @@ async function main() {
8982
console.log("Initial USDT0 balance:", initialUsdt0Balance.toString());
9083
console.log("Initial FXRP balance:", initialFxrpBalance.toString());
9184

92-
// 13. Check if there is enough USDT0 to perform the swap
85+
// Check if there are enough USDT0
9386
const amountInBN = AMOUNT_IN;
9487
if (initialUsdt0Balance < amountInBN) {
9588
console.log(
@@ -101,11 +94,20 @@ async function main() {
10194
console.log(
10295
"Please ensure you have sufficient USDT0 tokens to perform the swap.",
10396
);
104-
return;
97+
throw new Error("Insufficient USDT0 balance");
10598
}
10699

107-
// 14 Check Uniswap V3 pool using wrapper if it exists and has liquidity
108-
console.log("\n=== Step 1: Pool Verification ===");
100+
return { deployer, usdt0, fxrp, initialUsdt0Balance, initialFxrpBalance };
101+
}
102+
103+
// 8. Function to verify the pool and liquidity
104+
async function verifyPoolAndLiquidity(
105+
uniswapV3Wrapper: UniswapV3WrapperInstance,
106+
) {
107+
console.log("\n=== Pool Verification ===");
108+
const assetManager = await getAssetManagerFXRP();
109+
const FXRP = await assetManager.fAsset();
110+
109111
const poolInfo = await uniswapV3Wrapper.checkPool(USDT0, FXRP, FEE);
110112
console.log("Pool info:", poolInfo);
111113
const poolAddress = poolInfo.poolAddress;
@@ -119,26 +121,38 @@ async function main() {
119121
if (poolAddress === "0x0000000000000000000000000000000000000000") {
120122
console.log("❌ Pool does not exist for this token pair and fee tier");
121123
console.log("Please check if the USDT0/FXRP pool exists on SparkDEX");
122-
return;
124+
throw new Error("Pool does not exist");
123125
}
124126

125127
if (!hasLiquidity) {
126128
console.log("❌ Pool exists but has no liquidity");
127-
return;
129+
throw new Error("Pool has no liquidity");
128130
}
129131

130132
console.log("✅ Pool verification successful!");
133+
return { poolAddress, hasLiquidity, liquidity };
134+
}
131135

132-
// 15. Approve USDT0 to wrapper contract to spend the tokens
133-
console.log("\n=== Step 2: Token Approval ===");
136+
// 9. Function to approve USDT0 for the swap
137+
async function approveUsdt0ForSwap(
138+
usdt0: ERC20Instance,
139+
uniswapV3WrapperAddress: string,
140+
) {
141+
console.log("\n=== Token Approval ===");
134142
const approveTx = await usdt0.approve(
135143
uniswapV3WrapperAddress,
136144
AMOUNT_IN.toString(),
137145
);
138146
console.log("✅ USDT0 approved to wrapper contract", approveTx);
147+
return approveTx;
148+
}
149+
150+
// 10. Function to execute the SparkDEX swap
151+
async function executeSparkDexSwap(uniswapV3Wrapper: UniswapV3WrapperInstance) {
152+
console.log("\n=== Execute SparkDEX Swap ===");
153+
const assetManager = await getAssetManagerFXRP();
154+
const FXRP = await assetManager.fAsset();
139155

140-
// 16. Execute swap using the Uniswap V3 wrapper contract
141-
console.log("\n=== Step 3: Execute SparkDEX Swap ===");
142156
const deadline = Math.floor(Date.now() / 1000) + 20 * 60; // 20 minutes
143157
console.log("Deadline:", deadline);
144158

@@ -150,21 +164,27 @@ async function main() {
150164
AMOUNT_IN.toString(),
151165
AMOUNT_OUT_MIN.toString(),
152166
deadline,
153-
0, // sqrtPriceLimitX96 = 0 (no limit)
167+
0, // sqrtPriceLimitX96 = 0 (no limit for the price)
168+
// https://docs.uniswap.org/contracts/v3/guides/swaps/single-swaps#swap-input-parameters
154169
);
155170

156171
console.log("Transaction submitted:", swapTx);
157172

158-
await swapTx.receipt;
173+
const swapReceipt = await swapTx.receipt;
159174
console.log("✅ SparkDEX swap executed successfully!");
160175

161-
// 17. Extract amount out from events or calculate from balance change
162-
const finalFxrpBalance = BigInt((await fxrp.balanceOf(deployer)).toString());
163-
const amountOut = finalFxrpBalance - initialFxrpBalance;
164-
console.log("Amount out:", amountOut.toString());
176+
return { swapTx, swapReceipt };
177+
}
165178

166-
// 18. Check final balances to verify the swap
167-
console.log("\n=== Step 4: Final Balances ===");
179+
// 11. Function to check the final balances
180+
async function checkFinalBalances(
181+
usdt0: ERC20Instance,
182+
fxrp: ERC20Instance,
183+
deployer: string,
184+
initialUsdt0Balance: bigint,
185+
initialFxrpBalance: bigint,
186+
) {
187+
console.log("\n=== Final Balances ===");
168188
const finalUsdt0Balance = BigInt(
169189
(await usdt0.balanceOf(deployer)).toString(),
170190
);
@@ -182,6 +202,31 @@ async function main() {
182202
"FXRP received:",
183203
(finalFxrpBalanceAfter - initialFxrpBalance).toString(),
184204
);
205+
206+
return { finalUsdt0Balance, finalFxrpBalanceAfter };
207+
}
208+
209+
// 12. The main function to execute the complete swap logic and verify the results
210+
async function main() {
211+
const uniswapV3Wrapper: UniswapV3WrapperInstance =
212+
await deployAndVerifyContract();
213+
214+
const { deployer, usdt0, fxrp, initialUsdt0Balance, initialFxrpBalance } =
215+
await setupAndInitializeTokens();
216+
217+
await verifyPoolAndLiquidity(uniswapV3Wrapper);
218+
219+
await approveUsdt0ForSwap(usdt0, uniswapV3Wrapper.address);
220+
221+
await executeSparkDexSwap(uniswapV3Wrapper);
222+
223+
await checkFinalBalances(
224+
usdt0,
225+
fxrp,
226+
deployer,
227+
initialUsdt0Balance,
228+
initialFxrpBalance,
229+
);
185230
}
186231

187232
main().catch((error) => {

0 commit comments

Comments
 (0)