Skip to content

Commit ea48204

Browse files
committed
feat(docs): add guides for redeeming FAssets, including redeeming by amount, with tag
1 parent e8212c8 commit ea48204

10 files changed

Lines changed: 318 additions & 5 deletions

docs/fassets/developer-guides.mdx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ Guides for [redeeming FAssets](/fassets/redemption) back to underlying assets.
7575

7676
<DocCardList
7777
items={[
78+
{
79+
type: "link",
80+
label: "Redeem FXRP by Amount",
81+
href: "/fassets/developer-guides/fassets-redeem-amount",
82+
docId: "fassets/developer-guides/fassets-redeem-amount",
83+
},
84+
{
85+
type: "link",
86+
label: "Redeem FXRP with Tag",
87+
href: "/fassets/developer-guides/fassets-redeem-with-tag",
88+
docId: "fassets/developer-guides/fassets-redeem-with-tag",
89+
},
7890
{
7991
type: "link",
8092
label: "Redeem FAssets",
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
title: Redeem FXRP with Tag
3+
tags: [intermediate, fassets]
4+
slug: fassets-redeem-with-tag
5+
description: Redeem any amount of FXRP and require an XRPL destination tag on the agent's payment.
6+
keywords:
7+
[
8+
fassets,
9+
fxrp,
10+
redemption,
11+
redeem-with-tag,
12+
xrpl,
13+
destination-tag,
14+
flare-network,
15+
]
16+
sidebar_position: 10
17+
---
18+
19+
import CodeBlock from "@theme/CodeBlock";
20+
import FAssetsRedeemWithTag from "!!raw-loader!/examples/developer-hub-javascript/fassetsRedeemWithTag.ts";
21+
22+
## Overview
23+
24+
This guide walks you through redeeming FXRP using [`redeemWithTag`](/fassets/reference/IAssetManager#redeemwithtag) on the `AssetManagerFXRP` contract.
25+
Compared to [`redeemAmount`](/fassets/developer-guides/fassets-redeem-amount), `redeemWithTag` adds a required XRPL destination tag that the agent must include in the redemption payment — useful when redeeming directly to an exchange address that requires a tag.
26+
27+
The complete runnable example is available in the [flare-viem-starter](https://github.com/flare-foundation/flare-viem-starter/blob/main/src/fassets/redeem-with-tag.ts) repository.
28+
29+
## Prerequisites
30+
31+
- An EVM wallet with.
32+
- Native tokens on the same wallet to cover the gas fees.
33+
- An XRPL destination address and the destination tag the recipient requires.
34+
35+
## Redeem with Tag Script
36+
37+
<CodeBlock language="typescript" title="src/fassets/redeem-with-tag.ts">
38+
{FAssetsRedeemWithTag}
39+
</CodeBlock>
40+
41+
## Code Breakdown
42+
43+
1. Set `REDEEM_AMOUNT_UBA` to the amount of FXRP to redeem in UBA (underlying base unit).
44+
2. Set `REDEEMER_UNDERLYING_ADDRESS_STRING` to the XRPL address that will receive the redeemed XRP from the agent.
45+
3. `EXECUTOR_ZERO_ADDRESS` is used because no executor is appointed in this example.
46+
Pass a real address to delegate default-handling to an executor.
47+
4. Set `REDEMPTION_DESTINATION_TAG` to the XRPL destination tag the agent must include on the redemption payment.
48+
It must fit in a 32-bit integer.
49+
See [minting with tag](/fassets/direct-minting#minting-tag-manager) for more details or check out the [minting with tag example](/fassets/developer-guides/fassets-direct-minting-tag) on how to reserve a tag.
50+
5. Resolve the `AssetManagerFXRP` address through the [Flare Contract Registry](/network/guides/flare-contracts-registry) using [`getContractAddressByName`](/network/guides/flare-contracts-registry).
51+
6. Read [`minimumRedeemAmountUBA`](/fassets/reference/IAssetManager#minimumredeemamountuba) and check that the requested amount is at least the protocol minimum.
52+
7. Simulate the [`redeemWithTag`](/fassets/reference/IAssetManager#redeemwithtag) call to validate the arguments and produce a signed request payload.
53+
8. Submit the redemption request transaction.
54+
9. Wait for the transaction receipt.
55+
10. Decode [`RedemptionWithTagRequested`](/fassets/reference/IAssetManagerEvents#redemptionwithtagrequested) events from the receipt logs with the `parseEventLogs` function and select the one whose `redeemer` matches the caller.
56+
A single call may emit multiple `RedemptionWithTagRequested` events when multiple agents fulfill the request.
57+
58+
## Important Notes
59+
60+
- **XRP-only feature.** `redeemWithTag` is an XRP-only feature and is only available for FXRP.
61+
- **`minimumRedeemAmountUBA` is enforced on-chain.** Requests below the threshold revert.
62+
- **The redemption may be partial.** If the request requires too many redemption tickets, only part is filled and the leftover is returned via [`RedemptionAmountIncomplete`](/fassets/reference/IAssetManagerEvents#redemptionamountincomplete).
63+
Call `redeemWithTag` again for the remainder.
64+
- **Multiple agents may pay.** A single `redeemWithTag` call can produce several [`RedemptionWithTagRequested`](/fassets/reference/IAssetManagerEvents#redemptionwithtagrequested) events — one per agent serving the request.
65+
Track each `requestId` for the agent's underlying-chain payment.
66+
- **Default uses a dedicated proof type.** Confirming a tagged redemption uses `confirmXRPRedemptionPayment`, and if the agent fails to pay call `xrpRedemptionPaymentDefault` to start the default process.
67+
68+
:::tip[What's next]
69+
70+
To continue your FAssets development journey, you can:
71+
72+
- Redeem any amount without a tag with [`redeemAmount`](/fassets/developer-guides/fassets-redeem-amount).
73+
- Read the protocol details in [Redemption](/fassets/redemption).
74+
- Handle non-paying agents in [Monitor Redemptions & Execute Defaults](/fassets/developer-guides/fassets-redemption-default).
75+
76+
:::

docs/fassets/developer-guides/9-fassets-redeem.mdx renamed to docs/fassets/developer-guides/11-fassets-redeem.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tags: [intermediate, fassets]
44
slug: fassets-redeem
55
description: Learn how to redeem FAssets
66
keywords: [fassets, flare-network]
7-
sidebar_position: 9
7+
sidebar_position: 11
88
---
99

1010
import CodeBlock from "@theme/CodeBlock";

docs/fassets/developer-guides/10-fassets-swap-redeem.mdx renamed to docs/fassets/developer-guides/12-fassets-swap-redeem.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tags: [intermediate, fassets]
44
slug: fassets-swap-redeem
55
description: Learn how to swap and redeem FAssets
66
keywords: [fassets, flare-network]
7-
sidebar_position: 10
7+
sidebar_position: 12
88
---
99

1010
import CodeBlock from "@theme/CodeBlock";

docs/fassets/developer-guides/11-fassets-agent-details.mdx renamed to docs/fassets/developer-guides/13-fassets-agent-details.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tags: [intermediate, fassets]
44
slug: fassets-agent-details
55
description: Learn how to read FAssets agent details
66
keywords: [fassets, flare-network]
7-
sidebar_position: 11
7+
sidebar_position: 13
88
---
99

1010
import CodeBlock from "@theme/CodeBlock";

docs/fassets/developer-guides/12-fassets-redemption-default.mdx renamed to docs/fassets/developer-guides/14-fassets-redemption-default.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tags: [intermediate, fassets]
44
slug: fassets-redemption-default
55
description: Monitor and handle redemption scenarios
66
keywords: [fassets, flare-network]
7-
sidebar_position: 12
7+
sidebar_position: 14
88
---
99

1010
import YouTubeEmbed from "@site/src/components/YouTubeEmbed";

docs/fassets/developer-guides/13-fassets-redemption-queue.mdx renamed to docs/fassets/developer-guides/15-fassets-redemption-queue.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tags: [intermediate, fassets]
44
slug: fassets-redemption-queue
55
description: Learn how to get the redemption queue
66
keywords: [fassets, flare-network]
7-
sidebar_position: 13
7+
sidebar_position: 15
88
---
99

1010
import CodeBlock from "@theme/CodeBlock";
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
title: Redeem FXRP by Amount
3+
tags: [intermediate, fassets]
4+
slug: fassets-redeem-amount
5+
description: Redeem any amount of FXRP without rounding to whole lots.
6+
keywords: [fassets, fxrp, redemption, redeem-amount, flare-network, xrpl]
7+
sidebar_position: 9
8+
---
9+
10+
import CodeBlock from "@theme/CodeBlock";
11+
import FAssetsRedeemAmount from "!!raw-loader!/examples/developer-hub-javascript/fassetsRedeemAmount.ts";
12+
13+
## Overview
14+
15+
This guide walks you through redeeming FXRP using [`redeemAmount`](/fassets/reference/IAssetManager#redeemamount) on the `AssetManagerFXRP` contract.
16+
Unlike the previous [`redeem`](/fassets/reference/IAssetManager#redeem) guide, `redeemAmount` accepts an arbitrary amount instead of whole lots.
17+
18+
The complete runnable example is available in the [flare-viem-starter](https://github.com/flare-foundation/flare-viem-starter/blob/main/src/fassets/redeem-amount.ts) repository.
19+
20+
## Prerequisites
21+
22+
- An EVM wallet with FXRP.
23+
- Native tokens on the same wallet to cover the gas fees.
24+
- An XRPL address to receive the redeemed XRP.
25+
26+
## Redeem Amount Script
27+
28+
<CodeBlock language="typescript" title="src/fassets/redeem-amount.ts">
29+
{FAssetsRedeemAmount}
30+
</CodeBlock>
31+
32+
## Code Breakdown
33+
34+
1. Set `REDEEM_AMOUNT_UBA` to the amount of FXRP to redeem in UBA (underlying base unit).
35+
2. Set `REDEEMER_UNDERLYING_ADDRESS_STRING` to the XRPL address that will receive the redeemed XRP from the agent.
36+
3. `EXECUTOR_ZERO_ADDRESS` is used because no executor is appointed in this example.
37+
Pass a real address to delegate default-handling to an executor.
38+
4. Resolve the `AssetManagerFXRP` address through the [Flare Contract Registry](/network/guides/flare-contracts-registry) using [`getContractAddressByName`](/network/guides/flare-contracts-registry).
39+
5. Read [`minimumRedeemAmountUBA`](/fassets/reference/IAssetManager#minimumredeemamountuba) and check that the requested amount is at least the protocol minimum.
40+
6. Simulate the [`redeemAmount`](/fassets/reference/IAssetManager#redeemamount) call to validate the arguments and produce a signed request payload.
41+
7. Submit the redemption request transaction.
42+
8. Wait for the transaction receipt.
43+
9. Decode [`RedemptionRequested`](/fassets/reference/IAssetManagerEvents#redemptionrequested) events from the receipt logs with the `parseEventLogs` function and select the one whose `redeemer` matches the caller.
44+
A single call may emit multiple `RedemptionRequested` events when multiple agents fulfill the request.
45+
46+
## Important Notes
47+
48+
- **`minimumRedeemAmountUBA` is enforced on-chain.** Requests below the threshold revert.
49+
- **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`](/fassets/reference/IAssetManagerEvents#redemptionamountincomplete).
50+
Call `redeemAmount` again for the remainder.
51+
- **Multiple agents may pay.** A single `redeemAmount` call can produce several [`RedemptionRequested`](/fassets/reference/IAssetManagerEvents#redemptionrequested) events — one per agent serving the request.
52+
Track each `requestId` for the agent's underlying-chain payment.
53+
- **Agents have a deadline to pay.** If an agent fails to pay within the redemption window, start the [redemption default process](/fassets/developer-guides/fassets-redemption-default).
54+
- **Use `redeemWithTag` for exchange deposits.** When the destination XRPL address requires a destination tag, call [`redeemWithTag`](/fassets/reference/IAssetManager#redeemwithtag) instead.
55+
56+
:::tip[What's next]
57+
58+
To continue your FAssets development journey, you can:
59+
60+
- Redeem with tag with [`redeemWithTag`](/fassets/developer-guides/fassets-redeem-with-tag).
61+
- Read the protocol details in [Redemption](/fassets/redemption).
62+
- Handle non-paying agents in [Monitor Redemptions & Execute Defaults](/fassets/developer-guides/fassets-redemption-default).
63+
64+
:::
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { coston2 } from "@flarenetwork/flare-wagmi-periphery-package";
2+
import { parseEventLogs, type Address } from "viem";
3+
import { account, publicClient, walletClient } from "./utils/client";
4+
import { getContractAddressByName } from "./utils/flare-contract-registry";
5+
6+
// 1. Amount to redeem in UBA (underlying base units; 1 XRP = 1_000_000 UBA).
7+
const REDEEM_AMOUNT_UBA = 5000000n;
8+
// 2. Redeemer underlying (XRPL) address that will receive the redeemed XRP.
9+
const REDEEMER_UNDERLYING_ADDRESS_STRING = "rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm";
10+
// 3. Executor (not used here, so the zero address).
11+
const EXECUTOR_ZERO_ADDRESS: Address = "0x0000000000000000000000000000000000000000";
12+
13+
async function main() {
14+
// 4. Resolve the AssetManagerFXRP address from the Flare Contract Registry.
15+
const assetManagerAddress = await getContractAddressByName("AssetManagerFXRP");
16+
console.log("AssetManagerFXRP address:", assetManagerAddress, "\n");
17+
18+
// 5. Read the protocol-wide minimum redemption amount and assert that the
19+
// requested amount is above it. Smaller redemptions are rejected on-chain.
20+
const minimumRedeemAmountUBA = await publicClient.readContract({
21+
address: assetManagerAddress,
22+
abi: coston2.iAssetManagerAbi,
23+
functionName: "minimumRedeemAmountUBA",
24+
});
25+
console.log("minimumRedeemAmountUBA:", minimumRedeemAmountUBA.toString(), "\n");
26+
console.log("Requested redeem amount UBA:", REDEEM_AMOUNT_UBA.toString(), "\n");
27+
28+
if (REDEEM_AMOUNT_UBA < minimumRedeemAmountUBA) {
29+
throw new Error(
30+
`Redeem amount (${REDEEM_AMOUNT_UBA.toString()}) must be greater than minimumRedeemAmountUBA (${minimumRedeemAmountUBA.toString()}).`
31+
);
32+
}
33+
34+
// 6. Simulate the redeemAmount call to validate args and produce a request
35+
// that walletClient can submit.
36+
const { request } = await publicClient.simulateContract({
37+
account,
38+
address: assetManagerAddress,
39+
abi: coston2.iAssetManagerAbi,
40+
functionName: "redeemAmount",
41+
args: [REDEEM_AMOUNT_UBA, REDEEMER_UNDERLYING_ADDRESS_STRING, EXECUTOR_ZERO_ADDRESS],
42+
});
43+
44+
// 7. Submit the redemption request transaction on Flare.
45+
const txHash = await walletClient.writeContract(request);
46+
console.log("redeemAmount tx hash:", txHash, "\n");
47+
48+
// 8. Wait for the transaction receipt.
49+
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
50+
console.log("redeemAmount status:", receipt.status, "\n");
51+
52+
// 9. Decode RedemptionRequested events from the receipt logs and pick the
53+
// one that belongs to this redeemer.
54+
const redemptionLogs = parseEventLogs({
55+
abi: coston2.iAssetManagerAbi,
56+
eventName: "RedemptionRequested",
57+
logs: receipt.logs,
58+
});
59+
60+
const redemptionEvent = redemptionLogs.find(
61+
(log) => log.args.redeemer.toLowerCase() === account.address.toLowerCase(),
62+
);
63+
64+
if (!redemptionEvent) {
65+
throw new Error("RedemptionRequested event not found for this transaction and redeemer");
66+
}
67+
68+
console.log("RedemptionRequested event:", redemptionEvent, "\n");
69+
}
70+
71+
void main()
72+
.then(() => process.exit(0))
73+
.catch((error) => {
74+
console.error(error);
75+
process.exit(1);
76+
});
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { coston2 } from "@flarenetwork/flare-wagmi-periphery-package";
2+
import { parseEventLogs, type Address } from "viem";
3+
import { account, publicClient, walletClient } from "./utils/client";
4+
import { getContractAddressByName } from "./utils/flare-contract-registry";
5+
6+
// 1. Amount to redeem in UBA (underlying base units; 1 XRP = 1_000_000 UBA).
7+
const REDEEM_AMOUNT_UBA = 5000000n;
8+
// 2. Redeemer underlying (XRPL) address that will receive the redeemed XRP.
9+
const REDEEMER_UNDERLYING_ADDRESS_STRING = "rSHYuiEvsYsKR8uUHhBTuGP5zjRcGt4nm";
10+
// 3. Executor (not used here, so the zero address).
11+
const EXECUTOR_ZERO_ADDRESS: Address = "0x0000000000000000000000000000000000000000";
12+
// 4. XRPL destination tag the agent must include in the redemption payment
13+
// (must fit in 32 bits; e.g. an exchange deposit tag).
14+
const REDEMPTION_DESTINATION_TAG = 72n;
15+
16+
async function main() {
17+
// 5. Resolve the AssetManagerFXRP address from the Flare Contract Registry.
18+
const assetManagerAddress = await getContractAddressByName("AssetManagerFXRP");
19+
console.log("AssetManagerFXRP address:", assetManagerAddress, "\n");
20+
21+
// 6. Read the protocol-wide minimum redemption amount and assert that the
22+
// requested amount is above it. Smaller redemptions are rejected on-chain.
23+
const minimumRedeemAmountUBA = await publicClient.readContract({
24+
address: assetManagerAddress,
25+
abi: coston2.iAssetManagerAbi,
26+
functionName: "minimumRedeemAmountUBA",
27+
});
28+
console.log("minimumRedeemAmountUBA:", minimumRedeemAmountUBA.toString(), "\n");
29+
console.log("Requested redeem amount UBA:", REDEEM_AMOUNT_UBA.toString(), "\n");
30+
console.log("Redemption destination tag:", REDEMPTION_DESTINATION_TAG.toString(), "\n");
31+
32+
if (REDEEM_AMOUNT_UBA < minimumRedeemAmountUBA) {
33+
throw new Error(
34+
`Redeem amount (${REDEEM_AMOUNT_UBA.toString()}) must be greater than minimumRedeemAmountUBA (${minimumRedeemAmountUBA.toString()}).`
35+
);
36+
}
37+
38+
// 7. Simulate the redeemWithTag call to validate args and produce a request
39+
// that walletClient can submit.
40+
const { request } = await publicClient.simulateContract({
41+
account,
42+
address: assetManagerAddress,
43+
abi: coston2.iAssetManagerAbi,
44+
functionName: "redeemWithTag",
45+
args: [
46+
REDEEM_AMOUNT_UBA,
47+
REDEEMER_UNDERLYING_ADDRESS_STRING,
48+
EXECUTOR_ZERO_ADDRESS,
49+
REDEMPTION_DESTINATION_TAG,
50+
],
51+
});
52+
53+
// 8. Submit the redemption request transaction on Flare.
54+
const txHash = await walletClient.writeContract(request);
55+
console.log("redeemWithTag tx hash:", txHash, "\n");
56+
57+
// 9. Wait for the transaction receipt.
58+
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
59+
console.log("redeemWithTag status:", receipt.status, "\n");
60+
61+
// 10. Decode RedemptionWithTagRequested events from the receipt logs and
62+
// pick the one that belongs to this redeemer.
63+
const redemptionLogs = parseEventLogs({
64+
abi: coston2.iAssetManagerAbi,
65+
eventName: "RedemptionWithTagRequested",
66+
logs: receipt.logs,
67+
});
68+
69+
const redemptionEvent = redemptionLogs.find(
70+
(log) => log.args.redeemer.toLowerCase() === account.address.toLowerCase(),
71+
);
72+
73+
if (!redemptionEvent) {
74+
throw new Error("RedemptionWithTagRequested event not found for this transaction and redeemer");
75+
}
76+
77+
console.log("RedemptionWithTagRequested event:", redemptionEvent, "\n");
78+
}
79+
80+
void main()
81+
.then(() => process.exit(0))
82+
.catch((error) => {
83+
console.error(error);
84+
process.exit(1);
85+
});

0 commit comments

Comments
 (0)