Agent documentation index: llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Skip to main content

Transfer a Minting Tag

Overview

This guide walks you through transferring an existing minting tag to another address using transferFrom function on MintingTagManager.

In direct minting with tag, minting tags are ERC-721 NFTs. Transferring ownership is useful when buying a tag for a user, rotating custody, migrating operational wallets, or handing over a reserved tag to another account.

The complete runnable example is based on the transfer-minting-tag.ts script from Flare Viem starter.

Prerequisites

  • A previously reserved minting tag. Check the Direct Mint FXRP with Tag guide to reserve a minting tag.
  • The sender wallet must be the current owner of the tag and must have a native token for gas. To get the test tokens, use the Flare testnet faucet.
  • The target recipient EVM address that should become the new tag owner.

Minting Tag Transfer Script

src/fassets/transfer-minting-tag.ts
import { coston2 } from "@flarenetwork/flare-wagmi-periphery-package";
import { account, publicClient, walletClient } from "./utils/client";
import { getMintingTagManagerAddress } from "./utils/smart-accounts";

const MINTING_TAG = 72n;
const MINTING_TAG_RECIPIENT = "0x4F2E3d23BdFc554185fd06CC599c98D3A540d60A";

async function main() {
// 1. Set the tag to transfer and the recipient that should become the new owner.
const tag = MINTING_TAG;
const recipient = MINTING_TAG_RECIPIENT;
const sender = account.address;

// 2. Resolve MintingTagManager and log the transfer context.
const mintingTagManagerAddress = await getMintingTagManagerAddress();
console.log("MintingTagManager:", mintingTagManagerAddress, "\n");
console.log("Tag:", tag, "\n");
console.log("Sender:", sender, "\n");
console.log("Recipient:", recipient, "\n");

// 3. Read the current tag owner and configured minting recipient before transfer.
const [ownerBefore, mintingRecipientBefore] = await Promise.all([
publicClient.readContract({
address: mintingTagManagerAddress,
abi: coston2.iMintingTagManagerAbi,
functionName: "ownerOf",
args: [tag],
}),
publicClient.readContract({
address: mintingTagManagerAddress,
abi: coston2.iMintingTagManagerAbi,
functionName: "mintingRecipient",
args: [tag],
}),
]);

console.log("Owner before:", ownerBefore, "\n");
console.log("Minting recipient before:", mintingRecipientBefore, "\n");

// 4. Guard against accidental sends: only the current owner can transfer.
if (ownerBefore.toLowerCase() !== sender.toLowerCase()) {
throw new Error(
`Tag ${tag} is owned by ${ownerBefore}, but script sender is ${sender}. ` +
"Run this script with the owner's PRIVATE_KEY.",
);
}

// 5. Simulate transferFrom to build a validated request payload.
const { request } = await publicClient.simulateContract({
account,
address: mintingTagManagerAddress,
abi: coston2.iMintingTagManagerAbi,
functionName: "transferFrom",
args: [sender, recipient, tag],
});

// 6. Broadcast transferFrom and wait for confirmation.
const txHash = await walletClient.writeContract(request);
console.log("transferFrom tx:", txHash, "\n");
await publicClient.waitForTransactionReceipt({ hash: txHash });

// 7. Re-read owner and minting recipient to verify post-transfer state.
const [ownerAfter, mintingRecipientAfter] = await Promise.all([
publicClient.readContract({
address: mintingTagManagerAddress,
abi: coston2.iMintingTagManagerAbi,
functionName: "ownerOf",
args: [tag],
}),
publicClient.readContract({
address: mintingTagManagerAddress,
abi: coston2.iMintingTagManagerAbi,
functionName: "mintingRecipient",
args: [tag],
}),
]);

console.log("Owner after:", ownerAfter, "\n");
console.log("Minting recipient after:", mintingRecipientAfter, "\n");
}

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

Code Breakdown

Let's break down the code:

  1. Set MINTING_TAG to the tag ID you want to transfer and MINTING_TAG_RECIPIENT to the new owner address.
  2. Get the MintingTagManager address.
  3. Read the owner and recipient before the transfer.
  4. Validate that the script sender is not the current owner.
  5. Simulate the transferFrom function call to build a safe write request.
  6. Submit the transaction to the network and wait for the receipt confirmation.
  7. Read the owner and recipient after the transfer and verify the transfer.
Important

After transferring the tag, the recipient is reset to the new owner, and the allowed executor is cleared. The tag ID does not change. Transfer only changes ownership and related routing configuration for that existing destination tag.

Why this matters for direct minting

Every XRPL payment using this destination tag is routed by the tag's current on-chain configuration. Transferring a tag changes who controls that routing, so transfer operations should be treated as operational security actions.

What's next

To continue your FAssets development journey, you can:

FAssets demo dApp

The FAssets demo dApp showcases the FAssets system using the 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 repository.