@tetherto/wdk-wallet-ton-gasless
v1.0.0-beta.3
Published
A simple package to manage BIP-32 wallets for the TON blockchain, which implement the gasless functionality
Downloads
1,238
Readme
@tetherto/wdk-wallet-ton-gasless
Note: This package is currently in beta. Please test thoroughly in development environments before using in production.
A simple and secure package to manage gasless transactions on the TON blockchain. This package provides a clean API for creating, managing, and interacting with TON wallets using BIP-39 seed phrases and TON-specific derivation paths, with support for gasless transactions through a paymaster system.
🔍 About WDK
This module is part of the WDK (Wallet Development Kit) project, which empowers developers to build secure, non-custodial wallets with unified blockchain access, stateless architecture, and complete user control.
For detailed documentation about the complete WDK ecosystem, visit docs.wallet.tether.io.
🌟 Features
- TON Derivation Paths: Support for BIP-44 standard derivation paths for TON (m/44'/607')
- Multi-Account Management: Create and manage multiple accounts from a single seed phrase
- Gasless Transactions: Execute transactions without requiring TON for gas fees
- Paymaster Integration: Built-in support for paymaster-based fee delegation
- Jetton Support: Query native TON and Jetton token balances using smart contract interactions
- Message Signing: Sign and verify messages using TON cryptography
⬇️ Installation
To install the @tetherto/wdk-wallet-ton-gasless package, follow these instructions:
You can install it using npm:
npm install @tetherto/wdk-wallet-ton-gasless🚀 Quick Start
Importing from @tetherto/wdk-wallet-ton-gasless
Creating a New Wallet
import WalletManagerTonGasless, {
WalletAccountTonGasless,
WalletAccountReadOnlyTonGasless
} from '@tetherto/wdk-wallet-ton-gasless'
// Use a BIP-39 seed phrase (replace with your own secure phrase)
const seedPhrase = 'test only example nut use this real life secret phrase must random'
// Create wallet manager with TON client config
const wallet = new WalletManagerTonGasless(seedPhrase, {
tonClient: {
url: 'https://toncenter.com/api/v3',
secretKey: 'your-api-key' // Optional
},
tonApiClient: {
url: 'https://tonapi.io/v3',
secretKey: 'your-ton-api-key' // Optional
},
paymasterToken: {
address: 'EQ...' // Paymaster token contract address
},
transferMaxFee: 1000000000n // Optional: Maximum fee in nanotons
})
// Get a full access account
const account = await wallet.getAccount(0)
// Convert to a read-only account
const readOnlyAccount = await account.toReadOnlyAccount()Managing Multiple Accounts
import WalletManagerTonGasless from '@tetherto/wdk-wallet-ton-gasless'
// Assume wallet is already created
// Get the first account (index 0)
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Account 0 address:', address)
// Get the second account (index 1)
const account1 = await wallet.getAccount(1)
const address1 = await account1.getAddress()
console.log('Account 1 address:', address1)
// Get account by custom derivation path
// Full path will be m/44'/607'/0'/0/5
const customAccount = await wallet.getAccountByPath("0'/0/5")
const customAddress = await customAccount.getAddress()
console.log('Custom account address:', customAddress)
// Note: All addresses are TON addresses (EQ... or UQ...)
// All accounts inherit the provider configuration from the wallet managerChecking Balances
Owned Account
For accounts where you have the seed phrase and full access:
import WalletManagerTonGasless from '@tetherto/wdk-wallet-ton-gasless'
// Assume wallet and account are already created
// Get native TON balance (in nanotons)
const balance = await account.getBalance()
console.log('Native TON balance:', balance, 'nanotons') // 1 TON = 1000000000 nanotons
// Get Jetton token balance
const jettonContract = 'EQ...'; // Jetton contract address
const jettonBalance = await account.getTokenBalance(jettonContract);
console.log('Jetton balance:', jettonBalance);
// Get paymaster token balance (important for gasless operations)
const paymasterBalance = await account.getPaymasterTokenBalance();
console.log('Paymaster token balance:', paymasterBalance);
// Note: TON client is required for balance checks
// Make sure wallet was created with a tonClient configurationRead-Only Account
For addresses where you don't have the seed phrase:
import { WalletAccountReadOnlyTonGasless } from '@tetherto/wdk-wallet-ton-gasless'
// Create a read-only account with public key
const publicKey = '...'; // Replace with the actual public key
const readOnlyAccount = new WalletAccountReadOnlyTonGasless(publicKey, {
tonClient: {
url: 'https://toncenter.com/api/v3',
secretKey: 'your-api-key' // Optional
},
tonApiClient: {
url: 'https://tonapi.io/v3',
secretKey: 'your-ton-api-key' // Optional
},
paymasterToken: {
address: 'EQ...' // Paymaster token contract address
}
})
// Check native TON balance
const balance = await readOnlyAccount.getBalance()
console.log('Native balance:', balance, 'nanotons')
// Check paymaster token balance
const paymasterBalance = await readOnlyAccount.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)
// Check any other Jetton token balance
const tokenBalance = await readOnlyAccount.getTokenBalance('EQ...')
console.log('Token balance:', tokenBalance)
// Note: Jetton balance checks use the standard Jetton wallet interface
// Make sure the contract address is correct and implements the Jetton standardSending Transactions
⚠️ Important Note: Direct transaction sending using sendTransaction() is not supported in WalletAccountTonGasless. This is a gasless implementation that handles transactions through a gasless provider instead of direct blockchain transactions.
For sending tokens, please use the transfer() method instead.
Token Transfers (Gasless)
Transfer Jetton tokens and estimate fees using WalletAccountTonGasless. Uses paymaster for gasless operations.
// Transfer Jetton tokens using gasless transactions
const transferResult = await account.transfer({
token: 'EQ...', // Jetton contract address
recipient: 'EQ...', // Recipient's TON address
amount: 1000000000n // Amount in Jetton's base units (use BigInt for large numbers)
}, {
paymasterToken: { // Optional: override default paymaster token
address: 'EQ...'
},
transferMaxFee: 1000000000n // Optional: maximum allowed fee
});
console.log('Transfer hash:', transferResult.hash);
console.log('Transfer fee:', transferResult.fee, 'nanotons');
// Quote token transfer fee
const transferQuote = await account.quoteTransfer({
token: 'EQ...', // Jetton contract address
recipient: 'EQ...', // Recipient's TON address
amount: 1000000000n // Amount in Jetton's base units
})
console.log('Transfer fee estimate:', transferQuote.fee, 'nanotons')
// Note: Gas fees are paid by the paymaster token
// Ensure sufficient paymaster token balance before transfersMessage Signing and Verification
Sign and verify messages using WalletAccountTonGasless.
// Sign a message
const message = 'Hello, TON!'
const signature = await account.sign(message)
console.log('Signature:', signature)
// Verify a signature
const isValid = await account.verify(message, signature)
console.log('Signature valid:', isValid)Fee Management
Retrieve current fee rates using WalletManagerTonGasless.
// Get current fee rates
const feeRates = await wallet.getFeeRates();
console.log('Normal fee rate:', feeRates.normal, 'nanotons');
console.log('Fast fee rate:', feeRates.fast, 'nanotons');Memory Management
Clear sensitive data from memory using dispose methods in WalletAccountTonGasless and WalletManagerTonGasless.
// Dispose wallet accounts to clear private keys from memory
account.dispose()
// Dispose entire wallet manager
wallet.dispose()📚 API Reference
Table of Contents
| Class | Description | Methods |
|-------|-------------|---------|
| WalletManagerTonGasless | Main class for managing TON wallets with gasless features. Extends WalletManager from @tetherto/wdk-wallet. | Constructor, Methods |
| WalletAccountTonGasless | Individual TON wallet account with gasless features. Extends WalletAccountReadOnlyTonGasless and implements IWalletAccount from @tetherto/wdk-wallet. | Constructor, Methods, Properties |
| WalletAccountReadOnlyTonGasless | Read-only TON wallet account with gasless features. Extends WalletAccountReadOnly from @tetherto/wdk-wallet. | Constructor, Methods |
WalletManagerTonGasless
The main class for managing TON wallets with gasless features.
Extends WalletManager from @tetherto/wdk-wallet.
Constructor
new WalletManagerTonGasless(seed, config)Parameters:
seed(string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytesconfig(object, optional): Configuration objecttonClient(object | TonClient): TON client configuration or instanceurl(string): TON Center API URL (e.g., 'https://toncenter.com/api/v3')secretKey(string, optional): API key for TON Center
tonApiClient(object | TonApiClient): TON API client configuration or instanceurl(string): TON API URL (e.g., 'https://tonapi.io/v3')secretKey(string, optional): API key for TON API
paymasterToken(object): Paymaster token configurationaddress(string): The address of the paymaster token
transferMaxFee(number | bigint, optional): Maximum fee amount for transfer operations (in nanotons)
Example:
const wallet = new WalletManagerTonGasless(seedPhrase, {
tonClient: {
url: 'https://toncenter.com/api/v3',
secretKey: 'your-api-key'
},
tonApiClient: {
url: 'https://tonapi.io/v3',
secretKey: 'your-ton-api-key'
},
paymasterToken: {
address: 'EQ...'
},
transferMaxFee: '1000000000' // Maximum fee in nanotons
})Methods
| Method | Description | Returns |
|--------|-------------|---------|
| getAccount(index) | Returns a wallet account at the specified index | Promise<WalletAccountTonGasless> |
| getAccountByPath(path) | Returns a wallet account at the specified BIP-44 derivation path | Promise<WalletAccountTonGasless> |
| getFeeRates() | Returns current fee rates for transactions | Promise<{normal: bigint, fast: bigint}> |
| dispose() | Disposes all wallet accounts, clearing private keys from memory | void |
getAccount(index)
Returns a gasless TON wallet account at the specified index using BIP-44 derivation path m/44'/607'.
Parameters:
index(number, optional): The index of the account to get (default: 0)
Returns: Promise<WalletAccountTonGasless> - The gasless TON wallet account
Example:
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Gasless TON account address:', address)getAccountByPath(path)
Returns a gasless TON wallet account at the specified BIP-44 derivation path.
Parameters:
path(string): The derivation path (e.g., "0'/0/0", "1'/0/5")
Returns: Promise<WalletAccountTonGasless> - The gasless TON wallet account
Example:
const account = await wallet.getAccountByPath("0'/0/1")
const address = await account.getAddress()
console.log('Custom path gasless address:', address)getFeeRates()
Returns current fee rates for TON transactions (used by paymaster for gasless operations).
Returns: Promise<{normal: bigint, fast: bigint}> - Object containing fee rates in nanotons
normal: Standard fee rate for normal confirmation speedfast: Higher fee rate for faster confirmation
Example:
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'nanotons')
console.log('Fast fee rate:', feeRates.fast, 'nanotons')
// Note: These fees are typically covered by the paymaster in gasless transactionsdispose()
Disposes all gasless TON wallet accounts and clears sensitive data from memory.
Returns: void
Example:
wallet.dispose()
// All gasless accounts and private keys are now securely wiped from memoryWalletAccountTonGasless
Represents an individual wallet account with gasless features. Implements IWalletAccount from @tetherto/wdk-wallet.
Constructor
new WalletAccountTonGasless(seed, path, config)Parameters:
seed(string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytespath(string): BIP-44 derivation path (e.g., "0'/0/0")config(object, optional): Configuration objecttonClient(object | TonClient): TON client configuration or instanceurl(string): TON Center API URLsecretKey(string, optional): API key for TON Center
tonApiClient(object | TonApiClient): TON API client configuration or instanceurl(string): TON API URLsecretKey(string, optional): API key for TON API
paymasterToken(object): Paymaster token configurationaddress(string): The address of the paymaster token
transferMaxFee(number | bigint, optional): Maximum fee amount for transfer operations (in nanotons)
Methods
| Method | Description | Returns |
|--------|-------------|---------|
| getAddress() | Returns the account's TON address | Promise<string> |
| sign(message) | Signs a message using the account's private key | Promise<string> |
| verify(message, signature) | Verifies a message signature | Promise<boolean> |
| transfer(options, config?) | Transfers tokens using gasless transactions | Promise<{hash: string, fee: bigint}> |
| quoteTransfer(options, config?) | Estimates the fee for a token transfer | Promise<{fee: bigint}> |
| getBalance() | Returns the native TON balance (in nanotons) | Promise<bigint> |
| getTokenBalance(tokenAddress) | Returns the balance of a specific token | Promise<bigint> |
| getPaymasterTokenBalance() | Returns the balance of the paymaster token | Promise<bigint> |
| dispose() | Disposes the wallet account, clearing private keys from memory | void |
getAddress()
Returns the account's TON address.
Returns: Promise<string> - The TON address
Example:
const address = await account.getAddress()
console.log('Gasless TON address:', address) // EQBvW8Z5...sign(message)
Signs a message using the account's private key.
Parameters:
message(string): Message to sign
Returns: Promise<string> - Signature as hex string
Example:
const signature = await account.sign('Hello TON Gasless!')
console.log('Signature:', signature)verify(message, signature)
Verifies a message signature using the account's public key.
Parameters:
message(string): Original messagesignature(string): Signature as hex string
Returns: Promise<boolean> - True if signature is valid
Example:
const isValid = await account.verify('Hello TON Gasless!', signature)
console.log('Signature valid:', isValid)transfer(options, config?)
Transfers tokens using gasless transactions where the paymaster covers transaction fees.
Parameters:
options(object): Transfer optionstoken(string): Token contract address (e.g., 'EQ...')recipient(string): Recipient TON address (e.g., 'EQ...')amount(number | bigint): Amount in token's base units
config(object, optional): Override configurationpaymasterToken(object, optional): Override default paymaster tokenaddress(string): Paymaster token address
transferMaxFee(number | bigint, optional): Override maximum fee
Returns: Promise<{hash: string, fee: bigint}> - Object containing hash and fee (typically 0 or covered by paymaster)
Example:
const result = await account.transfer({
token: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs', // USDT Jetton
recipient: 'EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG',
amount: 1000000n // 1 USDT (6 decimals)
})
console.log('Gasless transfer hash:', result.hash)
console.log('Fee (covered by paymaster):', result.fee, 'nanotons')quoteTransfer(options, config?)
Estimates the fee for a token transfer (typically covered by paymaster in gasless operations).
Parameters:
options(object): Same as transfer parameterstoken(string): Token contract addressrecipient(string): Recipient TON addressamount(number | bigint): Amount in token's base units
config(object, optional): Same as transfer configurationpaymasterToken(object, optional): Override default paymaster tokentransferMaxFee(number | bigint, optional): Override maximum fee
Returns: Promise<{fee: bigint}> - Object containing estimated fee (typically 0 or covered by paymaster)
Example:
const quote = await account.quoteTransfer({
token: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs', // USDT Jetton
recipient: 'EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG',
amount: 1000000n // 1 USDT (6 decimals)
})
console.log('Estimated fee (paymaster will cover):', quote.fee, 'nanotons')getBalance()
Returns the account's native TON balance in nanotons.
Returns: Promise<bigint> - Balance in nanotons
Example:
const balance = await account.getBalance()
console.log('TON balance:', balance, 'nanotons')
console.log('Balance in TON:', Number(balance) / 1e9)getTokenBalance(tokenAddress)
Returns the balance of a specific token (Jetton).
Parameters:
tokenAddress(string): The token contract address
Returns: Promise<bigint> - Token balance in token's smallest unit
Example:
// Get USDT Jetton balance (6 decimals)
const usdtBalance = await account.getTokenBalance('EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs')
console.log('USDT balance:', Number(usdtBalance) / 1e6)getPaymasterTokenBalance()
Returns the balance of the paymaster token used for gasless operations.
Returns: Promise<bigint> - Paymaster token balance in token's smallest unit
Example:
const paymasterBalance = await account.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)
// This balance is used to cover transaction fees in gasless operationsdispose()
Disposes the wallet account, securely erasing the private key from memory.
Returns: void
Example:
account.dispose()
// Private key is now securely wiped from memoryProperties
| Property | Type | Description |
|----------|------|-------------|
| index | number | The derivation path's index of this account |
| path | string | The full derivation path of this account |
| keyPair | object | The account's key pair (⚠️ Contains sensitive data) |
⚠️ Security Note: The keyPair property contains sensitive cryptographic material. Never log, display, or expose the private key.
WalletAccountReadOnlyTonGasless
Represents a read-only wallet account with gasless features.
Constructor
new WalletAccountReadOnlyTonGasless(publicKey, config)Parameters:
publicKey(string | Uint8Array): The account's public keyconfig(object, optional): Configuration objecttonClient(object | TonClient): TON client configuration or instanceurl(string): TON Center API URLsecretKey(string, optional): API key for TON Center
tonApiClient(object | TonApiClient): TON API client configuration or instanceurl(string): TON API URLsecretKey(string, optional): API key for TON API
paymasterToken(object): Paymaster token configurationaddress(string): The address of the paymaster token
Methods
| Method | Description | Returns |
|--------|-------------|---------|
| getBalance() | Returns the native TON balance (in nanotons) | Promise<bigint> |
| getTokenBalance(tokenAddress) | Returns the balance of a specific token | Promise<bigint> |
| getPaymasterTokenBalance() | Returns the balance of the paymaster token | Promise<bigint> |
| quoteTransfer(options, config?) | Estimates the fee for a token transfer | Promise<{fee: bigint}> |
getBalance()
Returns the account's native TON balance in nanotons.
Returns: Promise<bigint> - Balance in nanotons
Example:
const balance = await readOnlyAccount.getBalance()
console.log('TON balance:', balance, 'nanotons')
console.log('Balance in TON:', Number(balance) / 1e9)getTokenBalance(tokenAddress)
Returns the balance of a specific token (Jetton).
Parameters:
tokenAddress(string): The token contract address
Returns: Promise<bigint> - Token balance in token's smallest unit
Example:
// Get USDT Jetton balance (6 decimals)
const usdtBalance = await readOnlyAccount.getTokenBalance('EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs')
console.log('USDT balance:', Number(usdtBalance) / 1e6)getPaymasterTokenBalance()
Returns the balance of the paymaster token used for gasless operations.
Returns: Promise<bigint> - Paymaster token balance in token's smallest unit
Example:
const paymasterBalance = await readOnlyAccount.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)
// This balance indicates how much the account can use for gasless transactionsquoteTransfer(options, config?)
Estimates the fee for a token transfer (typically covered by paymaster in gasless operations).
Parameters:
options(object): Transfer optionstoken(string): Token contract addressrecipient(string): Recipient TON addressamount(number | bigint): Amount in token's base units
config(object, optional): Override configurationpaymasterToken(object, optional): Override default paymaster tokenaddress(string): Paymaster token address
transferMaxFee(number | bigint, optional): Override maximum fee
Returns: Promise<{fee: bigint}> - Object containing estimated fee (typically 0 or covered by paymaster)
Example:
const quote = await readOnlyAccount.quoteTransfer({
token: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs', // USDT Jetton
recipient: 'EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG',
amount: 1000000n // 1 USDT (6 decimals)
})
console.log('Estimated fee (paymaster will cover):', quote.fee, 'nanotons')
console.log('Estimated fee in TON:', Number(quote.fee) / 1e9)🌐 Supported Networks
This package works with the TON blockchain, including:
- TON Mainnet
- TON Testnet
🔒 Security Considerations
- Seed Phrase Security: Always store your seed phrase securely and never share it
- Private Key Management: The package handles private keys internally with memory safety features using sodium-universal
- Provider Security: Use trusted TON Center and TON API endpoints
- Transaction Validation: Always validate transaction details before signing
- Memory Cleanup: Use the
dispose()method to clear private keys from memory when done - Fee Limits: Set
transferMaxFeein config to prevent excessive transaction fees - Address Validation: Be careful with bounceable vs non-bounceable addresses
- Paymaster Token: Ensure sufficient paymaster token balance for gasless operations
- API Keys: Securely manage both TON Center and TON API keys
- Gasless Provider: Validate gasless provider configuration and token allowances
🛠️ Development
Building
# Install dependencies
npm install
# Build TypeScript definitions
npm run build:types
# Lint code
npm run lint
# Fix linting issues
npm run lint:fixTesting
# Run tests
npm test
# Run tests with coverage
npm run test:coverage📜 License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
🆘 Support
For support, please open an issue on the GitHub repository.
