UNPKG

@codegame.dev/wallet-cli

Version:

A CLI tool for managing wallets across multiple blockchains, supporting operations like wallet creation, balance checking, transfers, and fee estimation.

356 lines (300 loc) 12.9 kB
import { EstimateFeeParams, EstimateFeeResponse, GetBalanceParams, GetBalanceResponse, TransferParams, TransferResponse } from "."; import { sleep } from "../utils/index"; import TonWeb from "tonweb"; export const getBalance = async (params: GetBalanceParams): Promise<GetBalanceResponse> => { const provider = new TonWeb.HttpProvider(params.jsonRpcProvider) const tonWeb = new TonWeb(provider) const address = new TonWeb.Address(params.address) if (params.tokenAddress) { const tokenAddress = new TonWeb.Address(params.tokenAddress) // @ts-ignore const tokenMinter = new TonWeb.token.jetton.JettonMinter(provider, { address: tokenAddress.toString(true, true, false, params.testnet), }) const jettonWalletAddress = await tokenMinter.getJettonWalletAddress(address) await sleep(params.delay) const jettonWallet = new TonWeb.token.jetton.JettonWallet(tonWeb.provider, { address: jettonWalletAddress, }); const jettonData = await jettonWallet.getData(); if (jettonData.jettonMinterAddress.toString(false) !== tokenMinter.address?.toString(false)) { return { success: false, code: 'jetton-minter-address-mismatch', message: 'Jetton minter address from jetton wallet does not match the expected minter address', } } const tokenBalance = TonWeb.utils.fromNano(jettonData.balance) return { success: true, token_balance: tokenBalance, } } else { const coinBalance = TonWeb.utils.fromNano(await tonWeb.getBalance(address)) return { success: true, coin_balance: coinBalance, } } } export const transfer = async (params: TransferParams): Promise<TransferResponse> => { const fromAddress = new TonWeb.Address(params.fromAddress) const toAddress = new TonWeb.Address(params.toAddress) const nacl = TonWeb.utils.nacl; const keyPair = nacl.sign.keyPair.fromSeed(params.secretKey); if (params.tokenAddress) { const tokenAddress = new TonWeb.Address(params.tokenAddress) const provider = new TonWeb.HttpProvider(params.jsonRpcProvider) const tonWeb = new TonWeb(provider) const wallet = new tonWeb.wallet.all.v4R2(provider, { publicKey: keyPair.publicKey }) // @ts-ignore const jettonMinter = new TonWeb.token.jetton.JettonMinter(provider, { address: tokenAddress.toString(true, true, false, params.testnet) }) const jettonWalletAddress = await jettonMinter.getJettonWalletAddress(fromAddress) await sleep(params.delay) const jettonWallet = new TonWeb.token.jetton.JettonWallet(tonWeb.provider, { address: jettonWalletAddress, }); const jettonData = await jettonWallet.getData(); await sleep(params.delay) if (jettonData.jettonMinterAddress.toString(false) !== jettonMinter.address?.toString(false)) { return { success: false, code: 'jetton-minter-address-mismatch', message: 'Jetton minter address from jetton wallet does not match the expected minter address', } } const seqno = await wallet.methods.seqno().call() || 0 await sleep(params.delay) const tx = wallet.methods.transfer({ secretKey: keyPair.secretKey, toAddress: jettonWalletAddress.toString(true, true, false, params.testnet), amount: TonWeb.utils.toNano("0.05"), seqno, payload: await jettonWallet.createTransferBody({ // @ts-ignore jettonAmount: TonWeb.utils.toNano(Number(params.amount).toString()), toAddress: toAddress, responseAddress: fromAddress, }), sendMode: 3, }) const query = await tx.getQuery() const boc = await query.toBoc(false) const bocBase64 = tonWeb.utils.bytesToBase64(boc) const payloadHash = tonWeb.utils.bytesToBase64(await query.hash()) const r = await tonWeb.provider.sendBoc(bocBase64) await sleep(params.delay) if (r['@type'] == 'ok') { try { let lastTx let i = 100 do { const newSeqno = await wallet.methods.seqno().call() || 0 await sleep(params.delay) if (newSeqno <= seqno) { i-- if (i < 0) break continue } const index = newSeqno - seqno - 1 const _lastTx = (await tonWeb.getTransactions(fromAddress.toString(true, true, false, params.testnet), 1, undefined, payloadHash))[index] if (!_lastTx) break if (_lastTx.transaction_id?.hash && !_lastTx.out_msgs?.length) { return { success: false, hash: _lastTx.transaction_id.hash, fee: _lastTx.fee, } } lastTx = { utime: _lastTx.utime, lt: _lastTx.transaction_id.lt, source: _lastTx.out_msgs[0].source, destination: _lastTx.out_msgs[0].destination, value: _lastTx.out_msgs[0].value, fee: _lastTx.fee, hash: _lastTx.transaction_id.hash } break } while (true) return { success: true, hash: lastTx?.hash, fee: TonWeb.utils.fromNano(lastTx?.fee || '0') } } catch (e) { return { success: true, hash: "", fee: "0" } } } else { return { success: false, hash: "", fee: "0" } } } else { const provider = new TonWeb.HttpProvider(params.jsonRpcProvider) const tonWeb = new TonWeb(provider) const wallet = new tonWeb.wallet.all.v4R2(provider, { publicKey: keyPair.publicKey }) const seqno = await wallet.methods.seqno().call() || 0 await sleep(params.delay) const tx = wallet.methods.transfer({ secretKey: keyPair.secretKey, toAddress: toAddress.toString(true, true, false, params.testnet), amount: TonWeb.utils.toNano(Number(params.amount).toString()), seqno, sendMode: 3, }) const query = await tx.getQuery() const boc = await query.toBoc(false) const bocBase64 = tonWeb.utils.bytesToBase64(boc) const payloadHash = tonWeb.utils.bytesToBase64(await query.hash()) const r = await tonWeb.provider.sendBoc(bocBase64) await sleep(params.delay) if (r['@type'] == 'ok') { try { let lastTx let i = 100 do { const newSeqno = await wallet.methods.seqno().call() || 0 await sleep(params.delay) if (newSeqno <= seqno) { i-- if (i < 0) break continue } const index = newSeqno - seqno - 1 const _lastTx = (await tonWeb.getTransactions(fromAddress.toString(true, true, false, params.testnet), 1, undefined, payloadHash))[index] if (!_lastTx) break if (_lastTx.transaction_id?.hash && !_lastTx.out_msgs?.length) { return { success: false, hash: _lastTx.transaction_id.hash, fee: _lastTx.fee, } } lastTx = { utime: _lastTx.utime, lt: _lastTx.transaction_id.lt, source: _lastTx.out_msgs[0].source, destination: _lastTx.out_msgs[0].destination, value: _lastTx.out_msgs[0].value, fee: _lastTx.fee, hash: _lastTx.transaction_id.hash } break } while (true) return { success: true, hash: lastTx?.hash, fee: TonWeb.utils.fromNano(lastTx?.fee || '0') } } catch (e) { return { success: true, hash: "", fee: "0" } } } else { return { success: false, hash: "", fee: "0" } } } } export const estimateFee = async (params: EstimateFeeParams): Promise<EstimateFeeResponse> => { const nacl = TonWeb.utils.nacl; const keyPair = nacl.sign.keyPair.fromSeed(params.secretKey); const fromAddress = new TonWeb.Address(params.fromAddress) const toAddress = new TonWeb.Address(params.toAddress) if (params.tokenAddress) { return { success: true, fee: "0.05" } } else { return { success: true, fee: "0.01" } } // if (params.tokenAddress) { // const tokenAddress = new TonWeb.Address(params.tokenAddress) // const provider = new TonWeb.HttpProvider(params.jsonRpcProvider) // const tonWeb = new TonWeb(provider) // const wallet = new tonWeb.wallet.all.v4R2(provider, { publicKey: keyPair.publicKey }) // // @ts-ignore // const jettonMinter = new TonWeb.token.jetton.JettonMinter(provider, { // address: tokenAddress.toString(true, true, false, params.testnet), // }) // const jettonWalletAddress = await jettonMinter.getJettonWalletAddress(fromAddress) // await sleep(params.delay) // const jettonWallet = new TonWeb.token.jetton.JettonWallet(tonWeb.provider, { // address: jettonWalletAddress, // }); // const seqno = await wallet.methods.seqno().call() || 0 // await sleep(params.delay) // const r = await wallet.methods.transfer({ // secretKey: keyPair.secretKey, // toAddress: jettonWalletAddress.toString(true, true, false, params.testnet), // amount: TonWeb.utils.toNano("0.05"), // seqno, // payload: await jettonWallet.createTransferBody({ // // @ts-ignore // jettonAmount: TonWeb.utils.toNano(Number(params.amount).toString()), // toAddress: toAddress, // responseAddress: fromAddress // }), // sendMode: 3, // }).estimateFee() // console.log(r) // const gasCost = TonWeb.utils.fromNano( // ([ // r?.source_fees?.in_fwd_fee || 0, // r?.source_fees?.storage_fee || 0, // r?.source_fees?.gas_fee || 0, // r?.source_fees?.fwd_fee || 0 // ].reduce((a, b) => a + b, 0)).toString() // ) // return { // success: true, // fee: gasCost // } // } else { // const provider = new TonWeb.HttpProvider(params.jsonRpcProvider) // const tonWeb = new TonWeb(provider) // const wallet = new tonWeb.wallet.all.v4R2(provider, { publicKey: keyPair.publicKey }) // const seqno = await wallet.methods.seqno().call() || 0 // await sleep(params.delay) // const r = await wallet.methods.transfer({ // secretKey: keyPair.secretKey, // toAddress: toAddress.toString(true, true, false, params.testnet), // amount: TonWeb.utils.toNano(Number(params.amount).toString()), // seqno, // sendMode: 3, // }).estimateFee() // console.log(r) // const gasCost = TonWeb.utils.fromNano( // ([ // r?.source_fees?.in_fwd_fee || 0, // r?.source_fees?.storage_fee || 0, // r?.source_fees?.gas_fee || 0, // r?.source_fees?.fwd_fee || 0 // ].reduce((a, b) => a + b, 0)).toString() // ) // return { // success: true, // fee: gasCost // } // } } export default { getBalance, transfer, estimateFee }