Skip to main content

Redeem FXRP by Amount

Overview

This guide walks you through redeeming FXRP using redeemAmount on the AssetManagerFXRP contract. Unlike the previous redeem guide, redeemAmount accepts an arbitrary amount instead of whole lots.

The complete runnable example is available in the flare-viem-starter repository.

Prerequisites

  • An EVM wallet with FXRP.
  • Native tokens on the same wallet to cover the gas fees.
  • An XRPL address to receive the redeemed XRP.

Redeem Amount Script

src/fassets/redeem-amount.ts
import { coston2 } from "@flarenetwork/flare-wagmi-periphery-package";
import { parseEventLogs, type Address } from "viem";
import { account, publicClient, walletClient } from "./utils/client";
import { getContractAddressByName } from "./utils/flare-contract-registry";

// 1. Amount to redeem in UBA (underlying base units; 1 XRP = 1_000_000 UBA).
const REDEEM_AMOUNT_UBA = 5000000n;
// 2. Redeemer underlying (XRPL) address that will receive the redeemed XRP.
const REDEEMER_UNDERLYING_ADDRESS_STRING = "rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm";
// 3. Executor (not used here, so the zero address).
const EXECUTOR_ZERO_ADDRESS: Address =
"0x0000000000000000000000000000000000000000";

async function main() {
// 4. Resolve the AssetManagerFXRP address from the Flare Contract Registry.
const assetManagerAddress =
await getContractAddressByName("AssetManagerFXRP");
console.log("AssetManagerFXRP address:", assetManagerAddress, "\n");

// 5. Read the protocol-wide minimum redemption amount and assert that the
// requested amount is above it. Smaller redemptions are rejected on-chain.
const minimumRedeemAmountUBA = await publicClient.readContract({
address: assetManagerAddress,
abi: coston2.iAssetManagerAbi,
functionName: "minimumRedeemAmountUBA",
});
console.log(
"minimumRedeemAmountUBA:",
minimumRedeemAmountUBA.toString(),
"\n",
);
console.log(
"Requested redeem amount UBA:",
REDEEM_AMOUNT_UBA.toString(),
"\n",
);

if (REDEEM_AMOUNT_UBA < minimumRedeemAmountUBA) {
throw new Error(
`Redeem amount (${REDEEM_AMOUNT_UBA.toString()}) must be greater than minimumRedeemAmountUBA (${minimumRedeemAmountUBA.toString()}).`,
);
}

// 6. Simulate the redeemAmount call to validate args and produce a request
// that walletClient can submit.
const { request } = await publicClient.simulateContract({
account,
address: assetManagerAddress,
abi: coston2.iAssetManagerAbi,
functionName: "redeemAmount",
args: [
REDEEM_AMOUNT_UBA,
REDEEMER_UNDERLYING_ADDRESS_STRING,
EXECUTOR_ZERO_ADDRESS,
],
});

// 7. Submit the redemption request transaction on Flare.
const txHash = await walletClient.writeContract(request);
console.log("redeemAmount tx hash:", txHash, "\n");

// 8. Wait for the transaction receipt.
const receipt = await publicClient.waitForTransactionReceipt({
hash: txHash,
});
console.log("redeemAmount status:", receipt.status, "\n");

// 9. Decode RedemptionRequested events from the receipt logs and pick the
// one that belongs to this redeemer.
const redemptionLogs = parseEventLogs({
abi: coston2.iAssetManagerAbi,
eventName: "RedemptionRequested",
logs: receipt.logs,
});

const redemptionEvent = redemptionLogs.find(
(log) => log.args.redeemer.toLowerCase() === account.address.toLowerCase(),
);

if (!redemptionEvent) {
throw new Error(
"RedemptionRequested event not found for this transaction and redeemer",
);
}

console.log("RedemptionRequested event:", redemptionEvent, "\n");
}

void main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

Code Breakdown

  1. Set REDEEM_AMOUNT_UBA to the amount of FXRP to redeem in UBA (underlying base unit).
  2. Set REDEEMER_UNDERLYING_ADDRESS_STRING to the XRPL address that will receive the redeemed XRP from the agent.
  3. EXECUTOR_ZERO_ADDRESS is used because no executor is appointed in this example. Pass a real address to delegate default-handling to an executor.
  4. Resolve the AssetManagerFXRP address through the Flare Contract Registry using getContractAddressByName.
  5. Read minimumRedeemAmountUBA and check that the requested amount is at least the protocol minimum.
  6. Simulate the redeemAmount call to validate the arguments and produce a signed request payload.
  7. Submit the redemption request transaction.
  8. Wait for the transaction receipt.
  9. Decode RedemptionRequested events from the receipt logs with the parseEventLogs function and select the one whose redeemer matches the caller. A single call may emit multiple RedemptionRequested events when multiple agents fulfill the request.

Important Notes

  • minimumRedeemAmountUBA is enforced on-chain. Requests below the threshold revert.
  • The redemption may be partial. If the request requires too many redemption tickets, only part is fulfilled, and the remaining tickets are returned via RedemptionAmountIncomplete. Call redeemAmount again for the remainder.
  • Multiple agents may pay. A single redeemAmount call can produce several RedemptionRequested events — one per agent serving the request. Track each requestId for the agent's underlying-chain payment.
  • Agents have a deadline to pay. If an agent fails to pay within the redemption window, start the redemption default process.
  • Use redeemWithTag for exchange deposits. When the destination XRPL address requires a destination tag, call redeemWithTag instead.
What's next

To continue your FAssets development journey, you can: