Usage

Installation, quick start, and usage examples for @tetherto/wdk-wallet-ton-gasless

Installation

To install the @tetherto/wdk-wallet-ton-gasless package, follow these instructions:

npm install @tetherto/wdk-wallet-to-gasless

Quick Start

Importing from @tetherto/wdk-wallet-ton-gasless

  1. WalletManagerTonGasless: Main class for managing wallets with gasless features

  2. WalletAccountTonGasless: Use this for full access accounts with gasless transactions

  3. WalletAccountReadOnlyTonGasless: Use this for read-only accounts

Creating a New Gasless 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 = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'


// Create gasless wallet manager with TON RPC and TON API endpoints, and paymaster token 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
  }, // Paymaster Jetton master contract address
  transferMaxFee: 10000000 // Maximum fee for transfer operations (in paymaster Jetton base units)
})

// 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
const customAccount = await wallet.getAccountByPath("0'/0/5")
const customAddress = await customAccount.getAddress()
console.log('Custom account address:', customAddress)

Checking 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')

// Get Jetton token balance
const jettonAddress = 'EQ...'; // Jetton contract address
const jettonBalance = await account.getTokenBalance(jettonAddress);
console.log('Jetton token balance:', jettonBalance);

// Get paymaster Jetton balance
const paymasterBalance = await account.getPaymasterTokenBalance()
console.log('Paymaster Jetton balance:', paymasterBalance)

Read-Only Account

For addresses where you don't have the seed phrase:

import { WalletAccountReadOnlyTonGasless } from '@tetherto/wdk-wallet-ton-gasless'

// Use the public key directly
const publicKey = '...'; // Replace with the actual public key

// Create a read-only account
const readOnlyAccount = new WalletAccountReadOnlyTonGasless(publicKey, {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key' // Optional
  },tonApiClient: {
    url: 'https://tonapi.io/v2',
    secretKey: 'your-ton-api-key' // Optional
  },
  paymasterToken: {
    address: 'EQ...' // Paymaster Jetton contract address
  }
})

// Check balances
const balance = await readOnlyAccount.getBalance()
console.log('Native TON balance:', balance)

// Check paymaster token balance
const paymasterBalance = await readOnlyAccount.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)

// Check any other token balance
const tokenBalance = await readOnlyAccount.getTokenBalance('EQC...')
console.log('Token balance:', tokenBalance)

Sending Transactions

⚠️ Direct transaction sending using sendTransaction() is not supported in WalletAccountTonGasless. This is a gasfree implementation that handles transactions through a gasfree provider instead of direct blockchain transactions.

For sending tokens, please use the transfer() method instead.

Jetton Token Transfers (Gasless)

Transfer Jetton tokens and estimate fees using WalletAccountTonGasless. Requires TON Center client configuration.

// Gasless transfer of Jettons (fee paid in paymaster Jetton)
const result = await account.transfer({
  token: 'EQ...',      // Jetton master contract address
  recipient: 'EQ...',  // Recipient's TON address
  amount: 1000000000    // Amount in Jetton's base units
}, {
  paymasterToken: {    // Optional: override default paymaster token
    address: 'EQ...'
  },
  transferMaxFee: 1000000   transferMaxFee: 1000000 // Optional: maximum allowed fee
})
console.log('Transfer hash:', transferResult.hash);
console.log('Transfer fee:', transferResult.fee, 'nanotons');

// Quote gasless transfer fee
const quote = await account.quoteTransfer({
  token: 'EQ...',      // Jetton contract address
  recipient: 'EQ...',  // Recipient's TON address
  amount: 1000000      // Amount in Jetton's base units 
})
console.log('Transfer fee estimate:', transferQuote.fee, 'nanotons')

Message 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()

Complete Examples

Complete Wallet Setup

import WalletManagerTonGasless from '@tetherto/wdk-wallet-ton-gasless'

async function setupWallet() {
  try {
    // Use a BIP-39 seed phrase (replace with your own secure phrase)
    const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
    
    // Create gasless wallet manager
    const wallet = new WalletManagerTonGasless(seedPhrase, {
      tonClient: {
        url: 'https://toncenter.com/api/v3',
        secretKey: 'your-api-key' // Optional
      },
      tonApiClient: {
        url: 'https://tonapi.io/v2',
        secretKey: 'your-tonapi-key' // Optional but recommended
      },
      paymasterToken: {
        address: 'EQ...' // REQUIRED: Paymaster token address
      },
      transferMaxFee: 1000000000 // Optional: Maximum fee in nanotons
    })
    
    // Get first account
    const account = await wallet.getAccount(0)
    const address = await account.getAddress()
    console.log('Wallet address:', address)
    // Check balances
    const balance = await account.getBalance()
    const paymasterBalance = await account.getPaymasterTokenBalance()
    console.log('TON balance:', balance, 'nanotons')
    console.log('Paymaster token balance:', paymasterBalance)
    
    return { wallet, account, address, balance }
  } catch (error) {
    console.error('Failed to setup wallet:', error)
    throw error
  }
}

