@thorwallet/xchain-util
Version:
Helper utilities for XChain clients
384 lines • 15.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatBaseAsAssetAmount = exports.formatAssetAmountCurrency = exports.currencySymbolByAsset = exports.AssetCurrencySymbol = exports.assetToString = exports.assetFromString = exports.isValidAsset = exports.AssetRuneERC20Testnet = exports.AssetRuneERC20 = exports.AssetRuneNative = exports.AssetRuneB1A = exports.AssetRune67C = exports.RUNE_TICKER = exports.AssetETH = exports.AssetLTC = exports.AssetBCH = exports.AssetBTC = exports.AssetBNB = exports.formatBaseAmount = exports.formatAssetAmount = exports.isBaseAmount = exports.isAssetAmount = exports.assetToBase = exports.baseToAsset = exports.baseAmount = exports.assetAmount = exports.isBigNumberValue = void 0;
const tslib_1 = require("tslib");
const bignumber_js_1 = tslib_1.__importDefault(require("bignumber.js"));
const bn_1 = require("./bn");
const string_1 = require("./string");
const chain_const_1 = require("./chain.const");
const chain_1 = require("./chain");
const types_1 = require("./types");
/**
* Guard whichs checks whether value is a BigNumber.Value or not
*
* @param {unknown} v
* @returns {boolean} `true` or `false`.
* */
const isBigNumberValue = (v) => typeof v === 'string' || typeof v === 'number' || v instanceof bignumber_js_1.default;
exports.isBigNumberValue = isBigNumberValue;
/**
* Default number of asset decimals
* For history reason and by starting the project on Binance chain assets, it's 8 decimal.
*
* For example:
* ```
* RUNE has a maximum of 8 digits of decimal
* 0.00000001 RUNE == 1 ð (tor)
* ```
* */
const ASSET_DECIMAL = 8;
/**
* Factory to create values of assets (e.g. RUNE)
*
* @param {string|number|BigNumber|undefined} value - The asset amount, If the value is undefined, AssetAmount with value `0` will be returned.
* @param {number} decimal The decimal places. (optional)
* @returns {AssetAmount} The asset amount from the given value and decimal.
*
**/
const assetAmount = (value, decimal = ASSET_DECIMAL) => {
const amount = bn_1.fixedBN(value, decimal);
return {
type: types_1.Denomination.ASSET,
amount: () => amount,
plus: (v, d = decimal) => exports.assetAmount(amount.plus(exports.isBigNumberValue(v) ? v : v.amount()), d),
minus: (v, d = decimal) => exports.assetAmount(amount.minus(exports.isBigNumberValue(v) ? v : v.amount()), d),
times: (v, d = decimal) => exports.assetAmount(amount.times(exports.isBigNumberValue(v) ? v : v.amount()), d),
div: (v, d = decimal) => exports.assetAmount(amount.div(exports.isBigNumberValue(v) ? v : v.amount()), d),
lt: (v) => amount.lt(exports.isBigNumberValue(v) ? v : v.amount()),
lte: (v) => amount.lte(exports.isBigNumberValue(v) ? v : v.amount()),
gt: (v) => amount.gt(exports.isBigNumberValue(v) ? v : v.amount()),
gte: (v) => amount.gte(exports.isBigNumberValue(v) ? v : v.amount()),
eq: (v) => amount.eq(exports.isBigNumberValue(v) ? v : v.amount()),
decimal,
};
};
exports.assetAmount = assetAmount;
/**
* Factory to create base amounts (e.g. tor)
*
* @param {string|number|BigNumber|undefined} value - The base amount, If the value is undefined, BaseAmount with value `0` will be returned.
* @param {number} decimal The decimal places of its associated AssetAmount. (optional)
* @returns {BaseAmount} The base amount from the given value and decimal.
**/
const baseAmount = (value, decimal = ASSET_DECIMAL) => {
const amount = bn_1.fixedBN(value, 0);
return {
type: types_1.Denomination.BASE,
amount: () => amount,
plus: (v, d = decimal) => exports.baseAmount(amount.plus(exports.isBigNumberValue(v) ? v : v.amount()), d),
minus: (v, d = decimal) => exports.baseAmount(amount.minus(exports.isBigNumberValue(v) ? v : v.amount()), d),
times: (v, d = decimal) => exports.baseAmount(amount.times(exports.isBigNumberValue(v) ? v : v.amount()), d),
div: (v, d = decimal) => exports.baseAmount(amount.div(exports.isBigNumberValue(v) ? v : v.amount()).decimalPlaces(0, bignumber_js_1.default.ROUND_DOWN), d),
lt: (v) => amount.lt(exports.isBigNumberValue(v) ? v : v.amount()),
lte: (v) => amount.lte(exports.isBigNumberValue(v) ? v : v.amount()),
gt: (v) => amount.gt(exports.isBigNumberValue(v) ? v : v.amount()),
gte: (v) => amount.gte(exports.isBigNumberValue(v) ? v : v.amount()),
eq: (v) => amount.eq(exports.isBigNumberValue(v) ? v : v.amount()),
decimal,
};
};
exports.baseAmount = baseAmount;
/**
* Helper to convert values for a asset from base values (e.g. RUNE from tor)
*
* @param {BaseAmount} base
* @returns {AssetAmount} The asset amount from the given base amount.
* */
const baseToAsset = (base) => {
const decimal = base.decimal;
const value = base
.amount()
.div(Math.pow(10, decimal))
.decimalPlaces(decimal);
return exports.assetAmount(value, decimal);
};
exports.baseToAsset = baseToAsset;
/**
* Helper to convert asset to base values (e.g. tor -> RUNE)
*
* @param {AssetAmount} asset
* @returns {BaseAmount} The base amount from the given AssetAmount.
* */
const assetToBase = (asset) => {
const value = asset
.amount()
.multipliedBy(Math.pow(10, asset.decimal))
.integerValue();
return exports.baseAmount(value, asset.decimal);
};
exports.assetToBase = assetToBase;
/**
* Guard to check whether value is an amount of asset or not
*
* @param {BaseAmount|AssetAmount} v
* @returns {boolean} `true` or `false`.
* */
const isAssetAmount = (v) => v.type === types_1.Denomination.ASSET;
exports.isAssetAmount = isAssetAmount;
/**
* Guard to check whether value is an amount of a base value or not
*
* @param {BaseAmount|AssetAmount} v
* @returns {boolean} `true` or `false`.
* */
const isBaseAmount = (v) => v.type === types_1.Denomination.BASE;
exports.isBaseAmount = isBaseAmount;
/**
* Formats an `AssetAmount` into `string` based on decimal places
*
* If `decimal` is not set, `amount.decimal` is used
* Note: `trimZeros` wins over `decimal`
*
* @param {Params} param The asset amount format options.
* @returns {string} The formatted asset amount string from the given options.
*/
const formatAssetAmount = ({ amount, decimal, trimZeros = false, }) => {
// strict check for `undefined` value as negate of 0 will return true and passed decimal value will be ignored
const formatted = bn_1.formatBN(amount.amount(), decimal === undefined ? amount.decimal : decimal);
// Note: `trimZeros` wins over `decimal`
return trimZeros ? string_1.trimZeros(formatted) : formatted;
};
exports.formatAssetAmount = formatAssetAmount;
/**
* Formats a `BaseAmount` value into a `string`
*
* @param {BaseAmount} amount
* @returns {string} The formatted base amount string from the given base amount.
*/
const formatBaseAmount = (amount) => bn_1.formatBN(amount.amount(), 0);
exports.formatBaseAmount = formatBaseAmount;
/**
* Base "chain" asset of Binance chain.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetBNB = { chain: chain_const_1.BNBChain, symbol: 'BNB', ticker: 'BNB' };
/**
* Base "chain" asset on bitcoin main net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetBTC = { chain: chain_const_1.BTCChain, symbol: 'BTC', ticker: 'BTC' };
/**
* Base "chain" asset on bitcoin cash main net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetBCH = { chain: chain_const_1.BCHChain, symbol: 'BCH', ticker: 'BCH' };
/**
* Base "chain" asset on litecoin main net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetLTC = { chain: chain_const_1.LTCChain, symbol: 'LTC', ticker: 'LTC' };
/**
* Base "chain" asset on ethereum main net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetETH = { chain: chain_const_1.ETHChain, symbol: 'ETH', ticker: 'ETH' };
exports.RUNE_TICKER = 'RUNE';
/**
* Base "chain" asset for RUNE-67C on Binance test net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetRune67C = { chain: chain_const_1.BNBChain, symbol: 'RUNE-67C', ticker: exports.RUNE_TICKER };
/**
* Base "chain" asset for RUNE-B1A on Binance main net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetRuneB1A = { chain: chain_const_1.BNBChain, symbol: 'RUNE-B1A', ticker: exports.RUNE_TICKER };
/**
* Base "chain" asset on thorchain main net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetRuneNative = { chain: chain_const_1.THORChain, symbol: exports.RUNE_TICKER, ticker: exports.RUNE_TICKER };
/**
* Base "chain" asset for RUNE on ethereum main net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetRuneERC20 = {
chain: chain_const_1.ETHChain,
symbol: `${exports.RUNE_TICKER}-0x3155ba85d5f96b2d030a4966af206230e46849cb`,
ticker: exports.RUNE_TICKER,
};
/**
* Base "chain" asset for RUNE on ethereum main net.
*
* Based on definition in Thorchain `common`
* @see https://gitlab.com/thorchain/thornode/-/blob/master/common/asset.go#L12-24
*/
exports.AssetRuneERC20Testnet = {
chain: chain_const_1.ETHChain,
symbol: `${exports.RUNE_TICKER}-0xd601c6A3a36721320573885A8d8420746dA3d7A0`,
ticker: exports.RUNE_TICKER,
};
/**
* Helper to check whether asset is valid
*
* @param {Asset} asset
* @returns {boolean} `true` or `false`
*/
const isValidAsset = (asset) => !!asset.chain && !!asset.ticker && !!asset.symbol;
exports.isValidAsset = isValidAsset;
/**
* Creates an `Asset` by a given string
*
* This helper function expects a string with following naming convention:
* `AAA.BBB-CCC`
* where
* chain: `AAA`
* ticker (optional): `BBB`
* symbol: `BBB-CCC` or `CCC` (if no ticker available)
*
* @see https://docs.thorchain.org/developers/transaction-memos#asset-notation
*
* If the naming convention fails, it returns null
*
* @param {string} s The given string.
* @returns {Asset|null} The asset from the given string.
*/
const assetFromString = (s) => {
var _a;
const data = s.split('.');
if (data.length <= 1 || ((_a = data[1]) === null || _a === void 0 ? void 0 : _a.length) < 1) {
return null;
}
const chain = data[0];
// filter out not supported string of chains
if (!chain || !chain_1.isChain(chain))
return null;
const symbol = data[1];
const ticker = symbol.split('-')[0];
return { chain, symbol, ticker };
};
exports.assetFromString = assetFromString;
/**
* Returns an `Asset` as a string using following naming convention:
*
* `AAA.BBB-CCC`
* where
* chain: `AAA`
* ticker (optional): `BBB`
* symbol: `BBB-CCC` or `CCC` (if no ticker available)
*
* @see https://docs.thorchain.org/developers/transaction-memos#asset-notation
*
* @param {Asset} asset The given asset.
* @returns {string} The string from the given asset.
*/
const assetToString = ({ chain, symbol }) => `${chain}.${symbol
.split('-')
.map((x, i) => {
if (i === 0) {
return x;
}
return x.toLowerCase();
})
.join('-')}`;
exports.assetToString = assetToString;
/**
* Currency symbols currently supported
*/
var AssetCurrencySymbol;
(function (AssetCurrencySymbol) {
AssetCurrencySymbol["RUNE"] = "\u16B1";
AssetCurrencySymbol["BTC"] = "\u20BF";
AssetCurrencySymbol["SATOSHI"] = "\u26A1";
AssetCurrencySymbol["ETH"] = "\u039E";
AssetCurrencySymbol["USD"] = "$";
})(AssetCurrencySymbol = exports.AssetCurrencySymbol || (exports.AssetCurrencySymbol = {}));
/**
* Returns currency symbols by given `Asset`
*
* @param {Asset} asset The given asset.
* @returns {string} The currency symbol from the given asset.
*/
const currencySymbolByAsset = ({ ticker }) => {
switch (true) {
case ticker === exports.RUNE_TICKER:
return AssetCurrencySymbol.RUNE;
case ticker === exports.AssetBTC.ticker:
return AssetCurrencySymbol.BTC;
case ticker === exports.AssetETH.ticker:
return AssetCurrencySymbol.ETH;
case ticker.includes('USD'):
return AssetCurrencySymbol.USD;
default:
return ticker;
}
};
exports.currencySymbolByAsset = currencySymbolByAsset;
/**
* Formats an asset amount using its currency symbol
*
* If `decimal` is not set, `amount.decimal` is used
* If `asset` is not set, `$` will be used as currency symbol by default
* `trimZeros` is `false` by default
* Note: `trimZeros` wins over `decimal`
*
* @param {Params} params The asset amount currency format options.
* @return {string} The formatted asset amount string using its currency format.
*/
const formatAssetAmountCurrency = ({ amount, asset, decimal, trimZeros: shouldTrimZeros = false, }) => {
var _a;
const amountFormatted = exports.formatAssetAmount({
amount,
// strict check for `undefined` value as negate of 0 will return true and passed decimal value will be ignored
decimal: decimal === undefined ? amount.decimal : decimal,
trimZeros: shouldTrimZeros,
});
const ticker = (_a = asset === null || asset === void 0 ? void 0 : asset.ticker) !== null && _a !== void 0 ? _a : '';
if (ticker) {
// RUNE
let regex = new RegExp(`${exports.AssetRune67C.ticker}|${exports.AssetRuneB1A.ticker}|${exports.AssetRuneNative.ticker}`, 'i');
if (ticker.match(regex))
return `${AssetCurrencySymbol.RUNE} ${amountFormatted}`;
// BTC
regex = new RegExp(exports.AssetBTC.ticker, 'i');
if (ticker.match(new RegExp(exports.AssetBTC.ticker, 'i'))) {
const base = exports.assetToBase(amount);
// format all < ₿ 0.01 in statoshi
if (base.amount().isLessThanOrEqualTo('1000000')) {
return `${AssetCurrencySymbol.SATOSHI} ${exports.formatBaseAmount(base)}`;
}
return `${AssetCurrencySymbol.BTC} ${amountFormatted}`;
}
// ETH
regex = new RegExp(exports.AssetETH.ticker, 'i');
if (ticker.match(regex))
return `${AssetCurrencySymbol.ETH} ${amountFormatted}`;
// USD
regex = new RegExp('USD', 'i');
if (ticker.match('USD'))
return `${AssetCurrencySymbol.USD} ${amountFormatted}`;
return `${amountFormatted} ${ticker}`;
}
return `$ ${amountFormatted}`;
};
exports.formatAssetAmountCurrency = formatAssetAmountCurrency;
/**
* Formats a `BaseAmount` into a string of an `AssetAmount`
*
* If `decimal` is not set, `amount.decimal` is used
* Note: `trimZeros` wins over `decimal`
*
* @param {Params} params The base amount currency format options.
* @return {string} The formatted base amount string using its currency format.
*/
const formatBaseAsAssetAmount = ({ amount, decimal, trimZeros = false, }) => exports.formatAssetAmount({ amount: exports.baseToAsset(amount), decimal, trimZeros });
exports.formatBaseAsAssetAmount = formatBaseAsAssetAmount;
//# sourceMappingURL=asset.js.map