Guides Overview
Practical guides for common TON blockchain tasks using Ton.NET.
Getting Started
New to Ton.NET? Start here:
- Installation - Set up Ton.NET in your project
- First Steps - Basic operations and concepts
- Key Concepts - Understanding TON fundamentals
Common Tasks
Wallet Management
Create New Wallet
using Ton.Crypto.Mnemonic;
using Ton.Contracts.Wallets.V5;
// Generate mnemonic
string[] mnemonic = Mnemonic.New(24);
// Derive keys
KeyPair keys = Mnemonic.ToWalletKey(mnemonic);
// Create wallet
WalletV5R1 wallet = new(keys.PublicKey);
Console.WriteLine($"Address: {wallet.Address}");
Console.WriteLine($"Mnemonic: {string.Join(" ", mnemonic)}");
Recover Wallet
// Get mnemonic from user
string[] mnemonic = GetMnemonicFromUser();
// Validate
if (!Mnemonic.Validate(mnemonic))
{
throw new ArgumentException("Invalid mnemonic");
}
// Restore wallet
KeyPair keys = Mnemonic.ToWalletKey(mnemonic);
WalletV5R1 wallet = new(keys.PublicKey);
Check Balance
using Ton.LiteClient;
LiteClient client = await LiteClientFactory.CreateFromUrlAsync(
"https://ton.org/global-config.json"
);
MasterchainInfo info = await client.GetMasterchainInfoAsync();
AccountState state = await client.GetAccountStateAsync(wallet.Address, info.Last);
Console.WriteLine($"Balance: {state.BalanceInTon:F4} TON");
Console.WriteLine($"State: {state.State}");
Sending Transactions
Simple Transfer
Address destination = Address.Parse("...");
decimal amount = 1.5m; // TON
// Get seqno
int seqno = await GetCurrentSeqno(client, wallet.Address);
// Create transfer
var actions = new[]
{
WalletV5OutActions.SendMessage(
mode: SendMode.PayGasSeparately | SendMode.IgnoreErrors,
message: CreateInternalMessage(
destination,
Coins.FromNano((long)(amount * 1_000_000_000))
)
)
};
Cell body = wallet.CreateTransferBody(
keys.SecretKey,
wallet.WalletId,
DateTimeOffset.UtcNow.AddMinutes(5).ToUnixTimeSeconds(),
seqno,
actions
);
// Send (see module documentation for sending)
Transfer with Comment
string comment = "Payment";
Cell commentCell = Builder.BeginCell()
.StoreUint(0, 32)
.StoreString(comment)
.EndCell();
// Use commentCell as message body
Querying Blockchain
Get Account Info
LiteClient client = await LiteClientFactory.CreateFromUrlAsync(...);
MasterchainInfo info = await client.GetMasterchainInfoAsync();
Address address = Address.Parse("...");
AccountState state = await client.GetAccountStateAsync(address, info.Last);
Console.WriteLine($"Balance: {state.BalanceInTon} TON");
Console.WriteLine($"Is active: {state.IsActive}");
Console.WriteLine($"Is contract: {state.IsContract}");
if (state.Code != null)
{
Console.WriteLine($"Code hash: {Convert.ToHexString(state.Code.Hash(0))}");
}
Get Recent Blocks
MasterchainInfo info = await client.GetMasterchainInfoAsync();
Console.WriteLine($"Latest block: {info.Last.Seqno}");
// Get block from 1 hour ago
int timestamp = (int)DateTimeOffset.UtcNow.AddHours(-1).ToUnixTimeSeconds();
BlockId oldBlock = await client.LookupBlockByUtimeAsync(-1, -9223372036854775808, timestamp);
Console.WriteLine($"Block 1h ago: {oldBlock.Seqno}");
List Transactions in Block
BlockTransactions txs = await client.ListBlockTransactionsAsync(blockId, count: 100);
foreach (BlockTransaction tx in txs.Transactions)
{
Console.WriteLine($"Account: {Convert.ToHexString(tx.AccountHash)}");
Console.WriteLine($"LT: {tx.Lt}");
}
Working with Cells
Build Cell
using Ton.Core.Boc;
Builder builder = Builder.BeginCell();
builder.StoreUint(123, 32);
builder.StoreAddress(address);
builder.StoreCoins(1_000_000_000);
builder.StoreBit(true);
Cell ref = Builder.BeginCell().StoreUint(456, 32).EndCell();
builder.StoreRef(ref);
Cell cell = builder.EndCell();
Read Cell
Slice slice = cell.BeginParse();
uint value = slice.LoadUint(32);
Address addr = slice.LoadAddress();
BigInteger coins = slice.LoadCoins();
bool flag = slice.LoadBit();
Cell ref = slice.LoadRef();
Serialize/Deserialize
// To BOC
byte[] boc = cell.ToBoc();
File.WriteAllBytes("data.boc", boc);
// From BOC
byte[] data = File.ReadAllBytes("data.boc");
Cell[] cells = Cell.FromBoc(data);
Cell root = cells[0];
Cryptography
Generate Keys
using Ton.Crypto.Mnemonic;
using Ton.Crypto.Ed25519;
string[] mnemonic = Mnemonic.New(24);
KeyPair keys = Mnemonic.ToWalletKey(mnemonic);
Sign and Verify
byte[] message = Encoding.UTF8.GetBytes("Hello");
// Sign
byte[] signature = Ed25519.Sign(message, keys.SecretKey);
// Verify
bool isValid = Ed25519.Verify(signature, message, keys.PublicKey);
Hash Data
using Ton.Crypto.Primitives;
byte[] data = Encoding.UTF8.GetBytes("data");
byte[] hash = Sha256.Hash(data);
Advanced Topics
Multiple Transfers in One Transaction
var actions = new[]
{
WalletV5OutActions.SendMessage(...), // Transfer 1
WalletV5OutActions.SendMessage(...), // Transfer 2
WalletV5OutActions.SendMessage(...) // Transfer 3
};
Cell body = wallet.CreateTransferBody(keys.SecretKey, ..., actions);
Custom Wallet IDs
int customWalletId = WalletV5R1WalletId.Create(
networkGlobalId: -239, // mainnet
workchain: 0,
subwalletNumber: 0,
version: 0
);
WalletV5R1 wallet = new(keys.PublicKey, walletId: customWalletId);
Parse MerkleProof
// Get header with proof
BlockHeader header = await client.GetBlockHeaderAsync(blockId);
// Parse proof
Cell proofCell = Cell.FromBoc(header.HeaderProof)[0];
Cell actualData = proofCell.UnwrapProof();
// Now parse actual data
Slice slice = actualData.BeginParse();
// ... parse block header
Round-Robin Connection
// Automatic from global config
LiteClient client = await LiteClientFactory.CreateFromUrlAsync(
"https://ton.org/global-config.json"
);
// Manual setup
var servers = new[]
{
("server1.com", 14432, "base64_key1"),
("server2.com", 14432, "base64_key2")
};
LiteClient roundRobin = LiteClientFactory.CreateRoundRobin(servers);
Troubleshooting
Common Issues
"Invalid mnemonic"
// Always validate user input
if (!Mnemonic.Validate(mnemonic))
{
Console.WriteLine("Mnemonic is invalid");
return;
}
"Insufficient balance"
// Check balance before sending
AccountState state = await client.GetAccountStateAsync(address, block);
if (state.Balance < amountToSend + estimatedFee)
{
throw new InvalidOperationException("Insufficient balance");
}
"Transaction not confirmed"
// Wait for seqno increase
int oldSeqno = currentSeqno;
for (int i = 0; i < 30; i++)
{
await Task.Delay(2000);
int newSeqno = await GetCurrentSeqno(client, address);
if (newSeqno > oldSeqno)
{
Console.WriteLine("Confirmed!");
break;
}
}
"Connection timeout"
// Increase timeout or retry
try
{
result = await client.GetAccountStateAsync(address, block, timeout: 10000);
}
catch (TimeoutException)
{
// Retry with different server or increase timeout
}
Best Practices
- Always validate addresses before sending TON
- Check balances before creating transactions
- Set appropriate timeouts (5 minutes recommended)
- Clear private keys from memory after use
- Use round-robin for production applications
- Handle errors gracefully with retries
- Cache rarely-changing data when possible
Module-Specific Guides
For detailed module documentation:
- LiteClient - Blockchain queries
- Core - Data structures
- Crypto - Cryptography
- Contracts - Wallets
- HttpClient - HTTP API
Example Projects
Check out the /samples directory in the repository:
- LiteClientPlayground - LiteClient usage examples
- AdnlSample - Low-level ADNL protocol usage
Getting Help
- Documentation: Read module-specific guides
- GitHub Issues: Report bugs or request features
- Examples: Check sample projects in repository