@tedcryptoorg/cosmos-signer
Version:
Cosmos Signer - A library for signing transactions for Cosmos SDK chains
184 lines (183 loc) • 9.09 kB
JavaScript
"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;