TON: Wallet initialization with tonweb

To be able to use your account on TON, you need to have an initialized wallet. Wallet initialization means deploying a TON wallet contract for your account.

While this is a great feature of the TON blockchain, you might find it cumbersome dealing with wallet deployments during your development stage.

So here's a couple of scripts in JavaScript using tonweb that can help you:

  • GenerateAndInitialize.js — a script that generates a key pair for an account and then keeps running until you top it up with TON; once the account has enough TON, the script deploys a wallet contract.
  • CheckAndDepoy.js — a script that checks whether an account is initialized; if it's not initialized, the script deploys a wallet contract.

Prerequisites

Make sure tonweb is installed.

👍

Get you own node endpoint today

Start for free and get your app to production levels immediately. No credit card required.

You can sign up with your GitHub, X, Google, or Microsoft account.

GenerateAndInitialize

This script does the following:

  • Generates a key pair and saves it to wallet_keys.json
  • Keeps running and checking the balance of the generated account until it's topped up
  • Once the account is topped up, the script deploys a v4R2 wallet contract
const TonWeb = require('tonweb');
const fs = require('fs');

const httpProvider = new TonWeb.HttpProvider('CHAINSTACK_NODE_WITH_jsonRPC');
const tonweb = new TonWeb(httpProvider);

async function generateAndInitializeWallet() {
    // Generate a new key pair
    const keyPair = TonWeb.utils.nacl.sign.keyPair();
    
    // Create a v4R2 wallet instance
    const WalletClass = tonweb.wallet.all['v4R2'];
    const wallet = new WalletClass(tonweb.provider, {
        publicKey: keyPair.publicKey,
        wc: 0
    });

    // Get the wallet address
    const walletAddress = await wallet.getAddress();
    const addressString = walletAddress.toString(true, true, true);

    console.log('Generated wallet address:', addressString);
    console.log('Please send some TON to this address to initialize the wallet.');

    // Save the key pair to a file
    const keyPairData = {
        publicKey: TonWeb.utils.bytesToHex(keyPair.publicKey),
        secretKey: TonWeb.utils.bytesToHex(keyPair.secretKey)
    };
    fs.writeFileSync('wallet_keys.json', JSON.stringify(keyPairData, null, 2));
    console.log('Key pair saved to wallet_keys.json');

    // Wait for the wallet to be topped up
    await waitForBalance(walletAddress);

    // Initialize the wallet
    console.log('Initializing wallet...');
    const deployResult = await wallet.deploy(keyPair.secretKey).send();
    console.log('Deployment transaction sent:', deployResult);

    console.log('Waiting for deployment to complete...');
    await new Promise(resolve => setTimeout(resolve, 10000)); // Wait for 10 seconds

    const seqno = await wallet.methods.seqno().call();
    if (seqno !== null) {
        console.log('Wallet successfully initialized!');
    } else {
        console.log('Wallet initialization might have failed. Please check the address on a block explorer.');
    }
}

async function waitForBalance(address) {
    while (true) {
        const balance = await tonweb.getBalance(address);
        if (balance && balance !== '0') {
            console.log('Balance detected:', TonWeb.utils.fromNano(balance), 'TON');
            break;
        }
        await new Promise(resolve => setTimeout(resolve, 5000)); // Check every 5 seconds
    }
}

generateAndInitializeWallet().catch(console.error);

Make sure you put your Chainstack TON node endpoint with a /jsonRPC at the end instead of CHAINSTACK_NODE_WITH_jsonRPC.

CheckAndDepoy

This script does the following:

  • Converts the private key to an account address
  • Checks the account if it's initialized or not
  • Checks the balance
  • If the account is not initialized and has enough TON coins for wallet contract deployment, proceeds with the deployment
const TonWeb = require('tonweb');

const privateKey = 'PRIVATE_KEY';

const httpProvider = new TonWeb.HttpProvider('CHAINSTACK_NODE_WITH_jsonRPC');
const tonweb = new TonWeb(httpProvider);

async function deployWallet() {
    try {
        const keyPair = TonWeb.utils.nacl.sign.keyPair.fromSecretKey(TonWeb.utils.hexToBytes(privateKey));
        const WalletClass = tonweb.wallet.all['v4R2'];
        const wallet = new WalletClass(tonweb.provider, {
            publicKey: keyPair.publicKey,
            wc: 0
        });

        const walletAddress = await wallet.getAddress();
        console.log('Wallet address:', walletAddress.toString(true, true, true));

        const balance = await tonweb.provider.getBalance(walletAddress.toString());
        console.log('Wallet balance:', balance);

        if (balance === '0') {
            console.error('Wallet has no balance. Please add funds before deploying.');
            return;
        }

        const seqno = await wallet.methods.seqno().call();
        console.log('Seqno:', seqno);

        if (seqno === null) {
            console.log('Wallet not deployed. Deploying...');
            const deployResult = await wallet.deploy(keyPair.secretKey).send();
            console.log('Deploy result:', deployResult);
        } else {
            console.log('Wallet already deployed. Seqno:', seqno);
        }
    } catch (error) {
        console.error('Unexpected error:', error.message);
    }
}

deployWallet();

Make sure you put your Chainstack TON node endpoint with a /jsonRPC at the end instead of CHAINSTACK_NODE_WITH_jsonRPC; and put your private key inPRIVATE_KEY.

Ake

🛠️ Developer Experience Director @ Chainstack
💸 Talk to me all things Web3 infrastructure and I'll save you the costs
Ake | Warpcast Ake | GitHub Ake | Twitter Ake | LinkedIN