Send TON
Send native TON and estimate transaction fees.
This guide explains how to send native TON, estimate transaction fees, quote and sign a reviewed base64 BoC body, cap transaction fees, read mainnet fee rates, prepare a signed transaction body, and quote and send a signed transaction body.
On TON, values are expressed in nanotons (1 TON = 10^9 nanotons). Transactions support an optional bounceable parameter specific to the TON network.
Send Native TON
You can transfer TON to a recipient address using account.sendTransaction():
const result = await account.sendTransaction({
to: 'EQ...', // TON address
value: 1000000000, // 1 TON in nanotons
bounceable: true // Optional: specify if the address is bounceable
})
console.log('Signed transfer body hash:', result.hash)
console.log('Transaction fee:', result.fee, 'nanotons')Estimate Transaction Fees
You can get a fee estimate before sending using account.quoteSendTransaction():
const quote = await account.quoteSendTransaction({
to: 'EQ...',
value: 1000000000,
bounceable: true
})
console.log('Estimated fee:', quote.fee, 'nanotons')Quote and Sign a Reviewed Base64 BoC Body
For object inputs, TonTransaction.body can carry a base64-encoded TON BoC. WDK decodes it as a Cell only when the decoded first four bytes match a TON BoC magic; an ordinary string remains a text comment. A magic-prefixed string that is not a valid BoC throws instead of being sent as a comment.
Treat a base64 BoC as untrusted instructions. Decode and review its cell content before signing, and verify the destination, value, and bounce behavior in the transaction object. The example below only quotes and signs the reviewed body; it does not broadcast an external payload.
async function quoteAndSignReviewedBody(account, candidate, reviewTransaction) {
const review = await reviewTransaction(candidate)
if (review?.approved !== true) {
throw new Error('TON transaction was not approved')
}
const {
body: reviewedBody,
bounceable: reviewedBounceable,
to: reviewedDestination,
value: reviewedValue
} = review.transaction
const transaction = {
to: reviewedDestination,
value: reviewedValue,
body: reviewedBody,
bounceable: reviewedBounceable
}
const quote = await account.quoteSendTransaction(transaction)
const signedBody = await account.signTransaction(transaction)
return { quote, signedBody }
}reviewTransaction is an application-supplied callback. It must decode the candidate body, verify the destination, value, and optional bounceable flag, and return { approved: true, transaction } only after explicit approval. Any other result fails closed. The helper returns a quote and signed transfer-body Cell; it does not call sendTransaction().
Cap Transaction Fees
Set transactionMaxFee when you create the wallet to stop native sendTransaction() and signTransaction() calls if the estimated fee exceeds your limit.
const wallet = new WalletManagerTon(seedPhrase, {
tonClient: { url: 'https://toncenter.com/api/v2/jsonRPC' },
transactionMaxFee: 1000000000n
})Read Mainnet Fee Rates
You can retrieve mainnet TON API fee rates from the wallet manager using wallet.getFeeRates(). In 1.0.0-beta.14, this method still does not follow a configured testnet client and returns the same calculated value for normal and fast:
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'nanotons')
console.log('Fast fee rate:', feeRates.fast, 'nanotons')Prepare a Signed Transaction Body
You can build a signed transaction body without broadcasting it using account.signTransaction(). The method still requires the configured TON client to read the current sequence number and, when a fee cap is configured, estimate the fee. It returns the body Cell accepted by the matching opened WalletContractV5R1.send() call, not a complete external-message BOC.
const cell = await account.signTransaction({
to: 'EQ...', // TON address
value: 1000000000 // 1 TON in nanotons
})
// `cell` is not broadcast by signTransaction().Quote and Send a Signed Transaction Body
Pass the Cell returned by signTransaction() to the quote and send methods when review and submission are separate steps.
const cell = await account.signTransaction({
to: 'EQ...',
value: 1000000000n
})
const quote = await account.quoteSendTransaction(cell)
console.log('Estimated fee:', quote.fee, 'nanotons')
const result = await account.sendTransaction(cell)
console.log('Signed transfer body hash:', result.hash)The signed body contains the wallet sequence number read during signing. Submit it through the same matching account before that sequence number changes. WDK sends the Cell unchanged and does not rebuild or re-sign it; sendTransaction() estimates its fee again and enforces transactionMaxFee. The returned hash identifies the signed transfer body, not a network transaction hash. Pass that body hash to getTransaction() or waitForTransaction() to follow block inclusion.
Next Steps
To transfer Jetton tokens instead of native TON, see Transfer Jetton Tokens.