TON DocsTON Docs
OnboardingNodesApplicationsAPIsContractsSmart contractsTolkTolk languageTVMTON Virtual MachineFoundationsBlockchain foundations

How to interact with preprocessed wallet v2

Community implementation

This wallet is a community-created implementation. Test it on testnet before using it with real funds.

  • Code hash: 45ebbce9b5d235886cb6bfe1c3ad93b708de058244892365c9ee0dfe439cb7b5
  • Source: pw-code.fif on GitHub

Funds at risk

This guide sends real GRAM. Test on testnet first. Double-check recipient addresses — blockchain transactions cannot be reversed.

This guide shows how to deploy Preprocessed Wallet V2 and send transfers.

The Preprocessed Wallet V2 specification documents its storage and message formats.

Objective

By the end of this guide, you will:

  • Create a Preprocessed Wallet V2 instance from scratch
  • Deploy the wallet on-chain
  • Send single and batch transfers

Prerequisites

This guide uses TypeScript with the official wrapper. The same logic applies to other SDKs (Go/Python): generate or load a mnemonic, derive a keypair, and calculate the address.

Step 1: Set up dependencies

Install required packages:

npm install @ton/ton @ton/core @ton/crypto

Copy typescript/wrappers/PreprocessedWalletV2.ts and the compiled contract code from the official repository.

Why copy wrappers?

The official @ton/ton SDK does not include Preprocessed Wallet V2 wrappers yet. Copy PreprocessedWalletV2.ts from the repository until SDK support is added.

Step 2: Generate or load a mnemonic

A wallet mnemonic derives the private key used to sign transactions. The wallet ownership guide explains how the contract verifies signatures.

Generate a new mnemonic

import { mnemonicNew } from '@ton/crypto';

const mnemonic = await mnemonicNew(24);

Load an existing mnemonic

const mnemonic = process.env.TON_WALLET_MNEMONIC.split(' ');

Pass the environment variable TON_WALLET_MNEMONIC containing a valid space-separated 24-word mnemonic for the wallet.

Protect your mnemonic

Anyone with access to your mnemonic can control your wallet and all funds. Store it securely (password manager, hardware wallet, encrypted storage). Never commit it to version control.

Step 3: Derive the keypair

Convert the mnemonic to an Ed25519 keypair:

// Not runnable: requires the mnemonic from the previous step.
import { mnemonicToPrivateKey } from '@ton/crypto';

const keyPair = await mnemonicToPrivateKey(mnemonic);

Use keyPair.publicKey in the contract state and keyPair.secretKey to sign external messages.

Step 4: Create the wallet instance

Create a Preprocessed Wallet V2 contract instance. The wrapper exports its compiled code as walletCode.

The example uses TON Center's testnet endpoint. An API key is optional; if needed, request one from @tonapibot or @tontestnetapibot.

// Not runnable: requires the keyPair from Step 3 and the copied wrapper.
import { TonClient } from '@ton/ton';
import { Cell } from '@ton/core';
import { Wallet, walletCode } from './wrappers/PreprocessedWalletV2';

// Compiled contract code (BoC)
const CODE = walletCode;

const client = new TonClient({
    endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
});

const wallet = client.open(
    Wallet.createFromPublicKey(keyPair.publicKey)
);

Step 5: Get the wallet address

Calculate the wallet's address:

// Not runnable: requires the wallet instance from Step 4.
// Get non-bounceable address for funding
const address = wallet.address.toString({ bounceable: false, testOnly: true });
console.log('Wallet address:', address);

The output is the wallet's non-bounceable testnet address. It is deterministic: the same CODE and publicKey produce the same address.

Why non-bounceable?

When funding a nonexist account, use the non-bounceable format to prevent funds from bouncing back if the account doesn't exist yet. The address formats reference describes bounceable and non-bounceable forms.

Account status: nonexist

The calculated address exists only as a deterministic value. No account exists on the blockchain yet — no balance, no code, no data.


Step 6: Fund the wallet

Funds at risk

You will send GRAM to this address. Test on testnet first. Verify the wallet address carefully — blockchain transactions cannot be reversed.

Required before deployment: Send GRAM to your wallet address (from Step 5) to prepare it for deployment.

An external-in message that deploys the wallet requires Gram to pay for execution. By funding the address, you transition the account from nonexist to uninit status and provide the balance needed for deployment. The account status reference describes this transition.

Send GRAM using a faucet (testnet) or from another wallet (mainnet). After funding, the account transitions to uninit status — it has a balance and can accept external messages, but no code or data yet.


Step 7: Send messages

Automatic deployment

The wallet will auto-deploy on the first external message. No separate deployment step is needed.

Send single transfers

Replace <TESTNET_RECIPIENT_ADDRESS> with an address you control on testnet.

// Not runnable: requires the active testnet wallet and keyPair from earlier steps.
import { Address, toNano } from '@ton/ton';

// Get current sequence number
const currentSeqno = Number(await wallet.getSeqno());

// Send a single transfer
await wallet.sendTransfers(keyPair, [{
    to: Address.parse('<TESTNET_RECIPIENT_ADDRESS>'),
    value: toNano('0.01'),
    bounce: false
}], currentSeqno);

console.log('Transfer sent');

Send batch transfers

// Not runnable: requires the active testnet wallet and keyPair from earlier steps.
import { Address, toNano, comment } from '@ton/ton';

// Get current sequence number
const currentSeqno = Number(await wallet.getSeqno());

// Create multiple transfers with similar structure
const transfers = [];
for (let i = 0; i < 5; i++) {
    transfers.push({
        to: Address.parse('<TESTNET_RECIPIENT_ADDRESS>'),
        value: toNano('0.01'),
        body: comment(`#${i}`)
    });
}

// Send batch transfers
await wallet.sendTransfers(keyPair, transfers, currentSeqno);

console.log('Batch transfers sent');

Maximum actions

Preprocessed Wallet V2 limits each request to 255 outgoing actions.

On this page