Sending transaction

Building transaction using TON blockchain to send inscriptions using GRAM-20 protocol.

import { Address, beginCell, internal, loadStateInit, toNano } from "@ton/core";
import { WalletContractV3R2, TonClient, WalletContractV4 } from "@ton/ton";
import { mnemonicToWalletKey } from "@ton/crypto";
import { configDotenv } from "dotenv";

type TransferParams = {
    recipient: Address;
    value: string;
    memo?: string;
}

async function getTransferInscriptionMsg(client: TonClient, rootAddress: Address, userAddress: Address, params: TransferParams) {
    let tick = '';
    let protocolFee = 0n;

    while(true) {
        try {
            const rootData = await client.runMethod(rootAddress, 'get_root_data', []);
            const tokenData = await client.runMethod(rootAddress, 'get_token_data', []);
            
            rootData.stack.skip(2);
            tick = rootData.stack.readString();
            tokenData.stack.skip(5);
            protocolFee = tokenData.stack.readBigNumber();
            
            break;
        } catch {
            await sleep(300);
        }
    }

    let userData;
    while(true) {
        try {
            userData = await client.runMethod(rootAddress, 'get_user_data', [
                { type: 'slice', cell: beginCell().storeAddress(userAddress).endCell() },
            ]);
            break;
        } catch {
            await sleep(300);
            continue;
        }
    }
    const userStateInit = loadStateInit(userData.stack.readCell().beginParse());
    const userContractAddress = userData.stack.readAddress();
    let userSCState;
    while(true) {
        try {
            userSCState = await client.getContractState(userContractAddress);
            break;
        } catch {
            await sleep(300);
            continue;
        }
    }
    const userSCActive = userSCState.state === 'active';

    let transferPayload = '';
    if (params.memo) {
      transferPayload = `data:application/json,{"p":"gram-20","op":"transfer","tick":"${tick}","amt":"${params.value}","to":"${params.recipient.toString({bounceable: true})}","memo":"${params.memo}"}`;
    } else {
      transferPayload = `data:application/json,{"p":"gram-20","op":"transfer","tick":"${tick}","amt":"${params.value}","to":"${params.recipient.toString({bounceable: true})}"}`;
    }
    if (!userSCActive) {
        return internal({
            to: userContractAddress,
            value: toNano(0.007),
            init: userStateInit,
            body: beginCell().storeUint(0, 32).storeStringTail(transferPayload).endCell(),
        })
    } else {
        return internal({
            to: userContractAddress,
            value: toNano(0.006),
            body: beginCell().storeUint(0, 32).storeStringTail(transferPayload).endCell(),
        })
    }
}

async function main() {
    configDotenv();
    const transferParams: TransferParams = {
        recipient: Address.parse(''),
        value: '1',
        // memo: 'test'
    }
    const rootTokenAddress = Address.parse('');

    const client = new TonClient({
      endpoint: 'https://toncenter-v4.gram20.com/jsonRPC'
    });
    if (process.env.WALLET_VERSION !== 'V3R2' && process.env.WALLET_VERSION !== 'V4R2') {
      throw new Error('Invalid wallet type');
    }
    if (!process.env.WALLET_MNEMONIC) {
      throw new Error('Mnemonic not found');
    }
    const keys = await mnemonicToWalletKey(process.env.WALLET_MNEMONIC.split(' '));
    let wallet: WalletContractV3R2 | WalletContractV4;
    if (process.env.WALLET_VERSION === 'V3R2') {
      wallet = WalletContractV3R2.create({
        workchain: 0,
        publicKey: keys.publicKey,
      });
    } else {
      wallet = WalletContractV4.create({
        workchain: 0,
        publicKey: keys.publicKey,
      });
    }
    console.log(`Wallet address: ${wallet.address.toString()}`)
    const contract = client.open(wallet);
    const transferMsg = await getTransferInscriptionMsg(client, rootTokenAddress, wallet.address, transferParams);
    // console.log(`--- Transfer message ---`);
    // console.log(transferMsg);
    await contract.sendTransfer({
        seqno: await contract.getSeqno(),
        secretKey: keys.secretKey,
        messages: [transferMsg],
    });
}

main()

function sleep(ms: number) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

Last updated