@onekeyfe/blockchain-libs
Version:
OneKey Blockchain Libs
205 lines • 8.72 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GAS_STEP_MULTIPLIER = exports.Tendermint = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const service_1 = require("cosmjs-types/cosmos/tx/v1beta1/service");
const exceptions_1 = require("../../../basic/exceptions");
const precondtion_1 = require("../../../basic/precondtion");
const exceptions_2 = require("../../../basic/request/exceptions");
const restful_1 = require("../../../basic/request/restful");
const provider_1 = require("../../../types/provider");
const abc_1 = require("../../abc");
const MINUTES_30 = 30 * 60 * 1000;
const GAS_STEP_MULTIPLIER = 10000;
exports.GAS_STEP_MULTIPLIER = GAS_STEP_MULTIPLIER;
const DEFAULT_GAS_PRICE_STEP = {
low: 100,
normal: 250,
high: 400,
};
class Tendermint extends abc_1.SimpleClient {
constructor(url) {
super();
this.restful = new restful_1.RestfulRequest(url);
}
get mainCoinDenom() {
var _a, _b;
return (0, precondtion_1.checkIsDefined)((_b = (_a = this.chainInfo) === null || _a === void 0 ? void 0 : _a.implOptions) === null || _b === void 0 ? void 0 : _b.mainCoinDenom, "Please config 'mainCoinDenom' in 'implOptions'");
}
async getInfo() {
const resp = await this.restful
.get('/blocks/latest')
.then((i) => i.json());
const bestBlockNumber = Number(resp['block']['header']['height']);
const bestBlockTime = new Date(resp['block']['header']['time']).getTime();
const isReady = isFinite(bestBlockNumber) &&
bestBlockNumber > 0 &&
Date.now() - bestBlockTime <= MINUTES_30;
return { bestBlockNumber, isReady };
}
async getAddress(address) {
var _a, _b, _c;
let existing;
let nonce = 0;
let accountNumber;
let balance = new bignumber_js_1.default(0);
try {
const accountInfo = await this.restful
.get(`/cosmos/auth/v1beta1/accounts/${address}`)
.then((i) => i.json());
existing = true;
nonce = Number(((_a = accountInfo.account) === null || _a === void 0 ? void 0 : _a.sequence) || 0);
accountNumber = Number((_b = accountInfo.account) === null || _b === void 0 ? void 0 : _b['account_number']);
}
catch (e) {
if (e instanceof exceptions_2.ResponseError && ((_c = e.response) === null || _c === void 0 ? void 0 : _c.status) === 404) {
existing = false;
accountNumber = undefined;
}
else {
throw e;
}
}
if (existing) {
try {
[balance] = await this.getNativeTokenBalances(address, [
{
tokenAddress: this.mainCoinDenom,
},
]);
}
catch (e) {
console.debug(`Error in get balance. address: ${address}, error: `, e);
}
}
return {
balance,
existing,
nonce,
accountNumber,
};
}
async getBalances(requests) {
const [nativeTokenRequests, cw20Requests] = requests.reduce((acc, cur, index) => {
var _a;
Object.assign(cur, { order: index });
if ((_a = cur.coin.options) === null || _a === void 0 ? void 0 : _a.isCW20) {
acc[1].push(cur);
}
else {
acc[0].push(cur);
}
return acc;
}, [[], []]);
const cw20Balances = await Promise.all(cw20Requests.map((req) => this.getCW20Balance(req.address, req.coin).then((value) => value, (reason) => {
console.debug('Error getting CW20 balances', reason);
return undefined;
}))).then((results) => results.map((v, index) => ({
order: cw20Requests[index].order,
value: v,
})));
const compressedNativeTokenRequests = Object.entries(nativeTokenRequests.reduce((acc, cur) => {
if (!acc[cur.address]) {
acc[cur.address] = [];
}
acc[cur.address].push(cur);
return acc;
}, {}));
const nativeTokenBalances = await Promise.all(compressedNativeTokenRequests.map(([address, reqs]) => this.getNativeTokenBalances(address, reqs.map((r) => r.coin)).then((value) => value, (reason) => {
console.debug('Error getting native token balances', reason);
return [];
}))).then((results) => results.reduce((acc, cur, index) => {
const [_address, reqs] = compressedNativeTokenRequests[index];
cur = cur || Array(reqs.length).fill(undefined);
acc.push(...cur.map((v, subIndex) => ({
value: v,
order: reqs[subIndex].order,
})));
return acc;
}, []));
return [...cw20Balances, ...nativeTokenBalances]
.sort((a, b) => a.order - b.order)
.map((i) => i.value);
}
async getNativeTokenBalances(address, coins) {
const rawResult = await this.restful
.get(`/bank/balances/${address}`)
.then((i) => i.json())
.then((i) => i.result || []);
const balanceInfo = rawResult.reduce((acc, cur) => {
acc[cur.denom] = new bignumber_js_1.default(cur.amount);
return acc;
}, {});
return coins.map(({ tokenAddress }) => tokenAddress && tokenAddress in balanceInfo
? balanceInfo[tokenAddress]
: new bignumber_js_1.default(0));
}
async getCW20Balance(address, coin) {
var _a;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const result = await this.queryContract(coin.tokenAddress, {
balance: { address },
});
return new bignumber_js_1.default((_a = result === null || result === void 0 ? void 0 : result.balance) !== null && _a !== void 0 ? _a : 0);
}
async queryContract(contractAddress, query, others = {}) {
return this.restful
.get(`/terra/wasm/v1beta1/contracts/${contractAddress}/store`, {
...others,
query_msg: Buffer.from(JSON.stringify(query), 'utf-8').toString('base64'),
})
.then((i) => i.json())
.then((i) => i.query_result);
}
getBalance(address, coin) {
return Promise.reject(exceptions_1.NotImplementedError);
}
getFeePricePerUnit() {
var _a, _b;
const gasPriceStep = ((_b = (_a = this.chainInfo) === null || _a === void 0 ? void 0 : _a.implOptions) === null || _b === void 0 ? void 0 : _b.gasPriceStep) || DEFAULT_GAS_PRICE_STEP;
return Promise.resolve({
normal: { price: new bignumber_js_1.default(gasPriceStep['normal']) },
others: Object.entries(gasPriceStep)
.filter(([key]) => key !== 'normal')
.map(([, price]) => ({ price: new bignumber_js_1.default(price) })),
});
}
async getTransactionStatus(txid) {
var _a, _b, _c;
let tx;
try {
tx = await this.restful
.get(`/cosmos/tx/v1beta1/txs/${txid}`)
.then((i) => i.json());
}
catch (e) {
if (e instanceof exceptions_2.ResponseError && ((_a = e.response) === null || _a === void 0 ? void 0 : _a.status) === 400) {
return provider_1.TransactionStatus.NOT_FOUND;
}
throw e;
}
const confirmedHeight = Number((_b = tx['tx_response']) === null || _b === void 0 ? void 0 : _b.height);
const isSuccess = ((_c = tx['tx_response']) === null || _c === void 0 ? void 0 : _c.code) === 0;
if (Number.isFinite(confirmedHeight) && confirmedHeight > 0) {
return isSuccess
? provider_1.TransactionStatus.CONFIRM_AND_SUCCESS
: provider_1.TransactionStatus.CONFIRM_BUT_FAILED;
}
return provider_1.TransactionStatus.PENDING;
}
async broadcastTransaction(rawTx) {
const data = {
mode: service_1.BroadcastMode.BROADCAST_MODE_SYNC,
tx_bytes: rawTx,
};
const resp = await this.restful
.post('/cosmos/tx/v1beta1/txs', data, true)
.then((i) => i.json());
return resp.tx_response.txhash;
}
}
exports.Tendermint = Tendermint;
//# sourceMappingURL=tendermint.js.map