--- title: Redeem FAssets tags: [intermediate, fassets] slug: fassets-redeem description: Learn how to redeem FAssets keywords: [fassets, flare-network] sidebar_position: 7 --- import CodeBlock from "@theme/CodeBlock"; import RemixEmbed from "@site/src/components/RemixEmbed"; import FAssetsRedeem from "!!raw-loader!/examples/developer-hub-solidity/FAssetsRedeem.sol"; import RedemptionProcessPrerequisites from "./_redemption_process_prerequisites.mdx"; import YouTubeEmbed from "@site/src/components/YouTubeEmbed"; ## Overview In this guide, you will learn how to redeem FAssets using the Asset Manager smart contract. ## Redeem FAssets Smart Contract The following example demonstrates how to redeem FAssets using the `AssetManager` smart contract. {FAssetsRedeem} {/* prettier-ignore */} Open in Remix ### Code Breakdown 1. Redeem the FAssets using the [`redeem`](/fassets/reference/IAssetManager#redeem) function by specifying the number of lots to redeem and the underlying chain address. 2. 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). 3. Get the redemption request info to check the redemption status. :::info In this example, you are not using the executor vault address, but you can use it to redeem FAssets on behalf of another address. ::: ## Deploy and Interact with the Smart Contract To deploy the contract and redeem FAssets, you can use the [Flare Hardhat Starter Kit](/network/guides/hardhat-foundry-starter-kit). Create a new file, for example, `scripts/fassets/redeem.ts` and add the following code: ### Import the Required Contracts At first, you need to import the required dependencies and smart contract TypeScript types: ```typescript import { web3, run } from "hardhat"; import { formatUnits } from "ethers"; import { FAssetsRedeemInstance, ERC20Instance } from "../../typechain-types"; import { logEvents } from "../../scripts/utils/core"; ``` ### Define the Constants Define the constants: - `LOTS_TO_REDEEM` - the number of lots to redeem; - `UNDERLYING_ADDRESS` - underlying chain address where the redeemed asset will be sent; ```typescript const LOTS_TO_REDEEM = 1; const UNDERLYING_ADDRESS = "rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm"; ``` ### Import Contract Artifacts Import the contract artifacts to interact with the smart contracts: - `FAssetsRedeem` - the `FAssetsRedeem` contract; - `IAssetManager` - the asset manager interface; - `IERC20` - the `IERC20` contract for FXRP token; ```typescript const FAssetsRedeem = artifacts.require("FAssetsRedeem"); const AssetManager = artifacts.require("IAssetManager"); const IERC20 = artifacts.require("IERC20"); ``` ### Deploy and Verify the Redeem Contract Deploy and verify the smart contract providing the asset manager address as a constructor argument: ```typescript async function deployAndVerifyContract() { const fAssetsRedeem: FAssetsRedeemInstance = await FAssetsRedeem.new(); const fAssetsRedeemAddress = fAssetsRedeem.address; try { await run("verify:verify", { address: fAssetsRedeemAddress, constructorArguments: [], }); } catch (e: any) { console.log(e); } console.log("FAssetsRedeem deployed to:", fAssetsRedeemAddress); return fAssetsRedeem; } ``` ### Approve the FXRP transfer to the Redeem Contract 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. ```typescript async function approveFAssets(fAssetsRedeem: any, amountToRedeem: string) { console.log("Approving FAssetsRedeem contract to spend FXRP..."); const fxrpAddress = await fAssetsRedeem.getFXRPAddress(); const fxrp: ERC20Instance = await IERC20.at(fxrpAddress); const approveTx = await fxrp.approve( await fAssetsRedeem.address, amountToRedeem, ); console.log("FXRP approval completed"); } ``` :::warning In a production environment, it is recommended to use a more secure method for approving the transfer of FXRP to a smart contract. ::: ### Parse the Redemption Events During the redemption process, the `AssetManager` emits events: - [`RedemptionRequested`](/fassets/reference/IAssetManagerEvents#redemptionrequested) - holds the agent vault address, redemption request id, the amount of FAssets to redeem, and other important information. - [`RedemptionTicketCreated`](/fassets/reference/IAssetManagerEvents#redemptionticketcreated) - holds the redemption ticket information updated during the redemption process. - [`RedemptionTicketUpdated`](/fassets/reference/IAssetManagerEvents#redemptionticketupdated) - holds the redemption ticket information updated during the redemption process. To parse the redemption events, you can use the following function: ```typescript async function parseRedemptionEvents( transactionReceipt: any, fAssetsRedeem: any, ) { console.log("\nParsing events...", transactionReceipt.rawLogs); const redemptionRequestedEvents = logEvents( transactionReceipt.rawLogs, "RedemptionRequested", AssetManager.abi, ); logEvents( transactionReceipt.rawLogs, "RedemptionTicketCreated", AssetManager.abi, ); logEvents( transactionReceipt.rawLogs, "RedemptionTicketUpdated", AssetManager.abi, ); return redemptionRequestedEvents; } ``` :::info The `logEvents` function is used to parse and log the events interacting using the [Truffle](https://archive.trufflesuite.com/) suite of tools. You can find this function in the [Flare Hardhat Starter Kit](/network/guides/hardhat-foundry-starter-kit). In this guide, we are not focusing on the event parsing. ::: ### Output the Redemption Result The following function is used to output the redemption request information. ```typescript async function printRedemptionRequestInfo( fAssetsRedeem: any, redemptionRequestedEvents: any[], ) { console.log("\n=== Redemption Request Information ==="); for (const event of redemptionRequestedEvents) { const redemptionRequestInfo = await fAssetsRedeem.getRedemptionRequestInfo( event.decoded.requestId, ); console.log("Redemption request info:", redemptionRequestInfo); } } ``` ### Redeeming FAssets To put it altogether you can use the following function to deploy the contract, transfer FXRP to it, redeem the FAssets, and parse the redemption events: ```typescript async function main() { // Deploy and verify the contract const fAssetsRedeem = await deployAndVerifyContract(); // Get the lot size and decimals to calculate the amount to redeem const settings = await fAssetsRedeem.getSettings(); const lotSize = settings[0]; const decimals = settings[1]; console.log("Lot size:", lotSize.toString()); console.log("Asset decimals:", decimals.toString()); // Calculate the amount to redeem according to the lot size and the number of lots to redeem const amountToRedeem = web3.utils .toBN(lotSize) .mul(web3.utils.toBN(LOTS_TO_REDEEM)); console.log( `Required FXRP amount ${formatUnits(amountToRedeem.toString(), Number(decimals))} FXRP`, ); console.log(`Required amount in base units: ${amountToRedeem.toString()}`); // Approve FXRP for redemption await approveFAssets(fAssetsRedeem, amountToRedeem.toString()); // Call redeem function and wait for transaction const redeemTx = await fAssetsRedeem.redeem( LOTS_TO_REDEEM, UNDERLYING_ADDRESS, ); console.log("Redeem transaction receipt", redeemTx); // Parse events from the transaction const redemptionRequestedEvents = await parseRedemptionEvents( redeemTx.receipt, fAssetsRedeem, ); // Print redemption request info for each redemption requested event await printRedemptionRequestInfo(fAssetsRedeem, redemptionRequestedEvents); } main().catch((error) => { console.error(error); process.exitCode = 1; }); ``` ### Run the Script To run the script, use the [Flare Hardhat Starter Kit](/network/guides/hardhat-foundry-starter-kit) with the following command: ```bash npx hardhat run scripts/fassets/getLotSize.ts --network coston2 ``` Once the script is executed, two events hold the important information: #### [`RedemptionRequested`](/fassets/reference/IAssetManagerEvents#redemptionrequested) The `RedemptionRequested` event contains the agent vault address, redeemer address, underlying chain address, amount of FAssets to redeem, redemption fee, and other important information. ```bash RedemptionRequested Result { '0': '0xaADbF766Fd9131996C7B270A0cCB2b5c88Fc810D', '1': '0xDc8B65D8C07825280F2A2E08D5b25B9eea892E8f', '2': '6797056', '3': 'rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm', '4': '10000000', '5': '50000', '6': '9113416', '7': '9113939', '8': '1753190628', '9': '0x464250526641000200000000000000000000000000000000000000000067b700', '10': '0x0000000000000000000000000000000000000000', '11': '0', __length__: 12, agentVault: '0xaADbF766Fd9131996C7B270A0cCB2b5c88Fc810D', redeemer: '0xDc8B65D8C07825280F2A2E08D5b25B9eea892E8f', requestId: '6797056', paymentAddress: 'rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm', valueUBA: '10000000', feeUBA: '50000', firstUnderlyingBlock: '9113416', lastUnderlyingBlock: '9113939', lastUnderlyingTimestamp: '1753190628', paymentReference: '0x464250526641000200000000000000000000000000000000000000000067b700', executor: '0x0000000000000000000000000000000000000000', executorFeeNatWei: '0' } ``` When decoding an event, the most important data from the event is: - The agent vault address that will redeem the FAssets is `0x3c831Fe4417bEFFAc721d24996985eE2dd627053`; - The redeemer address is `0xCA7C9fBbA56E44C508bcb4872775c5fEd169cDb3`; - The redemption ticket id is `1898730`; - The underlying chain address is `rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm`; - The amount of FAssets to redeem is `20000000`; - The redemption fee is `20000`; You can view the full event description [here](/fassets/reference/IAssetManagerEvents#redemptionrequested). #### [`RedemptionTicketUpdated`](/fassets/reference/IAssetManagerEvents#redemptionticketupdated) 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. For every minting, a redemption ticket is created, and during the redemption process, the redemption ticket is updated with the new redemption status. ```bash RedemptionTicketUpdated Result { '0': '0xaADbF766Fd9131996C7B270A0cCB2b5c88Fc810D', '1': '1628', '2': '5360000000', __length__: 3, agentVault: '0xaADbF766Fd9131996C7B270A0cCB2b5c88Fc810D', redemptionTicketId: '1628', ticketValueUBA: '5360000000' } ``` Once decoding the most important data from the event is: - The agent vault address that will redeem the FAssets is `0x3c831Fe4417bEFFAc721d24996985eE2dd627053`; - The redemption ticket id is `870`; - The value of the redemption ticket in underlying chain currency is `3440000000` (partially redeemed). You can read the full event description [here](/fassets/reference/IAssetManagerEvents#redemptionticketupdated). ### Agent Process The FAssets agent should perform the redemption, and the user must retrieve the redeemed assets from the agent. These [operational parameters](/fassets/operational-parameters) define the timeframe within which the agent must complete the redemption payment: - `underlyingBlocksForPayment`: The number of underlying blocks during which the agent can pay the underlying value. - `underlyingSecondsForPayment`: The minimum time allowed for an agent to pay for a redemption. If the agent is unable to pay the redemption payment in the specified time, the redeemer can: 1. Make a proof of [payment non-existence](/fdc/attestation-types/referenced-payment-nonexistence) using the [Flare Data Connector](/fdc/overview). 2. Execute the [`redemptionPaymentDefault`](/fassets/reference/IAssetManager#redemptionpaymentdefault) function and present the proof of payment non-existence to the FAssets system, which triggers a redemption failure. 3. The redeemer receives collateral plus a premium. ## Video Tutorial ## Summary This is only the first step of the redemption process. The redeemer or agent completes the redemption process when proof of payment is presented to the FAssets system. Read more about the redemption process in the [here](/fassets/redemption). :::tip[What's next] To continue your FAssets development journey, you can: - Learn how to [mint FAssets using the executor](/fassets/developer-guides/fassets-mint-executor). - Explore [FAssets system settings](/fassets/operational-parameters). :::