Skip to main content

NFT Transfers

Transfer NFTs and SFTs (Semi-Fungible Tokens) on MultiversX.

NFT vs SFT

TypeNonceAmountExample
NFTUniqueAlways 1Art, collectibles
SFTUniqueMultipleGame items, tickets

Simple NFT Transfer

import 'package:abidock_mvx/abidock_mvx.dart';

void main() async {
final provider = GatewayNetworkProvider.devnet();
final account = await Account.fromMnemonic('your mnemonic...');

final config = await provider.getNetworkConfig();
final networkAccount = await provider.getAccount(account.address);

// NFT details
final collection = 'MYNFT-abc123';
final nonce = 42; // NFT #42
final recipient = Address.fromBech32('erd1...recipient...');

// Create factory
final factory = TransferTransactionsFactory(
config: TransferTransactionsConfig(chainId: ChainId(config.chainId)),
);

// Build NFT transfer transaction
final tx = factory.createTransactionForEsdtTransfer(
sender: account.address,
receiver: recipient,
tokenTransfers: [
TokenTransfer.nonFungible(
tokenIdentifier: collection,
nonce: nonce,
amount: BigInt.one, // NFTs always have amount 1
),
],
);

// Set nonce and sign
final txWithNonce = tx.copyWith(newNonce: networkAccount.nonce);
final signer = UserSigner(account.secretKey);
final signature = await signer.sign(txWithNonce.serializeForSigning());
final signed = txWithNonce.copyWith(newSignature: Signature.fromUint8List(signature));

final hash = await provider.sendTransaction(signed);
print('Sent NFT: $hash');
}
Receiver Address

For NFT transfers, the transaction receiver is your own address. The actual recipient is encoded in the transfer data.

SFT Transfer (Multiple Quantity)

// Transfer 5 copies of an SFT using TokenTransfer
final factory = TransferTransactionsFactory(
config: TransferTransactionsConfig(chainId: ChainId(config.chainId)),
);

final tx = factory.createTransactionForEsdtTransfer(
sender: account.address,
receiver: recipient,
tokenTransfers: [
TokenTransfer.nonFungible(
tokenIdentifier: 'MYSFT-def456',
nonce: 10,
amount: BigInt.from(5), // 5 copies
),
],
);

Check NFT Balance

void main() async {
final provider = GatewayNetworkProvider.devnet();
final address = Address.fromBech32('erd1...');

// Get all NFTs
final nfts = await provider.getNonFungibleTokensOfAccount(address);

for (final nft in nfts) {
print('Collection: ${nft.collection}');
print('Nonce: ${nft.nonce}');
print('Name: ${nft.name}');
print('Balance: ${nft.balance}');
print('---');
}
}

NFT Transfer to Smart Contract

Send NFT to a contract with a function call using SmartContractController:

void main() async {
final provider = GatewayNetworkProvider.devnet();
final account = await Account.fromMnemonic('your mnemonic...');

final config = await provider.getNetworkConfig();
final networkAccount = await provider.getAccount(account.address);

// Load contract ABI
final abi = SmartContractAbi.fromJson(abiJson);
final contractAddress = SmartContractAddress.fromBech32('erd1qqq...');

final controller = SmartContractController(
contractAddress: contractAddress,
abi: abi,
networkProvider: provider,
);

// Create NFT transfer + contract call
final tx = await controller.call(
account: account,
nonce: networkAccount.nonce,
endpointName: 'stakeNft',
arguments: [], // Optional function arguments (native Dart types)
tokenTransfers: [
TokenTransferValue.fromPrimitives(
tokenIdentifier: 'MYNFT-abc123',
amount: BigInt.one,
nonce: BigInt.from(42),
),
],
options: BaseControllerInput(gasLimit: GasLimit(15000000)),
);

final hash = await provider.sendTransaction(tx);
print('Staked NFT: $hash');
}

NFT Identifier Format

NFTs are identified by collection + nonce:

COLLECTION-hash-NONCE
│ │ │
│ │ └── Hex nonce (e.g., 2a = 42)
│ └─────── 6 char random hex
└──────────────── 3-10 char ticker

Example: MYNFT-abc123-2a = NFT #42 from MYNFT collection
// Parse NFT identifier
void parseNftId(String identifier) {
final parts = identifier.split('-');
final collection = '${parts[0]}-${parts[1]}'; // MYNFT-abc123
final nonce = int.parse(parts[2], radix: 16); // 42

print('Collection: $collection');
print('Nonce: $nonce');
}

Complete Example

import 'package:abidock_mvx/abidock_mvx.dart';

void main() async {
print('=== NFT Transfer Demo ===\n');

final provider = GatewayNetworkProvider.devnet();
final account = await Account.fromMnemonic('your mnemonic...');
final signer = UserSigner(account.secretKey);

print('Sender: ${account.address.bech32}');

// Get account info
final config = await provider.getNetworkConfig();
final networkAccount = await provider.getAccount(account.address);

// List owned NFTs
final nfts = await provider.getNonFungibleTokensOfAccount(account.address);

if (nfts.isEmpty) {
print('No NFTs found');
return;
}

for (var i = 0; i < nfts.length && i < 5; i++) {
final nft = nfts[i];
print(' [$i] ${nft.collection}-${nft.nonce.toRadixString(16)}: ${nft.name}');
}

// Select first NFT for demo
final selectedNft = nfts.first;
final collection = selectedNft.collection;
final nonce = BigInt.from(selectedNft.nonce);

// Recipient
final recipient = Address.fromBech32(
'erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx'
);

print(' NFT: ${selectedNft.name}');
print(' Collection: $collection');
print(' Nonce: $nonce');
print(' To: ${recipient.bech32.substring(0, 20)}...');

// Build transfer using TransferTransactionsFactory
final factory = TransferTransactionsFactory(
config: TransferTransactionsConfig(chainId: ChainId(config.chainId)),
);

final tx = factory.createTransactionForEsdtTransfer(
sender: account.address,
receiver: recipient,
tokenTransfers: [
TokenTransfer.nonFungible(
tokenIdentifier: collection,
nonce: nonce.toInt(),
amount: BigInt.one, // NFTs always have amount 1
),
],
);

// Set nonce and sign
final txWithNonce = tx.copyWith(newNonce: networkAccount.nonce);
final signature = await signer.sign(txWithNonce.serializeForSigning());
final signed = txWithNonce.copyWith(newSignature: Signature.fromUint8List(signature));

// Send
final hash = await provider.sendTransaction(signed);

// Wait
final watcher = TransactionWatcher(networkProvider: provider);
final result = await watcher.awaitCompleted(hash);

}

Gas for NFT Transfers

OperationGas Limit
Simple NFT transfer1,000,000
NFT to contract1,000,000 + function gas
Multiple NFTs1,100,000 + 100,000 per NFT

Next Steps