@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
text/typescript
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 }