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.

259 lines (215 loc) 8.12 kB
import { ethers, formatUnits } from "ethers"; import { TronWeb } from 'tronweb' import { EstimateFeeParams, EstimateFeeResponse, GetBalanceParams, GetBalanceResponse, TransferParams, TransferResponse } from "."; import { sleep } from "../utils/index"; const trc20Abi = [ { "constant": true, "inputs": [{ "name": "owner", "type": "address" }], "name": "balanceOf", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "to", "type": "address" }, { "name": "amount", "type": "uint256" } ], "name": "transfer", "outputs": [{ "name": "", "type": "bool" }], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "decimals", "outputs": [{ "name": "", "type": "uint8" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "totalSupply", "outputs": [{ "name": "", "type": "uint256" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "symbol", "outputs": [{ "name": "", "type": "string" }], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "name", "outputs": [{ "name": "", "type": "string" }], "payable": false, "stateMutability": "view", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "from", "type": "address" }, { "indexed": true, "name": "to", "type": "address" }, { "indexed": false, "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "owner", "type": "address" }, { "indexed": true, "name": "spender", "type": "address" }, { "indexed": false, "name": "value", "type": "uint256" } ], "name": "Approval", "type": "event" } ] export const getBalance = async (params: GetBalanceParams): Promise<GetBalanceResponse> => { const tronWeb = new TronWeb({ fullHost: params.jsonRpcProvider, }); tronWeb.setAddress(params.address) if (params.tokenAddress) { const tokenContract = tronWeb.contract(trc20Abi, params.tokenAddress); const decimals = await tokenContract.decimals().call() await sleep(params.delay) const tokenBalance = formatUnits(await tokenContract.balanceOf(params.address).call(), decimals); return { success: true, token_balance: tokenBalance, } } else { const coinBalance = formatUnits(await tronWeb.trx.getBalance(params.address), params.chainDecimals); return { success: true, coin_balance: coinBalance, } } } export const transfer = async (params: TransferParams): Promise<TransferResponse> => { const tronWeb = new TronWeb({ fullHost: params.jsonRpcProvider, }); tronWeb.setPrivateKey(Buffer.from(params.secretKey).toString('hex')) tronWeb.setAddress(params.fromAddress) if (params.tokenAddress) { const tokenContract = tronWeb.contract(trc20Abi, params.tokenAddress); const decimals = Number(await tokenContract.decimals().call()) await sleep(params.delay) const amount = Number(params.amount).toFixed(decimals) const amountInSun = ethers.parseUnits(amount, decimals); const transaction = await tokenContract.transfer(params.toAddress, amountInSun).send() const hash = transaction const fee = "0" return { success: true, hash, fee, } } else { const amount = Number(params.amount).toFixed(params.chainDecimals) const amountInSun = Number(ethers.parseUnits(amount, params.chainDecimals)); const transaction: any = await tronWeb.trx.sendTransaction(params.toAddress, amountInSun); const hash = transaction.txid const fee = "0" return { success: true, hash, fee, } } } export const estimateFee = async (params: EstimateFeeParams): Promise<EstimateFeeResponse> => { const tronWeb = new TronWeb({ fullHost: params.jsonRpcProvider, }); tronWeb.setAddress(params.fromAddress) if (params.tokenAddress) { const tokenContract = tronWeb.contract(trc20Abi, params.tokenAddress); const decimals = await tokenContract.decimals().call() await sleep(params.delay) const amountInSun = ethers.parseUnits("0", decimals); const result = await tronWeb.transactionBuilder.triggerConstantContract( params.tokenAddress, 'transfer(address,uint256)', {}, [ { type: 'address', value: params.toAddress }, { type: 'uint256', value: amountInSun } ], params.fromAddress, ); await sleep(params.delay) const energyLimit = (result.energy_used || result.energy_required || 0) + (result.energy_penalty || 0) const currentTimestamp = Date.now() const energyPrices = (await tronWeb.trx.getEnergyPrices()).split(",").map(part => part.split(':').map(v => Number(v))) energyPrices.reverse() await sleep(params.delay) const energyPrice = (energyPrices.find(part => currentTimestamp <= part[0]) || energyPrices[0])[1] if (!energyPrice) { return { success: false, code: 'empty-gas-price', message: "Error in fetching energy price", } } const energyCostInSum = energyLimit * energyPrice; const energyCost = formatUnits(energyCostInSum, params.chainDecimals); const bandwidthLimit = 400 const bandwidthPrices = (await tronWeb.trx.getBandwidthPrices()).split(",").map(part => part.split(':').map(v => Number(v))) bandwidthPrices.reverse() const bandwidthPrice = (bandwidthPrices.find(part => currentTimestamp <= part[0]) || bandwidthPrices[0])[1] if (!bandwidthPrice) { return { success: false, code: 'empty-gas-price', message: "Error in fetching bandwidth price", } } const bandwidthCostInSum = bandwidthLimit * bandwidthPrice; const bandwidthCost = formatUnits(bandwidthCostInSum, params.chainDecimals); const gasCost = Number(bandwidthCost) + Number(energyCost) return { success: true, fee: String(gasCost || 0), } } else { const bandwidthLimit = 400 const bandwidthPrices = (await tronWeb.trx.getBandwidthPrices()).split(",").map(part => part.split(':').map(v => Number(v))) bandwidthPrices.reverse() const currentTimestamp = Date.now() const bandwidthPrice = (bandwidthPrices.find(part => currentTimestamp <= part[0]) || bandwidthPrices[0])[1] if (!bandwidthPrice) { return { success: false, code: 'empty-gas-price', message: "Error in fetching bandwidth price" } } const bandwidthCostInSum = bandwidthLimit * bandwidthPrice; const bandwidthCost = formatUnits(bandwidthCostInSum, params.chainDecimals); const gasCost = bandwidthCost return { success: true, fee: gasCost, } } } export default { getBalance, transfer, estimateFee }