Skip to content

Commit a705fe4

Browse files
committed
refactor(docs): update FAssets redemption guide and contract to include FXRP approval process and new asset manager address
1 parent 5ab03e4 commit a705fe4

File tree

2 files changed

+107
-70
lines changed

2 files changed

+107
-70
lines changed

docs/fassets/developer-guides/4-fassets-redeem.mdx

Lines changed: 71 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ The following example demonstrates how to redeem FAssets using the `AssetManager
3737
### Code Breakdown
3838

3939
1. Define the asset manager contract address to interact with it.
40-
2. Get the asset manager settings to calculate the redeemed amount; for that, you need to get the `lotSizeAMG` and `assetDecimals` from the asset manager [settings](/fassets/developer-guides/fassets-settings-solidity).
40+
2. Approve FAssets (FXRP) tokens for redemption.
4141
3. Redeem the FAssets using the [`redeem`](/fassets/reference/IAssetManager#redeem) function by specifying the number of lots to redeem and the underlying chain address.
42+
4. Retrieve the asset manager settings to calculate the redeemed amount; for this, you need to obtain the `lotSizeAMG` and `assetDecimals` from the asset manager settings [document](/fassets/developer-guides/fassets-settings-solidity).
4243

4344
:::info
4445
In this example, you are not using the executor vault address, but you can use it to redeem FAssets on behalf of another address.
@@ -55,7 +56,7 @@ Create a new file, for example, `scripts/fassets/redeem.ts` and add the followin
5556
At first, you need to import the required dependencies and smart contract TypeScript types:
5657

5758
```typescript
58-
import { ethers, run } from "hardhat";
59+
import { ethers, web3, run } from "hardhat";
5960
import { formatUnits } from "ethers";
6061