Multi-Account Management

async function manageMultipleAccounts(wallet) {
  try {
    const accounts = []
    
    // Create 5 accounts
    for (let i = 0; i < 5; i++) {
      const account = await wallet.getAccount(i)
      const address = await account.getAddress()
      const balance = await account.getBalance()
      const paymasterBalance = await account.getPaymasterTokenBalance()
      
      accounts.push({
        index: i,
        address,
        balance,
        paymasterBalance
      })
    }
    return accounts
  } catch (error) {
    console.error('Failed to manage accounts:', error)
    throw error
  } finally {
    // Clean up when done to remove sensitive data from memory
    wallet.dispose()
  }
}

Advanced Transaction Example

async function sendAdvancedGaslessTransfer(account) {
  try {
    // Check paymaster token balance first
    const paymasterBalance = await account.getPaymasterTokenBalance()
    console.log('Paymaster token balance:', paymasterBalance)
    
    // Get transfer quote first
    const quote = await account.quoteTransfer({
      token: 'EQ...',      // Jetton master contract address
      recipient: 'EQ...',  // Recipient's TON address
      amount: 1000000000   // Amount in Jetton's base units
    })
    
    console.log('Estimated fee (paymaster token):', quote.fee)
      // Execute gasless transfer
    const result = await account.transfer({
      token: 'EQ...',
      recipient: 'EQ...',
      amount: 1000000000
    }, {
      paymasterToken: {     // Optional: override default paymaster
        address: 'EQ...'
      },
      transferMaxFee: 2000000000 // Optional: override max fee
    })

    console.log('Transfer hash:', result.hash)
    console.log('Actual fee (paymaster token):', result.fee)

    return result
  }catch (error) {
    console.error('Transfer failed:', error)
    throw error
  }
}

Token Transfer with Validation

async function transferJettonWithValidation(account, jettonAddress, recipient, amount) {
  try {
    // Validate Jetton address (TON format)
    if (!jettonAddress.startsWith('EQ')) {
      throw new Error('Invalid Jetton address format')
    }

    // Validate recipient address (TON format)
    if (!recipient.startsWith('EQ')) {
      throw new Error('Invalid recipient address format')
    }

    // Check Jetton balance
    const balance = await account.getTokenBalance(jettonAddress)
    if (balance < amount) {
      throw new Error('Insufficient Jetton balance')
    }
     // Check paymaster token balance
    const paymasterBalance = await account.getPaymasterTokenBalance()
    console.log('Paymaster token balance:', paymasterBalance)

    // Get transfer quote (fee is in paymaster token units)
    const quote = await account.quoteTransfer({
      token: jettonAddress,
      recipient,
      amount
    })

    console.log('Transfer fee estimate (paymaster token):', quote.fee)

    // Execute transfer if fee is acceptable
    const result = await account.transfer({
      token: jettonAddress,
      recipient,
      amount
    })
     console.log('Transfer hash:', result.hash)
    console.log('Actual fee (paymaster token):', result.fee)
    
    return result
  } catch (error) {
    console.error('Transfer failed:', error)
    throw error
  }
}

Error Handling and Memory Management

async function safeTransferExample(account, wallet) {
  try {
    // Check balances first
    const jettonBalance = await account.getTokenBalance('EQ...')
    const paymasterBalance = await account.getPaymasterTokenBalance()
    const transferAmount = 1000000000

    if (jettonBalance < transferAmount) {
      throw new Error('insufficient jetton balance')
    }

    if (paymasterBalance < 1000000) { // Minimum paymaster balance check
      throw new Error('insufficient paymaster balance')
    }
    // Get fee estimate
    const quote = await account.quoteTransfer({
      token: 'EQ...',
      recipient: 'EQ...',
      amount: transferAmount
    })

    console.log('Estimated fee (paymaster token):', quote.fee)

    // Execute transfer
    const result = await account.transfer({
      token: 'EQ...',
      recipient: 'EQ...',
      amount: transferAmount
    })

    console.log('Transfer successful:', result.hash)
    return result
      } catch (error) {
    if (error.message.includes('insufficient jetton balance')) {
      console.error('Please add more Jetton tokens to your wallet')
    } else if (error.message.includes('insufficient paymaster balance')) {
      console.error('Please add more paymaster tokens for gas fees')
    } else if (error.message.includes('invalid address')) {
      console.error('The recipient address is invalid')
    } else if (error.message.includes('max fee')) {
      console.error('The transfer fee exceeds your configured maximum')
    } else {
      console.error('Transfer failed:', error.message)
    }
    throw error

  } finally {
    // Always clean up sensitive data
    account.dispose()
    wallet.dispose()
  }
}

Need Help?