Skip to content

Commit

Permalink
feat: add new utils
Browse files Browse the repository at this point in the history
  • Loading branch information
marslavish committed Mar 18, 2024
1 parent e485eb8 commit b922c9d
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 56 deletions.
82 changes: 69 additions & 13 deletions packages/utils/src/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ import { Asset, AssetDenomUnit, AssetList } from '@chain-registry/types';
export type Denom = AssetDenomUnit['denom'];
export type Exponent = AssetDenomUnit['exponent'];

export const customFind = <T>(
array: T[],
filterFn: (item: T) => boolean
): T | undefined => {
const filteredItems = array.filter(filterFn);
const filterCount = filteredItems.length;

if (filterCount > 1) {
throw new Error(`Ambiguity Error: ${filterCount} items found.`);
}

return filteredItems[0];
};

const getAssetByKeyValue = (
assets: AssetList[],
key: keyof Asset,
Expand All @@ -13,19 +27,7 @@ const getAssetByKeyValue = (
.filter(({ chain_name }) => !chainName || chain_name === chainName)
.flatMap(({ assets }) => assets);

const matchingAssets = filteredAssets.filter((asset) => asset[key] === value);

if (matchingAssets.length === 0) {
return undefined;
}

if (matchingAssets.length > 1) {
throw new Error(
`Ambiguity: ${matchingAssets.length} assets found for ${key}: ${value}`
);
}

return matchingAssets[0];
return customFind(filteredAssets, (asset) => asset[key] === value);
};

export const getAssetByDenom = (
Expand Down Expand Up @@ -126,3 +128,57 @@ export const getExponentBySymbol = (
const asset = getAssetBySymbol(assets, symbol, chainName);
return asset ? getExponentFromAsset(asset) : undefined;
};

export const getNativeTokenByChainName = (
assets: AssetList[],
chainName: string
): Asset | undefined => {
const assetList = customFind(
assets,
(assetList) =>
assetList.chain_name === chainName &&
!assetList.assets[0].base.startsWith('ibc/')
);

return assetList?.assets[0];
};

export const getTokenLogoByDenom = (
assets: AssetList[],
denom: Denom,
chainName?: string
): string | undefined => {
const asset = getAssetByDenom(assets, denom, chainName);
return Object.values(asset?.logo_URIs || {})[0];
};

export const getChainLogo = (
assets: AssetList[],
chainName: string
): string | undefined => {
const nativeToken = getNativeTokenByChainName(assets, chainName);
return Object.values(nativeToken?.logo_URIs || {})[0];
};

export const getTokenNameByDenom = (
assets: AssetList[],
denom: Denom,
chainName?: string
): string | undefined => {
const asset = getAssetByDenom(assets, denom, chainName);
return asset?.name;
};

export const getChainNameByDenom = (assets: AssetList[], denom: Denom) => {
const isIbcDenom = denom.startsWith('ibc/');

if (isIbcDenom) {
const asset = getAssetByDenom(assets, denom);
return asset?.traces?.find((t) => t.type === 'ibc')?.counterparty
?.chain_name;
}

return customFind(assets, (assetList) =>
assetList.assets.some((asset) => asset.base === denom)
)?.chain_name;
};
88 changes: 49 additions & 39 deletions packages/utils/src/calc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@ import { AssetList } from '@chain-registry/types';
import BigNumber from 'bignumber.js';
import {
Denom,
getDenomByCoinGeckoId,
getAssetBySymbol,
getExponentFromAsset,
getExponentBySymbol
getDenomByCoinGeckoId
} from './assets';

export interface CoinGeckoUSD {
export interface CoinGeckoUSDPrice {
usd: number;
}

export interface PriceHash {
export interface DenomPriceMap {
[key: Denom]: number;
}

export const convertCoinGeckoPricesToDenomPriceMap = (
export const mapCoinGeckoPricesToDenoms = (
assets: AssetList[],
prices: Record<string, CoinGeckoUSD>
): PriceHash => {
return Object.keys(prices).reduce((res: PriceHash, geckoId) => {
prices: Record<string, CoinGeckoUSDPrice>
): DenomPriceMap => {
return Object.keys(prices).reduce((res: DenomPriceMap, geckoId) => {
const denom = getDenomByCoinGeckoId(assets, geckoId);
if (!denom) {
throw new Error(`No denom found for CoinGecko ID: ${geckoId}`);
Expand All @@ -30,17 +29,15 @@ export const convertCoinGeckoPricesToDenomPriceMap = (
}, {});
};

export const noDecimals = (num: number | string): string => {
return new BigNumber(num).decimalPlaces(0, BigNumber.ROUND_DOWN).toString();
export const roundDown = (value: number | string): string => {
return new BigNumber(value).decimalPlaces(0, BigNumber.ROUND_DOWN).toString();
};

export const convertBaseUnitsToDollarValue = (
const getAssetInfo = (
assets: AssetList[],
prices: PriceHash,
symbol: string,
amount: string | number,
chainName?: string
): string => {
) => {
const asset = getAssetBySymbol(assets, symbol, chainName);
const denom = asset?.base;
const exponent = asset ? getExponentFromAsset(asset) : undefined;
Expand All @@ -49,44 +46,57 @@ export const convertBaseUnitsToDollarValue = (
throw new Error(`No denom or exponent found for symbol: ${symbol}`);
}

return new BigNumber(amount)
.shiftedBy(-exponent)
.multipliedBy(prices[denom])
.toString();
return { denom, exponent };
};

export const convertDollarValueToDenomUnits = (
const shiftDecimalPlaces = (
amount: string | number,
exponent: number,
direction: 1 | -1 = 1
) => {
return new BigNumber(amount).shiftedBy(exponent * direction).toString();
};

export const convertBaseUnitToDollarValue = (
assets: AssetList[],
prices: PriceHash,
prices: DenomPriceMap,
symbol: string,
value: string | number,
amount: string | number,
chainName?: string
): string => {
const asset = getAssetBySymbol(assets, symbol, chainName);
const denom = asset?.base;
const exponent = asset ? getExponentFromAsset(asset) : undefined;

if (!denom || !exponent) {
throw new Error(`No denom or exponent found for symbol: ${symbol}`);
}
const { denom, exponent } = getAssetInfo(assets, symbol, chainName);
const baseAmount = shiftDecimalPlaces(amount, exponent, -1);
return new BigNumber(baseAmount).multipliedBy(prices[denom]).toString();
};

return new BigNumber(value)
.dividedBy(prices[denom])
.shiftedBy(exponent)
.toString();
export const convertDollarValueToBaseUnit = (
assets: AssetList[],
prices: DenomPriceMap,
symbol: string,
value: string | number,
chainName?: string
): string => {
const { denom, exponent } = getAssetInfo(assets, symbol, chainName);
const baseAmount = new BigNumber(value).dividedBy(prices[denom]).toString();
return roundDown(shiftDecimalPlaces(baseAmount, exponent));
};

export const convertBaseUnitsToDisplayUnits = (
export const convertBaseUnitToDisplayUnit = (
assets: AssetList[],
symbol: string,
amount: string | number,
chainName?: string
): string => {
const exponent = getExponentBySymbol(assets, symbol, chainName);

if (!exponent) {
throw new Error(`No exponent found for symbol: ${symbol}`);
}
const { exponent } = getAssetInfo(assets, symbol, chainName);
return shiftDecimalPlaces(amount, exponent, -1);
};

return new BigNumber(amount).shiftedBy(-exponent).toString();
export const convertDisplayUnitToBaseUnit = (
assets: AssetList[],
symbol: string,
amount: string | number,
chainName?: string
): string => {
const { exponent } = getAssetInfo(assets, symbol, chainName);
return roundDown(shiftDecimalPlaces(amount, exponent));
};
39 changes: 35 additions & 4 deletions packages/utils/src/chains.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
import { Chain } from '@chain-registry/types';
import { customFind } from './assets';

export const getGasPriceStep = (chain: Chain) => {
export const getGasPriceRangesFromChain = (chain: Chain) => {
const feeToken = chain.fees?.fee_tokens?.[0];
return {
low: chain.fees?.fee_tokens?.[0]?.low_gas_price ?? 0.01,
average: chain.fees?.fee_tokens?.[0]?.average_gas_price ?? 0.025,
high: chain.fees?.fee_tokens?.[0]?.high_gas_price ?? 0.04
low: feeToken?.low_gas_price ?? 0.01,
average: feeToken?.average_gas_price ?? 0.025,
high: feeToken?.high_gas_price ?? 0.04
};
};

export const getChainByChainName = (chains: Chain[], chainName: string) => {
return customFind(chains, (chain) => chain.chain_name === chainName);
};

export const getChainByChainId = (chains: Chain[], chainId: string) => {
return customFind(chains, (chain) => chain.chain_id === chainId);
};

export const getChainNameByChainId = (chains: Chain[], chainId: string) => {
return getChainByChainId(chains, chainId)?.chain_name;
};

export const getChainIdByChainName = (chains: Chain[], chainName: string) => {
return getChainByChainName(chains, chainName)?.chain_id;
};

export const getChainGasPriceRanges = (chains: Chain[], chainName: string) => {
const chain = getChainByChainName(chains, chainName);
return chain ? getGasPriceRangesFromChain(chain) : undefined;
};

export const getChainPrettyName = (chains: Chain[], chainName: string) => {
return getChainByChainName(chains, chainName)?.pretty_name;
};

export const getChainBech32Prefix = (chains: Chain[], chainName: string) => {
return getChainByChainName(chains, chainName)?.bech32_prefix;
};

0 comments on commit b922c9d

Please sign in to comment.