6162
import {
@@ -72,14 +73,27 @@ Define the constants:
7273
- `ASSET_MANAGER_ADDRESS` - asset manager address;
7374
- `LOTS_TO_REDEEM` - the number of lots to redeem;
7475
- `UNDERLYING_ADDRESS` - underlying chain address where the redeemed asset will be sent;
75-
- `FXRP_TOKEN_ADDRESS` - FXRP token address.
7676

7777
```typescript
78-
// AssetManager address on Songbird Testnet Coston network
79-
const ASSET_MANAGER_ADDRESS = "0x56728e46908fB6FcC5BCD2cc0c0F9BB91C3e4D34";
78+
// AssetManager address on Flare Testnet Coston2 network
79+
const ASSET_MANAGER_ADDRESS = "0xDeD50DA9C3492Bee44560a4B35cFe0e778F41eC5";
8080
const LOTS_TO_REDEEM = 1;
8181
const UNDERLYING_ADDRESS = "rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm";
82-
const FXRP_TOKEN_ADDRESS = "0x36be8f2e1CC3339Cf6702CEfA69626271C36E2fd";
82+
```
83+
84+
### Import Contract Artifacts
85+
86+
Import the contract artifacts to interact with the smart contracts:
87+
88+
- `FAssetsRedeem` - the `FAssetsRedeem` contract;
89+
- `IAssetManager` - the asset manager interface;
90+
- `IERC20` - the `IERC20` contract for FXRP token;
91+
92+
```typescript
93+
const FAssetsRedeem = artifacts.require("FAssetsRedeem");
94+
95+
const IAssetManager = artifacts.require("IAssetManager");
96+
const IERC20 = artifacts.require("IERC20");
8397
```
8498

8599
### Deploy and Verify the Redeem Contract
@@ -88,15 +102,18 @@ Deploy and verify the smart contract providing the asset manager address as a co
88102

89103
```typescript
90104
async function deployAndVerifyContract() {
91-
const FAssetsRedeem = artifacts.require("FAssetsRedeem");
92-
const args = [ASSET_MANAGER_ADDRESS];
105+
// Get FXRP address first
106+
const fxrpAddress = await getFXRPAddress();
107+
console.log("FXRP address:", fxrpAddress);
108+
109+
const args = [ASSET_MANAGER_ADDRESS, fxrpAddress];
93110
const fAssetsRedeem: FAssetsRedeemInstance = await FAssetsRedeem.new(...args);
94111

95112
const fAssetsRedeemAddress = await fAssetsRedeem.address;
96113

97114
try {
98115
await run("verify:verify", {
99-
address: fAssetsRedeemAddress,
116+
address: fAssetsRedeem.address,
100117
constructorArguments: args,
101118
});
102119
} catch (e: any) {
@@ -109,36 +126,31 @@ async function deployAndVerifyContract() {
109126
}
110127
```
111128

112-
### Transfer FXRP to the Redeem Contract
129+
### Approve the FXRP transfer to the Redeem Contract
113130

114-
To redeem FAssets, you must transfer a sufficient amount of FXRP to the `FAssetsRedeem` contract address after it is deployed, as it acts as the invoker during the redemption process.
131+
To redeem FAssets, you must approve a sufficient amount of transfer of FXRP to the `FAssetsRedeem` contract address after it is deployed, as it acts as the invoker during the redemption process.
115132

116133
```typescript
117-
async function transferFXRP(
118-
fAssetsRedeemAddress: string,
119-
amountToRedeem: number,
120-
) {
121-
// Get FXRP token contract
122-
const fxrp = (await ethers.getContractAt(
123-
"IERC20",
124-
FXRP_TOKEN_ADDRESS,
125-
)) as ERC20Instance;
126-
127-
// Transfer FXRP to the deployed contract
128-
console.log("Transferring FXRP to contract...");
129-
const transferTx = await fxrp.transfer(fAssetsRedeemAddress, amountToRedeem);
130-
await transferTx.wait();
131-
console.log("FXRP transfer completed");
134+
async function approveFAssets(fAssetsRedeem: any, amountToRedeem: string) {
135+
console.log("Approving FAssetsRedeem contract to spend FXRP...");
136+
const fxrpAddress = await getFXRPAddress();
137+
const fxrp: ERC20Instance = await IERC20.at(fxrpAddress);
138+
139+
const approveTx = await fxrp.approve(
140+
await fAssetsRedeem.address,
141+
amountToRedeem,
142+
);
143+
console.log("FXRP approval completed");
132144
}
133145
```
134146

135147
:::warning
136-
In a production environment, you should use a more secure method to transfer FXRP to a smart contract.
148+
In a production environment, it is recommended to use a more secure method for approving the transfer of FXRP to a smart contract.
137149
:::
138150

139151
### Parse the Redemption Events
140152

141-
During the redemption process, the `AssetManager` emits an events:
153+
During the redemption process, the `AssetManager` emits events:
142154

143155
- [`RedemptionRequested`](/fassets/reference/IAssetManagerEvents#redemptionrequested) - holds the agent vault address, redemption request id, the amount of FAssets to redeem, and other important information.
144156
- [`RedemptionTicketCreated`](/fassets/reference/IAssetManagerEvents#redemptionticketcreated) - holds the redemption ticket information updated during the redemption process.
@@ -148,7 +160,7 @@ To parse the redemption events, you can use the following function:
148160
```typescript
149161
async function parseRedemptionEvents(
150162
transactionReceipt: any,
151-
fAssetsRedeem: FAssetsRedeemInstance,
163+
fAssetsRedeem: any,
152164
) {
153165
console.log("\nParsing events...", transactionReceipt.rawLogs);
154166

@@ -185,12 +197,12 @@ async function parseRedemptionEvents(
185197

186198
### Redeeming FAssets
187199

188-
To put it all together you can use the following function to deploy the contract, transfer FXRP to it, redeem the FAssets, and parse the redemption events:
200+
To put it alltogether you can use the following function to deploy the contract, transfer FXRP to it, redeem the FAssets, and parse the redemption events:
189201

190202
```typescript
191203
async function main() {
192204
// Deploy and verify the contract
193-
const fAssetsRedeem: FAssetsRedeemInstance = await deployAndVerifyContract();
205+
const fAssetsRedeem = await deployAndVerifyContract();
194206

195207
// Get the lot size and decimals to calculate the amount to redeem
196208
const settings = await fAssetsRedeem.getSettings();
@@ -200,21 +212,27 @@ async function main() {
200212
console.log("Asset decimals:", decimals.toString());
201213

202214
// Calculate the amount to redeem according to the lot size and the number of lots to redeem
203-
const amountToRedeem = Number(lotSize) * Number(LOTS_TO_REDEEM);
215+
const amountToRedeem = web3.utils
216+
.toBN(lotSize)
217+
.mul(web3.utils.toBN(LOTS_TO_REDEEM));
204218
console.log(
205-
`Required FXRP amount ${formatUnits(amountToRedeem, Number(decimals))} FXRP`,
219+
`Required FXRP amount ${formatUnits(amountToRedeem.toString(), Number(decimals))} FXRP`,
206220
);
207221
console.log(`Required amount in base units: ${amountToRedeem.toString()}`);
208222

209-
// Transfer FXRP to the contract
210-
await transferFXRP(fAssetsRedeem.address, amountToRedeem);
223+
// Approve FXRP for redemption
224+
await approveFAssets(fAssetsRedeem, amountToRedeem.toString());
211225

212226
// Call redeem function and wait for transaction
213-
const tx = await fAssetsRedeem.redeem(LOTS_TO_REDEEM, UNDERLYING_ADDRESS);
214-
console.log("TX receipt", tx.receipt);
227+
const redeemTx = await fAssetsRedeem.redeem(
228+
LOTS_TO_REDEEM,
229+
UNDERLYING_ADDRESS,
230+
);
231+
// const receipt = await tx.wait();
232+
console.log("Redeem transaction receipt", redeemTx);
215233

216-
// Parse events from the transaction
217-
await parseRedemptionEvents(tx.receipt, fAssetsRedeem);
234+
// // Parse events from the transaction
235+
await parseRedemptionEvents(redeemTx.receipt, fAssetsRedeem);
218236
}
219237

220238
main().catch((error) => {
@@ -228,7 +246,7 @@ main().catch((error) => {
228246
To run the script, use the [Flare Hardhat Starter Kit](/network/guides/hardhat-foundry-starter-kit) with the following command:
229247

230248
```bash
231-
npx hardhat run scripts/fassets/getLotSize.ts --network coston
249+
npx hardhat run scripts/fassets/getLotSize.ts --network coston2
232250
```
233251

234252
Once the script is executed, two events hold the important information:
@@ -257,18 +275,18 @@ Arguments: Result(12) [
257275

258276
When decoding an event, the most important data from the event is:
259277

260-
- agent vault address that will redeem the FAssets is `0x3c831Fe4417bEFFAc721d24996985eE2dd627053`;
261-
- redeemer address is `0xCA7C9fBbA56E44C508bcb4872775c5fEd169cDb3`;
262-
- redemption ticket id is `1898730`;
263-
- underlying chain address is `rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm`;
264-
- amount of FAssets to redeem is `20000000`;
265-
- redemption fee is `20000`;
278+
- The agent vault address that will redeem the FAssets is `0x3c831Fe4417bEFFAc721d24996985eE2dd627053`;
279+
- The redeemer address is `0xCA7C9fBbA56E44C508bcb4872775c5fEd169cDb3`;
280+
- The redemption ticket id is `1898730`;
281+
- The underlying chain address is `rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm`;
282+
- The amount of FAssets to redeem is `20000000`;
283+
- The redemption fee is `20000`;
266284

267-
You can see the full event description [here](/fassets/reference/IAssetManagerEvents#redemptionrequested) section.
285+
You can view the full event description [here](/fassets/reference/IAssetManagerEvents#redemptionrequested).
268286

269287
#### [`RedemptionTicketUpdated`](/fassets/reference/IAssetManagerEvents#redemptionticketupdated)
270288

271-
The event `RedemptionTicketUpdated` holds the redemption ticket information like agent vault address, redemption ticket ID and the value of the redemption ticket in underlying chain currency.
289+
The event `RedemptionTicketUpdated` contains the redemption ticket information, including the agent vault address, redemption ticket ID, and the value of the redemption ticket in the underlying chain currency.
272290

273291
For every minting, a redemption ticket is created, and during the redemption process, the redemption ticket is updated with the new redemption status.
274292

@@ -283,18 +301,18 @@ Arguments: Result(3) [
283301

284302
Once decoding the most important data from the event is:
285303

286-
- agent vault address that will redeem the FAssets is `0x3c831Fe4417bEFFAc721d24996985eE2dd627053`;
287-
- redemption ticket id is `870`;
288-
- value of the redemption ticket in underlying chain currency is `3440000000` (partially redeemed).
304+
- The agent vault address that will redeem the FAssets is `0x3c831Fe4417bEFFAc721d24996985eE2dd627053`;
305+
- The redemption ticket id is `870`;
306+
- The value of the redemption ticket in underlying chain currency is `3440000000` (partially redeemed).
289307

290308
You can read the full event description [here](/fassets/reference/IAssetManagerEvents#redemptionticketupdated).
291309

292310
### Agent Process
293311

294-
The FAssets agent should perform the redemption, and the user needs to get the redeemed assets from the agent.
312+
The FAssets agent should perform the redemption, and the user must retrieve the redeemed assets from the agent.
295313

296314
If the agent is unable to redeem the assets on the underlying chain in the specified time.
297-
In that case, the user can execute the [`redemptionPaymentDefault`](/fassets/reference/IAssetManager#redemptionpaymentdefault) function to receive compensation from agent's collateral.
315+
In that case, the user can execute the [`redemptionPaymentDefault`](/fassets/reference/IAssetManager#redemptionpaymentdefault) function to receive compensation from the agent's collateral.
298316

299317
If the agent rejects the redemption request and no other agent takes over the redemption, the redeemer or appointed executor calls [`rejectedRedemptionPaymentDefault`](/fassets/reference/IAssetManager#rejectedredemptionpaymentdefault) method and receives payment in collateral.
300318
The agent can also call default if the redeemer is unresponsive to payout the redeemer and free the remaining collateral.
Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,62 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.0;
33

4-
import {IAssetManager} from "@flarenetwork/flare-periphery-contracts/coston/IAssetManager.sol";
5-
import {AssetManagerSettings} from "@flarenetwork/flare-periphery-contracts/coston/userInterfaces/data/AssetManagerSettings.sol";
4+
import {IAssetManager} from "@flarenetwork/flare-periphery-contracts/coston2/IAssetManager.sol";
5+
import {AssetManagerSettings} from "@flarenetwork/flare-periphery-contracts/coston2/userInterfaces/data/AssetManagerSettings.sol";
6+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
67

78
contract FAssetsRedeem {
89
// 1. Use the AssetManager contract
910
IAssetManager public immutable assetManager;
11+
IERC20 public immutable underlyingToken;
1012

11-
constructor(address _assetManager) {
13+
address public immutable fAssetToken;
14+
15+
constructor(address _assetManager, address _fAssetToken) {
1216
assetManager = IAssetManager(_assetManager);
17+
fAssetToken = _fAssetToken;
1318
}
1419

15-
// 2. Get the AssetManager settings
16-
function getSettings()
17-
public
18-
view
19-
returns (uint256 lotSizeAMG, uint256 assetDecimals)
20-
{
21-
AssetManagerSettings.Data memory settings = assetManager.getSettings();
22-
lotSizeAMG = settings.lotSizeAMG;
23-
assetDecimals = settings.assetDecimals;
24-
25-
return (lotSizeAMG, assetDecimals);
20+
// 2. Approve FAssets for redemption
21+
function approveFAssets(uint256 _amount) public returns (bool) {
22+
return IERC20(fAssetToken).approve(address(this), _amount);
2623
}
2724

28-
// 3. Redeem FAssets
25+
// 3. Redeem FAssets (requires prior approval)
2926
function redeem(
3027
uint256 _lots,
3128
string memory _redeemerUnderlyingAddressString
3229
) public returns (uint256) {
30+
// Calculate the amount of FXRP needed for redemption
31+
AssetManagerSettings.Data memory settings = assetManager.getSettings();
32+
uint256 amountToRedeem = settings.lotSizeAMG * _lots;
33+
34+
// Transfer FXRP from caller to AssetManager
35+
IERC20(fAssetToken).transferFrom(
36+
msg.sender,
37+
address(this),
38+
amountToRedeem
39+
);
40+
3341
uint256 redeemedAmountUBA = assetManager.redeem(
3442
_lots,
3543
_redeemerUnderlyingAddressString,
36-
// The account that is allowed to execute redemption default (besides redeemer and agent).
37-
// In this case it is not used
3844
payable(address(0))
3945
);
4046

4147
return redeemedAmountUBA;
4248
}
49+
50+
// 4. Get the AssetManager settings
51+
function getSettings()
52+
public
53+
view
54+
returns (uint256 lotSizeAMG, uint256 assetDecimals)
55+
{
56+
AssetManagerSettings.Data memory settings = assetManager.getSettings();
57+
lotSizeAMG = settings.lotSizeAMG;
58+
assetDecimals = settings.assetDecimals;
59+
60+
return (lotSizeAMG, assetDecimals);
61+
}
4362
}

0 commit comments

Comments
 (0)