# Direct Mint FXRP with Tag

> Mint FXRP using a reserved XRPL destination tag.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

Source: https://dev.flare.network/fassets/developer-guides/fassets-direct-minting-tag

## Overview[​](#overview "Direct link to Overview")

This guide walks you through minting FXRP using [direct minting](/fassets/direct-minting) with an **XRPL destination tag** reserved on Flare that maps to a recipient (and optionally an executor). Once a tag is reserved and bound, every XRPL payment to the [Core Vault](/fassets/core-vault) carrying that destination tag mints FXRP to the configured recipient — no per-payment memo required.

The complete runnable example is available in the [flare-viem-starter](https://github.com/flare-foundation/flare-viem-starter/blob/main/src/fassets/direct-mint-tag.ts) repository.

## Tag vs. memo[​](#tag-vs-memo "Direct link to Tag vs. memo")

Compared to the [memo-based direct minting](/fassets/developer-guides/fassets-direct-minting), the tag flow is better suited for repeat minters:

-   **One-time setup**: reserve a tag once via [`MintingTagManager`](/fassets/reference/IMintingTagManager) — pay the [`reservationFee`](/fassets/reference/IMintingTagManager#reservationfee) in native token and bind the recipient with [`setMintingRecipient`](/fassets/reference/IMintingTagManager#setmintingrecipient).
-   **Reusable**: every subsequent XRPL payment with the same destination tag routes to the bound recipient without rebuilding a memo.
-   **Transferable**: tags are [ERC-721 NFTs](https://ethereum.org/developers/docs/standards/tokens/erc-721/) and can be transferred to another owner with [`transfer`](/fassets/reference/IMintingTagManager#transfer).
-   **Optional preferred executor**: the tag owner may restrict execution via [`setAllowedExecutor`](/fassets/reference/IMintingTagManager#setallowedexecutor). After [`othersCanExecuteAfterSeconds`](/fassets/reference/IAssetManager#getdirectmintingotherscanexecuteafterseconds), anyone can finalize.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

-   [Flare smart account](/smart-accounts/overview) controlled by your XRPL wallet.
-   Native FLR (or C2FLR on Coston2) on the Flare wallet to cover the tag reservation fee.
-   Testnet XRP on the XRP Ledger Testnet — get it from the [XRP Testnet Faucet](https://xrpl.org/resources/dev-tools/xrp-faucets).
-   Environment variables:
    -   `XRPL_TESTNET_RPC_URL` — XRPL Testnet RPC endpoint.
    -   `XRPL_SEED` — seed for the XRPL wallet that will send the payment.
    -   `MINTING_TAG` — *optional*. If set, the script reuses this tag instead of reserving a new one.

## Direct Minting Tag Script[​](#direct-minting-tag-script "Direct link to Direct Minting Tag Script")

src/fassets/direct-mint-tag.ts

```
import { Client, Wallet } from "xrpl";import type { Address } from "viem";import { sendXrplPayment } from "./utils/xrpl";import { account, publicClient, walletClient } from "./utils/client";import { getPersonalAccountAddress } from "./utils/smart-accounts";import {  getContractAddressByName,  getDirectMintingPaymentAddress,  getMintingTagManagerAddress,} from "./utils/flare-contract-registry";import {  computeDirectMintingPaymentAmountXrp,  getFxrpBalance,  waitForDirectMintingExecuted,} from "./utils/fassets";import { coston2 } from "@flarenetwork/flare-wagmi-periphery-package";// 1. Reserve a new tag from MintingTagManager. The reservation fee is paid in//    native currency (FLR/SGB). The contract returns the next available tag.async function reserveTag(mintingTagManagerAddress: Address): Promise<bigint> {  const reservationFee = await publicClient.readContract({    address: mintingTagManagerAddress,    abi: coston2.iMintingTagManagerAbi,    functionName: "reservationFee",  });  console.log("Tag reservation fee (wei):", reservationFee, "\n");  const { result, request } = await publicClient.simulateContract({    account,    address: mintingTagManagerAddress,    abi: coston2.iMintingTagManagerAbi,    functionName: "reserve",    value: reservationFee,  });  const txHash = await walletClient.writeContract(request);  await publicClient.waitForTransactionReceipt({ hash: txHash });  const tag = result;  console.log("Reserved tag:", tag, "\n");  return tag;}// 2. Bind the reserved tag to the Flare recipient that should receive FXRP//    when payments arrive at the Core Vault with this destination tag.async function setMintingRecipient(  mintingTagManagerAddress: Address,  tag: bigint,  recipient: Address,): Promise<void> {  const { request } = await publicClient.simulateContract({    account,    address: mintingTagManagerAddress,    abi: coston2.iMintingTagManagerAbi,    functionName: "setMintingRecipient",    args: [tag, recipient],  });  const txHash = await walletClient.writeContract(request);  await publicClient.waitForTransactionReceipt({ hash: txHash });  console.log("Set minting recipient for tag", tag, "to", recipient, "\n");}// 3. Read the configured minting recipient for a tag.async function getMintingRecipient(  mintingTagManagerAddress: Address,  tag: bigint,): Promise<Address> {  return publicClient.readContract({    address: mintingTagManagerAddress,    abi: coston2.iMintingTagManagerAbi,    functionName: "mintingRecipient",    args: [tag],  });}// 4. Reuse MINTING_TAG from the .env if set, otherwise reserve a new tag and//    bind it to the recipient. Tags are ERC-721 NFTs and can be reused.async function getOrReserveTag(  mintingTagManagerAddress: Address,  recipient: Address,): Promise<bigint> {  if (process.env.MINTING_TAG) {    const tag = BigInt(process.env.MINTING_TAG);    console.log("Using existing minting tag from .env:", tag, "\n");    return tag;  }  const tag = await reserveTag(mintingTagManagerAddress);  await setMintingRecipient(mintingTagManagerAddress, tag, recipient);  console.log(    "Add MINTING_TAG=" + tag.toString() + " to your .env to reuse this tag.\n",  );  return tag;}async function main() {  // 5. Net FXRP amount to mint in XRP. Minting + executor fees are added on top  //    by computeDirectMintingPaymentAmountXrp to form the XRPL payment amount.  const fxrpMintAmount = 10;  // 6. Connect to the XRPL Testnet and load the sender wallet from XRPL_SEED.  const xrplClient = new Client(process.env.XRPL_TESTNET_RPC_URL!);  const xrplWallet = Wallet.fromSeed(process.env.XRPL_SEED!);  // 7. Resolve the Flare smart-account recipient and the AssetManagerFXRP address.  const [personalAccountAddress, assetManagerAddress] = await Promise.all([    getPersonalAccountAddress(xrplWallet.address),    getContractAddressByName("AssetManagerFXRP"),  ]);  console.log("Personal account address:", personalAccountAddress, "\n");  // 8. Resolve the MintingTagManager contract address from the AssetManager.  const mintingTagManagerAddress =    await getMintingTagManagerAddress(assetManagerAddress);  console.log("MintingTagManager address:", mintingTagManagerAddress, "\n");  // 9. Reserve a new tag (or reuse one from MINTING_TAG) and confirm the recipient.  const tag = await getOrReserveTag(    mintingTagManagerAddress,    personalAccountAddress,  );  const configuredRecipient = await getMintingRecipient(    mintingTagManagerAddress,    tag,  );  console.log("Minting recipient for tag:", configuredRecipient, "\n");  // 10. Read the Core Vault XRPL payment address, the recipient's initial FXRP  //     balance, and the gross XRP amount (net mint + minting fee + executor fee).  const [coreVaultXrplAddress, initialBalance, paymentAmountXrp] =    await Promise.all([      getDirectMintingPaymentAddress(assetManagerAddress),      getFxrpBalance(personalAccountAddress),      computeDirectMintingPaymentAmountXrp({        netMintAmountXrp: fxrpMintAmount,      }),    ]);  console.log("Core Vault XRPL address:", coreVaultXrplAddress, "\n");  console.log("AssetManagerFXRP address:", assetManagerAddress, "\n");  console.log("Initial FXRP balance:", initialBalance, "\n");  console.log("Payment amount (XRP, net mint + fees):", paymentAmountXrp, "\n");  // 11. Send the XRPL payment with the destination tag (no memo needed).  const transaction = await sendXrplPayment({    destination: coreVaultXrplAddress,    amount: paymentAmountXrp,    destinationTag: Number(tag),    wallet: xrplWallet,    client: xrplClient,  });  console.log(    "Direct mint XRPL transaction hash:",    transaction.result.hash,    "\n",  );  // 12. Wait for the DirectMintingExecuted event from AssetManagerFXRP.  const mintEvent = await waitForDirectMintingExecuted({    assetManagerAddress,    targetAddress: personalAccountAddress,  });  console.log("DirectMintingExecuted event:", mintEvent, "\n");  console.log("Minted amount (UBA):", mintEvent.args.mintedAmountUBA, "\n");  console.log("Minting fee (UBA):", mintEvent.args.mintingFeeUBA, "\n");  console.log("Executor fee (UBA):", mintEvent.args.executorFeeUBA, "\n");  // 13. Read the final FXRP balance and log the delta.  const finalBalance = await getFxrpBalance(personalAccountAddress);  console.log("Final FXRP balance:", finalBalance, "\n");  console.log("FXRP minted:", finalBalance - initialBalance, "\n");}void main()  .then(() => process.exit(0))  .catch((error) => {    console.error(error);    process.exit(1);  });
```

## Code Breakdown[​](#code-breakdown "Direct link to Code Breakdown")

1.  `reserveTag` function reads the [`reservationFee`](/fassets/reference/IMintingTagManager#reservationfee) from [`MintingTagManager`](/fassets/reference/IMintingTagManager) contract and calls [`reserve`](/fassets/reference/IMintingTagManager#reserve) with the fee. The contract assigns the next available tag and returns it.
2.  `setMintingRecipient` function binds the tag to a recipient address via [`setMintingRecipient`](/fassets/reference/IMintingTagManager#setmintingrecipient). Payments arriving at the [Core Vault](/fassets/core-vault) with this destination tag will mint FXRP to that recipient.
3.  `getMintingRecipient` reads the [`mintingRecipient`](/fassets/reference/IMintingTagManager#mintingrecipient) currently configured for a tag.
4.  `getOrReserveTag` reuses `MINTING_TAG` from the `.env` variables if set; otherwise, it reserves a new tag and binds it to the recipient.
5.  Set the net FXRP amount to mint in XRP. Minting and executor fees are added to the the XRPL payment amount.
6.  Connect to the XRPL Testnet using `XRPL_TESTNET_RPC_URL` and load the sender wallet from `XRPL_SEED`.
7.  Resolve the recipient — the Flare [`PersonalAccount`](/smart-accounts/reference/IPersonalAccount) for the XRPL wallet — via [`getPersonalAccountAddress`](/smart-accounts/reference/IPersonalAccount), and look up `AssetManagerFXRP` through the [Flare Contract Registry](/network/guides/flare-contracts-registry) using [`getContractAddressByName`](/network/guides/flare-contracts-registry).
8.  Resolve the [`MintingTagManager`](/fassets/reference/IMintingTagManager) contract address from the `AssetManager` using [`getMintingTagManager`](/fassets/reference/IAssetManager#getmintingtagmanager).
9.  Reserve a new tag (or reuse one from `MINTING_TAG`) and confirm the configured recipient.
10.  Read three values in parallel:
     -   `getDirectMintingPaymentAddress` — the Core Vault XRPL address that receives the payment.
     -   `getFxrpBalance` — the recipient's FXRP balance before minting.
     -   `computeDirectMintingPaymentAmountXrp` — the gross XRP amount equal to the net mint amount plus the minting fee and the executor fee, as quoted by the `AssetManagerFXRP` contract.
11.  Send the XRPL payment to the [Core Vault](/fassets/core-vault) with `destinationTag: Number(tag)` — no memo required.
12.  Wait for the [`DirectMintingExecuted`](/fassets/reference/IAssetManagerEvents#directmintingexecuted) event on `AssetManagerFXRP` using the `waitForDirectMintingExecuted` function. The event's `mintedAmountUBA`, `mintingFeeUBA`, and `executorFeeUBA` describe how the underlying payment was split.
13.  Read the final FXRP balance and log the delta.

## Important Notes[​](#important-notes "Direct link to Important Notes")

-   **Reservations cost native currency.** Tag reservation pays a fee in native token. Tags are assigned sequentially.
-   **Executor changes are not immediate.** After calling the [`setAllowedExecutor`](/fassets/reference/IMintingTagManager#setallowedexecutor) function, the new executor only becomes active after a 10-minute cooldown to protect in-flight FDC proofs. See [Executor Restrictions](/fassets/direct-minting#executor-restrictions).
-   **Transferring a tag resets it.** When ownership changes, the recipient is reset to the new owner, and the executor is reset to the zero address.
-   **Rate limits may delay execution.** If the minting hits hourly, daily, or large-minting thresholds, [`DirectMintingDelayed`](/fassets/reference/IAssetManagerEvents#directmintingdelayed) is emitted instead of [`DirectMintingExecuted`](/fassets/reference/IAssetManagerEvents#directmintingexecuted), with an `executionAllowedAt` timestamp.

## Video Tutorial[​](#video-tutorial "Direct link to Video Tutorial")

What's next

To continue your FAssets development journey, you can:

-   Mint without a tag using [memo-based direct minting](/fassets/developer-guides/fassets-direct-minting).
-   Transfer an existing tag to a new owner using [Transfer a Minting Tag](/fassets/developer-guides/fassets-direct-minting-tag-transfer).
-   Read the protocol details in [Direct Minting](/fassets/direct-minting).
-   Redeem FAssets with [`redeemAmount`](/fassets/developer-guides/fassets-redeem-amount) or [`redeemWithTag`](/fassets/developer-guides/fassets-redeem-with-tag).

FAssets demo dApp

The [FAssets demo dApp](https://fassets-demo-dapp.vercel.app/) showcases the FAssets system using the [Flare wagmi periphery package](https://www.npmjs.com/package/@flarenetwork/flare-wagmi-periphery-package). This app is a Next.js reference implementation for settings, minting, tags, transfer, and redeem functionality.

The source code is available in the [fassets-demo-dapp](https://github.com/flare-foundation/fassets-demo-dapp) repository.
