@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.
315 lines (274 loc) • 12.6 kB
text/typescript
import { Command } from "commander";
import type { WalletCore } from '@trustwallet/wallet-core'
import { getCoin } from "./address";
import Chains from "../chains/index";
export default (program: Command, trustCore: WalletCore) => {
const { HDWallet, CoinType, Curve, Derivation, AnyAddress } = trustCore
program.command('get-balance')
.description('check wallet balance of coin or token')
.option('--coin <coin>', 'set coin name based on trustwallet core')
.option('--coingecko-platform <platform>', 'set platform name based on coingecko api')
.option('--address <address>', 'receiver wallet address')
.option('--token-address <token-address>', 'contract address of the token. set empty for the coin.')
.option('--json-rpc-provider <json-rpc-provider>', 'url of the json rpc provider')
.option('--http-provider <http-provider>', 'url of the http provider')
.option('--json', 'output will be in json format')
.option('--testnet', 'the default provider will be in testnet')
.option('--delay <delay>', 'delay between each request in milliseconds to avoid rate limiting')
.action(async (values) => {
const [coin, error] = getCoin(trustCore, values.coin, values.coingeckoPlatform, true)
if (error || !coin) {
program.error(JSON.stringify({
...error,
json: values.json
}))
}
const chain = Chains.find(v => v.id == coin)
if (!chain) {
program.error(JSON.stringify({
success: false,
code: 'not-supported',
message: "This chain not supported",
json: values.json
}))
}
const address = values.address
const tokenAddress = values.tokenAddress
const delay = Number(values.delay) || 0
let jsonRpcProvider = values.jsonRpcProvider?.trim?.()
if (!jsonRpcProvider) {
jsonRpcProvider = values.testnet ? chain.json_rpc_test_provider : chain.json_rpc_provider
}
try {
if (!chain.api?.getBalance) {
program.error(JSON.stringify({
success: false,
code: 'not-supported',
message: "This chain not supported",
json: values.json
}))
}
const r = await chain.api.getBalance({
coin, address, jsonRpcProvider, tokenAddress, chainDecimals: chain.decimals, testnet: values.testnet, delay
})
if (!r.success) {
program.error(JSON.stringify({
...r,
json: values.json
}))
}
if (values.json) {
console.log(JSON.stringify(r))
} else {
if (r.coin_balance !== undefined) {
console.log("Coin Balance:", r.coin_balance);
}
if (r.token_balance !== undefined) {
console.log("Token Balance:", r.token_balance);
}
}
} catch (e: any) {
program.error(JSON.stringify({
success: false,
code: 'error-get-balance',
message: e?.shortMessage || e?.message || "Error in fetching balance",
json: values.json
}))
}
})
program.command('transfer')
.description('transfer coin or token to another wallet')
.option('--mnemonic <mnemonic>', 'set an existing mnemonic')
.option('--coin <coin>', 'set coin name based on trustwallet core')
.option('--coingecko-platform <platform>', 'set platform name based on coingecko api')
.option('--address <address>', 'receiver wallet address')
.option('--amount <amount>', 'the amount to transfer')
.option('--token-address <token-address>', 'contract address of the token. set empty for the coin.')
.option('--json-rpc-provider <json-rpc-provider>', 'url of the json rpc provider')
.option('--json', 'output will be in json format')
.option('--testnet', 'the default provider will be in testnet')
.option('--delay <delay>', 'delay between each request in milliseconds to avoid rate limiting')
.action(async (values) => {
const [coin, error] = getCoin(trustCore, values.coin, values.coingeckoPlatform, true)
if (error || !coin) {
program.error(JSON.stringify({
...error,
json: values.json
}))
}
const chain = Chains.find(v => v.id == coin)
if (!chain) {
program.error(JSON.stringify({
success: false,
code: 'not-supported',
message: "This chain not supported",
json: values.json
}))
}
const mnemonic = values.mnemonic || ''
let amount = values.amount
const tokenAddress = values.tokenAddress
const toAddress = values.address
const delay = Number(values.delay) || 0
let jsonRpcProvider = values.jsonRpcProvider?.trim?.()
if (!jsonRpcProvider) {
jsonRpcProvider = values.testnet ? chain.json_rpc_test_provider : chain.json_rpc_provider
}
if (!mnemonic) {
program.error(JSON.stringify({
success: false,
code: 'empty-mnemonic',
message: "Set the mnemonic",
json: values.json
}))
}
if (!amount) {
program.error(JSON.stringify({
success: false,
code: 'empty-amount',
message: "Set the amount you want to transfer",
json: values.json
}))
}
if (!toAddress) {
program.error(JSON.stringify({
success: false,
code: 'empty-address',
message: "Set the wallet address you want to transfer to it",
json: values.json
}))
}
const wallet = HDWallet.createWithMnemonic(mnemonic, "")
const secretKey = wallet.getKeyForCoin(CoinType[coin]).data()
const fromAddress = wallet.getAddressForCoin(CoinType[coin])
try {
if (!chain.api?.transfer) {
program.error(JSON.stringify({
success: false,
code: 'not-supported',
message: "This chain not supported",
json: values.json
}))
}
const r = await chain.api.transfer({
coin, mnemonic, secretKey, fromAddress, toAddress, amount, jsonRpcProvider, tokenAddress, chainDecimals: chain.decimals, testnet: values.testnet, delay
})
if (!r.success) {
program.error(JSON.stringify({
...r,
json: values.json
}))
}
if (values.json) {
console.log(JSON.stringify(r))
} else {
console.log("Hash:", r.hash);
console.log("Fee:", r.fee);
}
} catch (e: any) {
program.error(JSON.stringify({
success: false,
code: 'error-transfer',
message: e?.shortMessage || e?.message || "Error in transfering",
json: values.json
}))
}
})
program.command('estimate-fee')
.description('estimate fee for a coin or token transfer')
.option('--mnemonic <mnemonic>', 'set an existing mnemonic')
.option('--coin <coin>', 'set coin name based on trustwallet core')
.option('--coingecko-platform <platform>', 'set platform name based on coingecko api')
.option('--address <address>', 'receiver wallet address')
.option('--amount <amount>', 'the amount to transfer')
.option('--token-address <token-address>', 'contract address of the token. set empty for the coin.')
.option('--json-rpc-provider <json-rpc-provider>', 'url of the json rpc provider')
.option('--json', 'output will be in json format')
.option('--testnet', 'the default provider will be in testnet')
.option('--delay <delay>', 'delay between each request in milliseconds to avoid rate limiting')
.action(async (values) => {
const [coin, error] = getCoin(trustCore, values.coin, values.coingeckoPlatform, true)
if (error || !coin) {
program.error(JSON.stringify({
...error,
json: values.json
}))
}
const chain = Chains.find(v => v.id == coin)
if (!chain) {
program.error(JSON.stringify({
success: false,
code: 'not-supported',
message: "This chain not supported",
json: values.json
}))
}
const mnemonic = values.mnemonic || ''
const amount = values.amount
const tokenAddress = values.tokenAddress
const toAddress = values.address
const delay = Number(values.delay) || 0
let jsonRpcProvider = values.jsonRpcProvider?.trim?.()
if (!jsonRpcProvider) {
jsonRpcProvider = values.testnet ? chain.json_rpc_test_provider : chain.json_rpc_provider
}
if (!mnemonic) {
program.error(JSON.stringify({
success: false,
code: 'empty-mnemonic',
message: "Set the mnemonic",
json: values.json
}))
}
if (!amount) {
program.error(JSON.stringify({
success: false,
code: 'empty-amount',
message: "Set the amount you want to transfer",
json: values.json
}))
}
if (!toAddress) {
program.error(JSON.stringify({
success: false,
code: 'empty-address',
message: "Set the wallet address you want to transfer to it",
json: values.json
}))
}
const wallet = HDWallet.createWithMnemonic(mnemonic, "")
const secretKey = wallet.getKeyForCoin(CoinType[coin]).data()
const fromAddress = wallet.getAddressForCoin(CoinType[coin])
try {
if (!chain.api?.estimateFee) {
program.error(JSON.stringify({
success: false,
code: 'not-supported',
message: "This chain not supported",
json: values.json
}))
}
const r = await chain.api.estimateFee({
coin, mnemonic, secretKey, fromAddress, toAddress, amount, jsonRpcProvider, tokenAddress, chainDecimals: chain.decimals, testnet: values.testnet, delay
})
if (!r.success) {
program.error(JSON.stringify({
...r,
json: values.json
}))
}
if (values.json) {
console.log(JSON.stringify(r))
} else {
console.log("Fee:", r.fee);
}
} catch (e: any) {
program.error(JSON.stringify({
success: false,
code: 'error-gas-limit',
message: e?.shortMessage || e?.message || "Error in estimating gas limit",
json: values.json
}))
}
})
}