UNPKG

@tedcryptoorg/cosmos-signer

Version:

Cosmos Signer - A library for signing transactions for Cosmos SDK chains

184 lines (183 loc) 9.09 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SigningClient = void 0; const axios_1 = __importDefault(require("axios")); const stargate_1 = require("@cosmjs/stargate"); const encoding_1 = require("@cosmjs/encoding"); const tx_1 = require("cosmjs-types/cosmos/tx/v1beta1/tx"); const lodash_1 = __importDefault(require("lodash")); const bignumber_js_1 = __importDefault(require("bignumber.js")); const DefaultAdapter_1 = require("./adapter/DefaultAdapter"); const TypeUtils_1 = require("../util/TypeUtils"); const Sleep_1 = require("../util/Sleep"); const Coin_1 = require("../util/Coin"); const TransactionHelper_1 = require("../util/TransactionHelper"); class SigningClient { constructor(network, wallet, defaultGasPrice, defaultGasModifier = 1.5, selectedAdapter) { this.network = network; this.wallet = wallet; this.defaultGasPrice = defaultGasPrice; this.defaultGasModifier = defaultGasModifier; this.selectedAdapter = selectedAdapter; this.adapter = selectedAdapter !== null && selectedAdapter !== void 0 ? selectedAdapter : new DefaultAdapter_1.DefaultAdapter(network, wallet); } getAccount(address) { return __awaiter(this, void 0, void 0, function* () { return yield axios_1.default .get(this.network.restUrl + '/cosmos/auth/v1beta1/accounts/' + address) .then((res) => res.data.account) .then((value) => { if (!value) throw new Error('Failed to fetch account, please try again'); const baseAccount = 'BaseAccount' in value ? value.BaseAccount : ('baseAccount' in value ? value.baseAccount : value.base_account); if (!(0, TypeUtils_1.isEmpty)(baseAccount)) { value = baseAccount; } const baseVestingAccount = 'BaseVestingAccount' in value ? value.BaseVestingAccount : ('baseVestingAccount' in value ? value.baseVestingAccount : value.base_vesting_account); if (!(0, TypeUtils_1.isEmpty)(baseVestingAccount)) { value = baseVestingAccount; const baseAccount = 'BaseAccount' in value ? value.BaseAccount : ('baseAccount' in value ? value.baseAccount : value.base_account); if (!(0, TypeUtils_1.isEmpty)(baseAccount)) { value = baseAccount; } } const nestedAccount = value.account; if (!(0, TypeUtils_1.isEmpty)(nestedAccount)) { value = nestedAccount; } return value; }) .catch((error) => { var _a; if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) { throw new Error('Account does not exist on chain'); } else { throw new Error('Unknown error when getting account'); } }); }); } calculateFee(gasLimit, gasPrice) { const processedGasPrice = typeof gasPrice === 'string' ? stargate_1.GasPrice.fromString(gasPrice) : gasPrice; const { denom, amount: gasPriceAmount } = processedGasPrice; const amount = new bignumber_js_1.default(gasPriceAmount.toString()) .multipliedBy(new bignumber_js_1.default(gasLimit.toString())) .integerValue(bignumber_js_1.default.ROUND_CEIL); return { amount: [(0, Coin_1.coin)(amount, denom)], gas: BigInt(gasLimit) }; } getFee(gas, gasPrice) { if (gas === undefined || gas === 0) { gas = 200000; } const fee = this.calculateFee(gas, gasPrice !== null && gasPrice !== void 0 ? gasPrice : this.defaultGasPrice); return tx_1.Fee.fromPartial({ amount: fee.amount, gasLimit: fee.gas }); } signAndBroadcastWithoutBalanceCheck(address, msgs, gas, memo, gasPrice) { return __awaiter(this, void 0, void 0, function* () { const defaultOptions = lodash_1.default.cloneDeep(this.wallet.getOptions()); this.wallet.setOptions({ sign: { disableBalanceCheck: true } }); try { return yield this.signAndBroadcast(address, msgs, gas, memo, gasPrice); } finally { this.wallet.setOptions(defaultOptions); } }); } signAndBroadcast(address, messages, gas, memo, gasPrice) { return __awaiter(this, void 0, void 0, function* () { if (!gas) { gas = yield this.simulate(address, messages, memo); } const fee = this.getFee(gas, gasPrice); const txBody = yield this.sign(address, messages, fee, memo); return yield this.broadcast(txBody); }); } sign(address, messages, fee, memo) { return __awaiter(this, void 0, void 0, function* () { const account = yield this.getAccount(address); return yield this.adapter.sign(account, messages, fee, memo); }); } simulate(address, messages, memo, modifier) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; const account = yield this.getAccount(address); const fee = this.getFee(100000); const txBody = yield this.adapter.simulate(account, messages, fee, memo); try { const estimate = yield axios_1.default.post(this.network.restUrl + '/cosmos/tx/v1beta1/simulate', { tx_bytes: (0, encoding_1.toBase64)(tx_1.TxRaw.encode(txBody).finish()), }).then(el => el.data.gas_info.gas_used); return (parseInt(estimate * (modifier !== null && modifier !== void 0 ? modifier : this.defaultGasModifier))); } catch (error) { throw new Error(((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) || error.message); } }); } broadcast(txBody) { return __awaiter(this, void 0, void 0, function* () { const timeoutMs = this.network.txTimeout !== 0 ? this.network.txTimeout : 60000; const pollIntervalMs = 3000; let timedOut = false; const txPollTimeout = setTimeout(() => { timedOut = true; }, timeoutMs); const pollForTx = (txId) => __awaiter(this, void 0, void 0, function* () { if (timedOut) { throw new Error(`Transaction with ID ${txId} was submitted but was not yet found on the chain. You might want to check later. There was a wait of ${timeoutMs / 1000} seconds.`); } yield (0, Sleep_1.sleep)(pollIntervalMs); try { const response = yield axios_1.default.get(this.network.restUrl + '/cosmos/tx/v1beta1/txs/' + txId); return (0, TransactionHelper_1.parseTxResult)(response.data.tx_response); } catch (_a) { return yield pollForTx(txId); } }); const response = yield axios_1.default.post(this.network.restUrl + '/cosmos/tx/v1beta1/txs', { tx_bytes: (0, encoding_1.toBase64)(tx_1.TxRaw.encode(txBody).finish()), mode: "BROADCAST_MODE_SYNC" }); const result = (0, TransactionHelper_1.parseTxResult)(response.data.tx_response); (0, stargate_1.assertIsDeliverTxSuccess)(result); return yield pollForTx(result.transactionHash).then((value) => { clearTimeout(txPollTimeout); (0, stargate_1.assertIsDeliverTxSuccess)(value); return value; }, (error) => { clearTimeout(txPollTimeout); return error; }); }); } } exports.SigningClient = SigningClient;