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
- Set
REDEEM_AMOUNT_UBAto the amount of FXRP to redeem in UBA (underlying base unit). - Set
REDEEMER_UNDERLYING_ADDRESS_STRINGto the XRPL address that will receive the redeemed XRP from the agent. EXECUTOR_ZERO_ADDRESSis used because no executor is appointed in this example. Pass a real address to delegate default-handling to an executor.- Resolve the
AssetManagerFXRPaddress through the Flare Contract Registry usinggetContractAddressByName. - Read
minimumRedeemAmountUBAand check that the requested amount is at least the protocol minimum. - Simulate the
redeemAmountcall to validate the arguments and produce a signed request payload. - Submit the redemption request transaction.
- Wait for the transaction receipt.
- Decode
RedemptionRequestedevents from the receipt logs with theparseEventLogsfunction and select the one whoseredeemermatches the caller. A single call may emit multipleRedemptionRequestedevents when multiple agents fulfill the request.
Important Notes
minimumRedeemAmountUBAis 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. CallredeemAmountagain for the remainder. - Multiple agents may pay. A single
redeemAmountcall can produce severalRedemptionRequestedevents — one per agent serving the request. Track eachrequestIdfor 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
redeemWithTagfor exchange deposits. When the destination XRPL address requires a destination tag, callredeemWithTaginstead.
What's next
To continue your FAssets development journey, you can:
- Redeem with tag with
redeemWithTag. - Handle non-paying agents in Monitor Redemptions & Execute Defaults.
- Mint without a tag using memo-based direct minting or direct minting with tag.