Skip to content

Instantly share code, notes, and snippets.

@sench93
Last active May 23, 2023 12:33
Show Gist options
  • Save sench93/09b127901e4bdd455f08886d7b46b4d1 to your computer and use it in GitHub Desktop.
Save sench93/09b127901e4bdd455f08886d7b46b4d1 to your computer and use it in GitHub Desktop.
πŸ’‘ Smart Description: This code sends a specified amount of cryptocurrency to a specified address, with an optional message. If the "wait" parameter is true, it waits for the transaction to be confirmed and returns the transaction hash.

Async Ton Transfer Function.

Preview:
import TonWeb from "tonweb";
import {generateMnemonic, mnemonicToKeyPair} from "tonweb-mnemonic"
const MNEMONIC_OF_EXISTING_WALLET = ""
const DESTINATION_ADDRESS = ""
const API_KEY = "";
async function createDeploySend(){
    
    //STEP 1 , you need to create a wallet. Creation will return an object with bouncable address ,
    // nonbounceable address , mnemonic. Save address and mnemonics somewhere when you are live.
    
    let createResult:any = await createTonWallet();
    let newMnemonic:string = createResult.mnemonic
    //STEP 2 , you need to fund your newly created wallet with some fund because on next step you need to deploy a contract which is not free.
    // MNEMONIC_OF_EXISTING_WALLET must be used to send from exisitng wallet to 0.02 TON to newly created wallet.
    // Note that we will use deployAddress from create result for funding ( non bounceable address), because if we use normal address funds will go back. 
    // Also we have to wait for result to go to next step.
    
    let fundingResult = await sendTon(MNEMONIC_OF_EXISTING_WALLET,"20000000",createResult.deployAddress,"some message",true);
    
    //STEP 3 , as wallets are smart contracts too, we have to deploy smart contract of wallet to blockchain in order it becomes a wallet.
    // We will use mnemonic of newly created wallet.
    
    let deployResult =  await deployWallet(createResult.mnemonic)
    await sleep(15000)
    
    //STEP 4 now you an send some TON coin from your new wallet.
    
    let sendResult = await sendTon(newMnemonic,"1000000",DESTINATION_ADDRESS,"some message",true)
    console.log(sendResult.txId) // you can check tx id in tonscan.org

}

async function createTonWallet(): Promise<object> {
    const mnemonic = await generateMnemonic()
    const key = await mnemonicToKeyPair(mnemonic);
    const tonweb = new TonWeb();
    const WalletClass = tonweb.wallet.all["v4R2"];
    const wallet = new WalletClass(undefined!, {publicKey: key.publicKey});
    const walletAddress = await wallet.getAddress();
    const result = {
        address: walletAddress.toString(true, true, true),
        deployAddress: walletAddress.toString(true, true, false),
        mnemonic: mnemonic.join(" ")
    }
    return result
}

async function deployWallet(mnemonic: string): Promise<any> {
    const key = await mnemonicToKeyPair(mnemonic.split(" "));
    const tonweb = new TonWeb(new TonWeb.HttpProvider('https://toncenter.com/api/v2/jsonRPC', {apiKey: API_KEY}));
    const WalletClass = tonweb.wallet.all["v4R2"];
    const wallet = new WalletClass(tonweb.provider, {publicKey: key.publicKey});
    const walletAddress = await wallet.getAddress();
    const balance = await tonweb.getBalance(walletAddress);
    const deploy = wallet.deploy(key.secretKey);
    const deployFee = await deploy.estimateFee()
    const numFee = deployFee.source_fees.in_fwd_fee + deployFee.source_fees.storage_fee + deployFee.source_fees.gas_fee + deployFee.source_fees.fwd_fee;
    let errArray: string[];
    if (numFee > Number(balance)) {
        errArray = []
        errArray.push("balanceNotEnoughForDeployment")
        const errResult = {
            address: walletAddress.toString(true, true, true),
            deployAddress: walletAddress.toString(true, true, false),
            estimatedFee: numFee,
            balance: Number(balance),
            deployed: false,
            errors: errArray
        }
        return errResult
    }
    errArray = []

    try {
        const deploySent = await deploy.send() // deploy wallet contract to blockchain
        const result = {
            address: walletAddress.toString(true, true, true),
            deployAddress: walletAddress.toString(true, true, false),
            estimatedFee: numFee,
            deployed: deploySent["@type"] === "ok",
            balance: Number(balance),
            errors: errArray
        }
        return result
    } catch (e) {
        errArray.push("contractAlreadyDeployed")
        const result = {
            errors: errArray
        }
        return result
    }
}

