UNPKG

@holographxyz/cli

Version:
201 lines (200 loc) 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const inquirer = tslib_1.__importStar(require("inquirer")); const core_1 = require("@oclif/core"); const color_1 = tslib_1.__importDefault(require("@oclif/color")); const networks_1 = require("@holographxyz/networks"); const bignumber_1 = require("@ethersproject/bignumber"); const units_1 = require("@ethersproject/units"); const core_chain_service_1 = tslib_1.__importDefault(require("../../services/core-chain-service")); const operator_chain_service_1 = tslib_1.__importDefault(require("../../services/operator-chain-service")); const token_chain_service_1 = tslib_1.__importDefault(require("../../services/token-chain-service")); const config_1 = require("../../utils/config"); const network_monitor_1 = require("../../utils/network-monitor"); const utils_1 = require("../../utils/utils"); const validation_1 = require("../../utils/validation"); const _1 = tslib_1.__importDefault(require(".")); /** * Bond * Description: Bond and operator into a pod. */ class Bond extends core_1.Command { static description = 'Bond in to a pod.'; static examples = ['$ <%= config.bin %> <%= command.id %> --network <string> --pod <number> --amount <number>']; static flags = { ...network_monitor_1.networkFlag, pod: core_1.Flags.integer({ description: 'Pod number to join', }), amount: core_1.Flags.integer({ description: 'Amount of tokens to deposit', }), }; networkMonitor; async run() { const { flags } = await this.parse(Bond); let { pod, amount } = flags; let prompt; this.log(color_1.default.red('WARNING: To bond you must first have an operator running with the same wallet on the chain you are bonding to. Failure to do so will result in a loss of funds.')); prompt = await inquirer.prompt([ { name: 'continue', message: 'Do you have the operator with the wallet you are bonding from running on the network and are ready to proceed?', type: 'confirm', default: false, }, ]); if (!prompt.continue) { this.log('Operator is not ready to bond, please start an operator first.'); this.exit(); } this.log('Loading user configurations...'); const { userWallet, configFile, supportedNetworksOptions } = await (0, config_1.ensureConfigFileIsValid)(this.config.configDir, undefined, true); const network = await (0, validation_1.checkOptionFlag)(supportedNetworksOptions, flags.network, 'Select the network to bond to'); this.log(`Joining network: ${networks_1.networks[network].shortKey}`); this.networkMonitor = new network_monitor_1.NetworkMonitor({ parent: this, configFile, networks: [network], debug: this.debug, userWallet, verbose: false, }); core_1.CliUx.ux.action.start('Loading network RPC provider'); await this.networkMonitor.run(true); core_1.CliUx.ux.action.stop(); // Setup the contracts and chain services const coreChainService = new core_chain_service_1.default(network, this.networkMonitor); await coreChainService.initialize(); const tokenContract = await coreChainService.getUtilityToken(); const tokenChainService = new token_chain_service_1.default(network, this.networkMonitor, tokenContract); const operatorContract = await coreChainService.getOperator(); const operatorChainService = new operator_chain_service_1.default(network, this.networkMonitor, operatorContract); const operator = operatorChainService.operator; const currentHlgBalance = (await tokenChainService.balanceOf(coreChainService.wallet.address)); this.log(`Current HLG balance: ${(0, units_1.formatUnits)(currentHlgBalance, 'ether')}`); if ((await operator.getBondedAmount(coreChainService.wallet.address)) > 0) { prompt = await inquirer.prompt([ { name: 'continue', message: 'You are already bonded on this network. Would you like to unbond?', type: 'confirm', default: true, }, ]); if (!prompt.continue) { this.log('You are already bonded on this network. Please unbond first.'); this.exit(); } this.log(`Unbonding operator ${coreChainService.wallet.address} from network: ${networks_1.networks[network].shortKey}`); const unbondReceipt = await operatorChainService.unbondUtilityToken(); if (unbondReceipt === null) { this.log(color_1.default.red(`Could not confirm the success of unbonding transaction.`)); this.exit(); } prompt = await inquirer.prompt([ { name: 'continue', message: 'Would you like to rebond?', type: 'confirm', default: true, }, ]); if (!prompt.continue) { this.log('Thank you. Come again.'); this.exit(); } } if (!currentHlgBalance.gt(bignumber_1.BigNumber.from('0'))) { this.log('No HLG balance found, please deposit HLG into your wallet before bonding.'); this.exit(); } this.log('Checking pods available...'); const totalPods = await operator.getTotalPods(); this.log(`Total Pods: ${totalPods}`); // Get the bond amounts for each pod const allPodBondAmounts = []; for (let i = 1; i <= totalPods; i++) { allPodBondAmounts.push(await operator.getPodBondAmounts(i)); } const podChoices = allPodBondAmounts.map((podBondAmounts, index) => { return `${index + 1} - ${(0, units_1.formatUnits)(podBondAmounts.current, 'ether')} HLG`; }); if (!pod) { prompt = await inquirer.prompt([ { name: 'pod', message: 'Enter the pod number to join', type: 'list', choices: podChoices, }, ]); pod = Number.parseInt(prompt.pod.split(' - ')[0], 10); this.log(`Joining pod: ${pod}`); } const podBondAmounts = await operator.getPodBondAmounts(pod); this.log(`Pod ${pod} has a base bond amount of ${(0, units_1.formatUnits)(podBondAmounts.base, 'ether')} and currently requires ${(0, units_1.formatUnits)(podBondAmounts.current, 'ether')} to bond.`); this.log(`Enter an amount greater or equal to: ${(0, units_1.formatUnits)(podBondAmounts.current, 'ether')} to bond.`); if (!amount) { prompt = await inquirer.prompt([ { name: 'amount', message: `Enter the amount of tokens to deposit (Units in ether)`, type: 'number', validate: async (input) => { const inputBN = bignumber_1.BigNumber.from((0, utils_1.toLong18)(input)); if (typeof input === 'number' && input > 0 && inputBN.gte(podBondAmounts.current)) { return true; } return 'Input is not a valid bond amount'; }, }, ]); amount = prompt.amount; } this.log(`Bonding from ${coreChainService.wallet.address} to pod ${pod} on ${networks_1.networks[network].shortKey} network for ${amount} tokens`); core_1.CliUx.ux.action.start('Calculating gas amounts and prices'); const estimatedGas = await operatorChainService.estimateGasForBondUtilityToken(coreChainService.wallet.address, (0, utils_1.toLong18)(amount), pod); core_1.CliUx.ux.action.stop(); this.log(`Transaction is estimated to cost a total of ${(0, units_1.formatUnits)(estimatedGas, 'ether')} ${networks_1.networks[network].tokenSymbol}`); if (estimatedGas.gt(await coreChainService.getBalance())) { this.log(`You do not have enough ${networks_1.networks[network].tokenSymbol} to cover the transaction cost. Please deposit more ${networks_1.networks[network].tokenSymbol} into your wallet before bonding.`); this.exit(); } prompt = await inquirer.prompt([ { name: 'continue', message: 'Next steps submit the transaction, would you like to proceed?', type: 'confirm', default: true, }, ]); if (!prompt.continue) { this.log('Dropping command, no blockchain transactions executed'); this.exit(); } const receipt = await operatorChainService.bondUtilityToken(coreChainService.wallet.address, (0, utils_1.toLong18)(amount), pod); if (receipt === null) { this.log(color_1.default.red(`Could not confirm the success of transaction.`)); this.exit(); } this.log(color_1.default.green(`Welcome operator! Your wallet ${coreChainService.wallet.address} has bonded ${amount} eth to pod ${pod} on ${networks_1.networks[network].shortKey} 🎉` + `\nAgain please make sure your operator remains operational! ` + `Failure will result in slashed funds!`)); prompt = await inquirer.prompt([ { name: 'continue', message: "Last chance to start your operator if you don't have it running already. Would you like to proceed?", type: 'confirm', default: true, }, ]); if (!prompt.continue) { this.log('Successfully bonded. Exiting...'); this.exit(); } await _1.default.run(['--mode', 'auto']); } } exports.default = Bond;