UNPKG

@cheqd/sdk

Version:

A TypeScript SDK built with CosmJS to interact with the cheqd network ledger

186 lines 7.73 kB
import { GasPriceResponse, GasPricesResponse, ParamsResponse, QueryClientImpl, protobufPackage, } from '@cheqd/ts-proto/feemarket/feemarket/v1/index.js'; import { createProtobufRpcClient, GasPrice } from '@cosmjs/stargate'; import { AbstractCheqdSDKModule } from './_.js'; import { DefaultBackoffOptions, retry } from '../utils.js'; import { Decimal, Uint32 } from '@cosmjs/math'; export const defaultFeemarketExtensionKey = 'feemarket'; export const protobufLiterals = { GasPriceResponse: 'GasPriceResponse', GasPricesResponse: 'GasPricesResponse', ParamsResponse: 'ParamsResponse', }; export const typeUrlGasPriceResponse = `/${protobufPackage}.${protobufLiterals.GasPriceResponse}`; export const typeUrlGasPricesResponse = `/${protobufPackage}.${protobufLiterals.GasPricesResponse}`; export const typeUrlParamsResponse = `/${protobufPackage}.${protobufLiterals.ParamsResponse}`; export const defaultGasPriceTiers = { Low: 'DefaultLowTier', Avg: 'DefaultAvgTier', High: 'DefaultHighTier', }; export function isGasPriceEncodeObject(obj) { return obj.typeUrl === typeUrlGasPriceResponse; } export function isGasPricesEncodeObject(obj) { return obj.typeUrl === typeUrlGasPricesResponse; } export function isParamsEncodeObject(obj) { return obj.typeUrl === typeUrlParamsResponse; } export const setupFeemarketExtension = (base) => { const rpc = createProtobufRpcClient(base); const queryService = new QueryClientImpl(rpc); return { [defaultFeemarketExtensionKey]: { gasPrice: async (denom) => { return queryService.GasPrice({ denom }); }, gasPrices: async () => { return queryService.GasPrices({}); }, params: async () => { return queryService.Params({}); }, }, }; }; export class FeemarketModule extends AbstractCheqdSDKModule { // @ts-expect-error underlying type `GeneratedType` is intentionally wider static registryTypes = [ [typeUrlGasPriceResponse, GasPriceResponse], [typeUrlGasPricesResponse, GasPricesResponse], [typeUrlParamsResponse, ParamsResponse], ]; static defaultGasPrices = { [defaultGasPriceTiers.Low]: { amount: '5000', denom: 'ncheq' }, [defaultGasPriceTiers.Avg]: { amount: '7500', denom: 'ncheq' }, [defaultGasPriceTiers.High]: { amount: '10000', denom: 'ncheq' }, }; static gasOffsetFactor = 10 ** 4; static feeCollectorAddress = 'cheqd13pxn9n3qw79e03844rdadagmg0nshmwfszqu0g'; static moduleAccountAddress = 'cheqd1el68mjnzv87uurqks8u29tec0cj3297047g2dl'; static querierExtensionSetup = setupFeemarketExtension; querier; constructor(signer, querier) { super(signer, querier); this.querier = querier; this.methods = { queryGasPrice: this.queryGasPrice.bind(this), queryGasPrices: this.queryGasPrices.bind(this), queryParams: this.queryParams.bind(this), generateGasPrice: this.generateGasPrice.bind(this), generateOfflineGasPrice: this.generateOfflineGasPrice.bind(this), generateSafeGasPrice: this.generateSafeGasPrice.bind(this), generateSafeGasPriceWithExponentialBackoff: this.generateSafeGasPriceWithExponentialBackoff.bind(this), }; } getRegistryTypes() { return FeemarketModule.registryTypes; } getQuerierExtensionSetup() { return FeemarketModule.querierExtensionSetup; } async queryGasPrice(denom, context) { if (!this.querier) this.querier = context.sdk.querier; return this.querier[defaultFeemarketExtensionKey].gasPrice(denom); } async queryGasPrices(context) { if (!this.querier) this.querier = context.sdk.querier; return this.querier[defaultFeemarketExtensionKey].gasPrices(); } async queryParams(context) { if (!this.querier) this.querier = context.sdk.querier; return this.querier[defaultFeemarketExtensionKey].params(); } /** * Generate gas price by denom by live polling. If live poll fails, the error is bubbled up. * @param denom * @returns GasPrice */ async generateGasPrice(denom, context) { if (!this.querier) this.querier = context.sdk.querier; // query gas price, bubble up error, no catch const gasPrice = await this.queryGasPrice(denom, context); // validate gas price if (!gasPrice.price) throw new Error('Invalid gas price: live poll for gas price failed'); // convert gas price through offset factor const adjustedGasPrice = Decimal.fromAtomics(gasPrice.price.amount, 18) .multiply(Uint32.fromString(FeemarketModule.gasOffsetFactor.toString())) .toString(); // safe convert gas price to string return GasPrice.fromString(`${adjustedGasPrice}${gasPrice.price.denom}`); } /** * Generate offline gas price by denom by static tier. * @param denom * @param tier * @returns GasPrice */ async generateOfflineGasPrice(denom, tier = defaultGasPriceTiers.Low) { // validate denom against default if (!Object.values(FeemarketModule.defaultGasPrices).some((gp) => gp.denom === denom)) throw new Error(`Invalid denom: ${denom}`); // validate tier against default if (!Object.keys(FeemarketModule.defaultGasPrices).includes(tier)) throw new Error(`Invalid tier: ${tier}`); // generate gas price const gasPrice = FeemarketModule.defaultGasPrices[tier]; // safe convert gas price to string return GasPrice.fromString(`${gasPrice.amount}${gasPrice.denom}`); } /** * Generate safe gas price by denom by live polling with fallback to offline gas price. If live poll fails, the error is caught and offline gas price is generated. * @param denom * @param tier * @returns GasPrice */ async generateSafeGasPrice(denom, tier = defaultGasPriceTiers.Low, context) { if (!this.querier) this.querier = context.sdk.querier; try { // generate gas price return await this.generateGasPrice(denom, context); } catch (error) { // generate offline gas price return await this.generateOfflineGasPrice(denom, tier); } } /** * Generate safe gas price by denom by live polling with exponential backoff to offline gas price. * @param denom * @param tier * @param backoffOptions * @returns GasPrice */ async generateSafeGasPriceWithExponentialBackoff(denom, tier = defaultGasPriceTiers.Low, backoffOptions = DefaultBackoffOptions, context) { if (!this.querier) this.querier = context.sdk.querier; // live poll for gas price const gasPrice = await retry(() => this.generateGasPrice(denom, context), backoffOptions); // return, if applicable if (gasPrice) return gasPrice; // otherwise, generate offline gas price return await this.generateOfflineGasPrice(denom, tier); } /** * Generate fees from gas price. Use with live polling for gas price. * @param gasPrice * @param payer * @param gas * @returns DidStdFee */ static generateFeesFromGasPrice(gasPrice, payer, gas = '200000') { return { amount: [{ denom: gasPrice.denom, amount: gasPrice.amount.multiply(Uint32.fromString(gas)).toString() }], gas, payer, }; } } //# sourceMappingURL=feemarket.js.map