Post
Share your knowledge.

How to Transfer a Specific Amount of SUI Tokens: Handling Coin Objects
How to Transfer a Specific Amount of SUI Tokens: Handling Coin Objects
The Challenge
Unlike traditional blockchains where token balances are simple numbers, SUI stores tokens as individual coin objects. This means if you have 3 SUI tokens, they exist as three separate objects (e.g., 1 SUI + 1 SUI + 1 SUI = 3 total), not as a single balance of "3 SUI".
When you want to transfer a specific amount (like 2.5 SUI), you need to:
- Merge multiple coin objects if needed
- Split coins to get the exact amount
- Transfer the resulting coin object
Code Example: Transferring 2.5 SUI
Here's a complete TypeScript example showing how to handle this:
import { SuiClient, getFullnodeUrl } from '@mysten/sui.js/client';
import { TransactionBlock } from '@mysten/sui.js/transactions';
import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519';
// Initialize client and keypair
const client = new SuiClient({ url: getFullnodeUrl('testnet') });
const keypair = Ed25519Keypair.fromSecretKey(YOUR_SECRET_KEY);
const senderAddress = keypair.getPublicKey().toSuiAddress();
async function transferSUI(recipientAddress: string, amountInSUI: number) {
try {
// Convert SUI to MIST (1 SUI = 1,000,000,000 MIST)
const amountInMist = Math.floor(amountInSUI * 1_000_000_000);
// Step 1: Get all SUI coin objects owned by sender
const coinObjects = await client.getCoins({
owner: senderAddress,
coinType: '0x2::sui::SUI'
});
if (coinObjects.data.length === 0) {
throw new Error('No SUI coins found');
}
console.log(`Found ${coinObjects.data.length} SUI coin objects`);
coinObjects.data.forEach((coin, index) => {
console.log(`Coin ${index + 1}: ${coin.balance} MIST`);
});
// Step 2: Create transaction block
const txb = new TransactionBlock();
// Step 3: Handle coin merging and splitting
let primaryCoin;
if (coinObjects.data.length === 1) {
// Single coin - just split it
primaryCoin = coinObjects.data[0].coinObjectId;
} else {
// Multiple coins - merge them first
primaryCoin = coinObjects.data[0].coinObjectId;
const coinsToMerge = coinObjects.data.slice(1).map(coin => coin.coinObjectId);
if (coinsToMerge.length > 0) {
txb.mergeCoins(primaryCoin, coinsToMerge);
console.log(`Merging ${coinsToMerge.length} coins into primary coin`);
}
}
// Step 4: Split the exact amount needed
const [transferCoin] = txb.splitCoins(primaryCoin, [amountInMist]);
// Step 5: Transfer the split coin
txb.transferObjects([transferCoin], recipientAddress);
// Step 6: Set gas budget and execute
txb.setGasBudget(10000000); // 0.01 SUI in MIST
const result = await client.signAndExecuteTransactionBlock({
signer: keypair,
transactionBlock: txb,
options: {
showEffects: true,
showObjectChanges: true,
},
});
console.log('Transaction successful!');
console.log('Digest:', result.digest);
console.log('Gas used:', result.effects?.gasUsed);
return result;
} catch (error) {
console.error('Transfer failed:', error);
throw error;
}
}
// Usage example
async function main() {
const recipientAddress = '0x742d35cc6db7e3b6c7e4c46e7f8c7e6f1234567890abcdef';
const amountToTransfer = 2.5; // SUI
await transferSUI(recipientAddress, amountToTransfer);
}
// Run the transfer
main().catch(console.error);
Step-by-Step Breakdown
1. Fetch Coin Objects
const coinObjects = await client.getCoins({
owner: senderAddress,
coinType: '0x2::sui::SUI'
});
This retrieves all SUI coin objects owned by your address.
2. Merge Multiple Coins (if needed)
if (coinObjects.data.length > 1) {
const primaryCoin = coinObjects.data[0].coinObjectId;
const coinsToMerge = coinObjects.data.slice(1).map(coin => coin.coinObjectId);
txb.mergeCoins(primaryCoin, coinsToMerge);
}
If you have multiple coin objects, merge them into one larger coin.
3. Split Exact Amount
const [transferCoin] = txb.splitCoins(primaryCoin, [amountInMist]);
Split the exact amount you want to transfer from the merged coin.
4. Transfer the Split Coin
txb.transferObjects([transferCoin], recipientAddress);
Transfer the newly created coin object to the recipient.
Key Points to Remember
- MIST vs SUI: Always convert SUI to MIST (multiply by 1,000,000,000) when working with transactions
- Gas Budget: Set an appropriate gas budget (usually 0.01 SUI is sufficient)
- Object IDs: Each coin has a unique object ID that you reference in transactions
- Atomic Operations: All merge, split, and transfer operations happen in a single transaction
Error Handling Tips
// Check if you have enough balance
const totalBalance = coinObjects.data.reduce((sum, coin) =>
sum + parseInt(coin.balance), 0
);
if (totalBalance < amountInMist) {
throw new Error(`Insufficient balance. Have: ${totalBalance/1e9} SUI, Need: ${amountInSUI} SUI`);
}
Alternative: Using SUI SDK's Built-in Method
For simpler use cases, you can use the SDK's convenience method:
const txb = new TransactionBlock();
const [coin] = txb.splitCoins(txb.gas, [amountInMist]);
txb.transferObjects([coin], recipientAddress);
This uses the gas coin for the transfer, which works well for smaller amounts. However, if gas coin does not have required amount of SUI the above approach is required/
- Sui
- Transaction Processing
- Move
Handling coin objects in SUI feels like crafting in a game
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

- 24p30p... SUI+78
1
- MoonBags... SUI+71
2
- Meaning.Sui... SUI+43
3
- ... SUIJojo+34
- ... SUIOpiiii+31
- ... SUI0xduckmove+20
- ... SUIHaGiang+20
- ... SUIfomo on Sui+16
- ... SUI
- ... SUI
- Why does BCS require exact field order for deserialization when Move structs have named fields?53
- Multiple Source Verification Errors" in Sui Move Module Publications - Automated Error Resolution43
- Sui Transaction Failing: Objects Reserved for Another Transaction25
- How do ability constraints interact with dynamic fields in heterogeneous collections?05