NFT Marketplace
XRPL supports native NFTs (XLS-20) without smart contracts. Minting, listing, and trading happen directly on-ledger via dedicated transaction types — giving your marketplace low-fee, instant-finality trades.
This guide uses XRPL NFToken* transactions. For Xahau, use the URIToken examples, including URITokenBuy to accept a sell offer.
Supported Transactions
NFTokenMint— create a new NFT with optional royalty and metadata URINFTokenCreateOffer— list an NFT for sale or place a buy offerNFTokenAcceptOffer— complete a trade (buyer or marketplace account calls this)NFTokenCancelOffer— withdraw a listing or buy offerNFTokenBurn— permanently destroy an NFT
Mint an NFT
// URI must be hex-encoded
const uri = "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi";
const uriHex = Buffer.from(uri).toString("hex").toUpperCase();
const result = await manager.signAndSubmit({
txJson: {
TransactionType: "NFTokenMint",
Account: manager.getSession()?.account.address,
NFTokenTaxon: 0, // collection ID — your app defines the value
TransferFee: 2500, // 2.5% creator royalty (unit = 0.001%, max 50000)
Flags: 8, // tfTransferable — allows secondary sales
URI: uriHex,
},
});
console.log("Minted. TX hash:", result.hash);
// Look up the validated transaction by result.hash to obtain mint metadata.List for Sale
const result = await manager.signAndSubmit({
txJson: {
TransactionType: "NFTokenCreateOffer",
Account: manager.getSession()?.account.address,
NFTokenID: "<token_id>",
Amount: "10000000", // 10 XRP in drops
Flags: 1, // tfSellNFToken
},
});
// Store the resulting offer ID (from tx metadata) for later acceptanceAccept a Sell Offer
await manager.signAndSubmit({
txJson: {
TransactionType: "NFTokenAcceptOffer",
Account: manager.getSession()?.account.address,
NFTokenSellOffer: "<offer_id>",
},
});Cancel a Listing
await manager.signAndSubmit({
txJson: {
TransactionType: "NFTokenCancelOffer",
Account: manager.getSession()?.account.address,
NFTokenOffers: ["<offer_id_1>", "<offer_id_2>"],
},
});Adapter Compatibility
| Adapter | NFTokenMint | NFTokenCreateOffer | NFTokenAcceptOffer |
|---|---|---|---|
| Xaman | ✅ | ✅ | ✅ |
| GemWallet | ✅ | ✅ | ✅ |
| Crossmark | ✅ | ✅ | ✅ |
| DropFi | ✅ | ✅ | ✅ |
| WalletConnect | ✅ | ✅ | ✅ |
| XRPL Snap | ✅ | ✅ | ✅ |
| Ledger | ✅ | ✅ | ✅ |
| GhostSig | ✅ | ✅ | ✅ |
| Xyra | Wallet dependent | Wallet dependent | Wallet dependent |
| Joey Wallet | Wallet dependent | Wallet dependent | Wallet dependent |
Support depends on the wallet/device app version and transaction fields. Use the XRP app on Ledger for these XRPL transactions; see its adapter guide. Generic signing is not proof of support for every NFT operation.
Tips
Royalties are enforced on-ledger. TransferFee is collected automatically on every secondary sale — no smart contract needed.
Use validated metadata. Fetch the transaction using the returned hash and extract the minted token ID from the validated metadata/affected NFT pages. parseNFTokenID() decodes an existing token ID; it does not extract one from metadata. Kit's normalized result does not expose a top-level meta field.
The accepting account is part of the trade. A direct sell-offer acceptance transfers the NFT to the accepting buyer; it is not a gasless relay on behalf of an unrelated buyer. Brokered acceptance requires matching buy/sell offers and follows the NFTokenAcceptOffer rules.
Brokered mode lets a marketplace match a buy and sell offer atomically by specifying both NFTokenBuyOffer and NFTokenSellOffer in a single NFTokenAcceptOffer call.
Next Steps
- WalletManager API — full
signAndSubmitreference - Events & Hooks — listen for
tx_confirmed - Recent Transactions — display trade history in the wallet UI