Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
This guide shows you how to sign TON transactions using Dynamic’s Node SDK. You build your transaction cell using @ton/ton, serialize it to a base64 string, and pass it to signTransaction(). The method returns a base64-encoded Ed25519 signature that you then attach to the cell before broadcasting.
Prerequisites
Step 1: Install Dependencies
bun add @ton/ton @ton/crypto
Step 2: Build, Sign, and Send a Transaction
The approach for signing transactions depends on how you created your wallet:
With Automatic Backup (Recommended)
If you created your wallet with backUpToClientShareService: true, you can sign directly without retrieving key shares:
import { DynamicTonWalletClient } from '@dynamic-labs-wallet/node-ton';
import { WalletContractV5R1, internal, beginCell, toNano } from '@ton/ton';
export const authenticatedTonClient = async () => {
const client = new DynamicTonWalletClient({
environmentId: process.env.DYNAMIC_ENVIRONMENT_ID!,
});
await client.authenticateApiToken(process.env.DYNAMIC_AUTH_TOKEN!);
return client;
};
const tonClient = await authenticatedTonClient();
// Build the transfer message body
const transferBody = beginCell()
.storeUint(0, 32) // op (0 = text comment)
.storeStringTail('Hello, TON!')
.endCell();
// Serialize to base64 string for signing
const transactionString = transferBody.toBoc().toString('base64');
// ✅ Simple signing - no externalServerKeyShares needed
// Returns a base64-encoded Ed25519 signature
const signature = await tonClient.signTransaction({
senderAddress: 'YourTonWalletAddress',
transaction: transactionString,
});
console.log('Signature (base64):', signature);
With Manual Backup
If you created your wallet with backUpToClientShareService: false, you must retrieve and provide external key shares:
// ⚠️ First, get external server key shares (required for manual backup)
const keyShares = await tonClient.getExternalServerKeyShares({
accountAddress: 'YourTonWalletAddress',
});
const signature = await tonClient.signTransaction({
senderAddress: 'YourTonWalletAddress',
externalServerKeyShares: keyShares, // Required for manual backup!
transaction: transactionString,
password: 'your-password', // Only if wallet was created with password
});
Password Handling Notes:
- If your wallet was created without a password, omit the
password parameter
- If your wallet was created with a password, you must provide it for all operations
- The password parameter is always optional in the API, but required if the wallet is password-protected
Step 3: Broadcast the Transaction
After signing, attach the signature to the cell and broadcast via the TON HTTP API:
import { WalletContractV5R1, Cell } from '@ton/ton';
// Reconstruct the signed external message
const signatureBuffer = Buffer.from(signature, 'base64');
// Build the signed message cell
const signedCell = beginCell()
.storeBuffer(signatureBuffer)
.storeSlice(transferBody.beginParse())
.endCell();
const boc = signedCell.toBoc().toString('base64');
const response = await fetch('https://toncenter.com/api/v2/sendBoc', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ boc }),
});
const result = await response.json();
console.log('Broadcast result:', result);
Common Transaction Bodies
const transferBody = beginCell().endCell();
const transactionString = transferBody.toBoc().toString('base64');
const transferBody = beginCell()
.storeUint(0, 32)
.storeStringTail('Payment for services')
.endCell();
const transactionString = transferBody.toBoc().toString('base64');
Next Steps