async function sendTon(mnemonic: string, nano: string, to: string, message: string = '', waitForResult: boolean): Promise<any> {

    const key = await mnemonicToKeyPair(mnemonic.split(" ")); //creates keyPair from mnemonic
    const tonweb = new TonWeb(new TonWeb.HttpProvider('https://toncenter.com/api/v2/jsonRPC', {apiKey: API_KEY})); //creates Tonweb  with your api key
    const WalletClass = tonweb.wallet.all["v4R2"]; //loads WalletClass
    const wallet = new WalletClass(tonweb.provider, {publicKey: key.publicKey}); //creates wallet from key public key
    const seqno = await wallet.methods.seqno().call() || 0; //waits for current seqno
    let knownTxHash: any;// creates empty transaction
    let address = await wallet.getAddress() // gets your address
    let readableAddress = address.toString(true, true, true) // gets human readble address
    getLastTx(readableAddress, 1).then(value => {
        knownTxHash = value // sets the last transaction value to  previously creaed  transaction object
    }) // get current Last transaction

    await wallet.methods.transfer({
        secretKey: key.secretKey,
        toAddress: to,
        amount: nano,
        seqno: seqno,
        payload: message,
        sendMode: 3,
    }).send(); // transfers TON Coin  sendMode is 3 for normal mode, for emptying wallet use 128

    if (waitForResult) { // if we want to wait for result we  enter this block
        let currentSeqno = seqno;
        while (currentSeqno == seqno) {
            await sleep(500);
            currentSeqno = await wallet.methods.seqno().call() || 0;
        } // this block waits for seqno change


        let txHash = knownTxHash; // when seqno changes we query  for last transaction
        while (txHash.txId == knownTxHash.txId) {
            getLastTx(readableAddress, 1).then(value => {
                txHash = value
            })
            await sleep(500)
        } // when transactions changes we takes the transaction and return


        return txHash;
    } else {
        return {
            txId: "sent" // if we don't want to wait  for transaction we just send empty object  or anything you want.
        }
    }
}

async function getLastTx(address: string, limit: number): Promise<any> {
    const tonweb = new TonWeb(new TonWeb.HttpProvider('https://toncenter.com/api/v2/jsonRPC', {apiKey: API_KEY}));
    const lastTx = (await tonweb.getTransactions(address, limit))[0]
    const errorArray: string[] = []
    if (lastTx !== null && lastTx !== undefined) {
        if (lastTx.out_msgs !== null && lastTx.out_msgs !== undefined && lastTx.out_msgs.length > 0) {
            const result = {
                txId: lastTx.transaction_id.hash,
                from: lastTx.out_msgs[0].source,
                to: lastTx.out_msgs[0].destination,
                amount: lastTx.out_msgs[0].value,
                message: lastTx.out_msgs[0].message,
                incoming: address !== lastTx.out_msgs[0].source,
                fee: lastTx.fee,
                errors: errorArray

            }
            return result
        } else {
            const result = {
                txId: lastTx.transaction_id.hash,
                from: lastTx.in_msg.source,
                to: lastTx.in_msg.destination,
                amount: lastTx.in_msg.value,
                message: lastTx.in_msg.message,
                incoming: address === lastTx.in_msg.destination,
                fee: lastTx.fee,
                errors: errorArray

            }
            return result
        }

    } else {
        errorArray.push("noTransaction")
        const errorResult = {
            errors: errorArray
        }
        return errorResult
    }
}

function sleep(ms: number) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
Associated Context
Type Code Snippet ( .ts )
Associated Tags solidity blockchain smartcontracts Promise Transfer Method autodesk-viewer getLastTx Function Mnemonic HttpProvider SendMode WalletClass angular Nano ethereum Sleep Function TonWeb SDK Framework:TonWeb.
πŸ’‘ Smart Description This code sends a specified amount of cryptocurrency to a specified address, with an optional message. If the "wait" parameter is true, it waits for the transaction to be confirmed and returns the transaction hash.
πŸ”Ž Suggested Searches Javascript function to send TON with mnemonic and nano
How to send TON using TonWeb and HttpProvider
WalletClass for TON transfer with TonWeb
Javascript code to transfer TON with wait option
TonWeb HttpProvider transfer function with mnemonic and wait option
Related Links https://www.npmjs.com/package/ton-client-js
https://www.npmjs.com/package/@tonclient/lib-node
https://www.npmjs.com/package/tonweb
https://www.npmjs.com/package/@tonclient/lib-web
https://docs.ton.dev/
https://toncenter.com/api/v2/jsonRPC
https://github.com/tonlabs/ever-sdk-js
https://www.npmjs.com/package/@tonclient/core
https://www.npmjs.com/package/@tonclient/lib-react-native
Related People sench@outlook.com
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment