@swapkit/helpers 1.0.0-rc.6 → 1.0.0-rc.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,84 +1,46 @@
1
- import type {
2
- CoinGeckoList,
3
- MayaList,
4
- PancakeswapETHList,
5
- PancakeswapList,
6
- PangolinList,
7
- StargateARBList,
8
- SushiswapList,
9
- ThorchainList,
10
- TraderjoeList,
11
- UniswapList,
12
- WoofiList,
13
- } from '@swapkit/tokens';
14
- import { BaseDecimal, Chain } from '@swapkit/types';
1
+ import { BaseDecimal, Chain, ChainToChainId } from '@swapkit/types';
15
2
 
16
3
  import type { CommonAssetString } from '../helpers/asset.ts';
17
4
  import { getAssetType, getCommonAssetInfo, getDecimal, isGasAsset } from '../helpers/asset.ts';
18
5
  import { validateIdentifier } from '../helpers/validators.ts';
6
+ import type { TokenNames, TokenTax } from '../types.ts';
19
7
 
20
- import { BigIntArithmetics } from './bigIntArithmetics.ts';
8
+ import type { NumberPrimitives } from './bigIntArithmetics.ts';
9
+ import { BigIntArithmetics, formatBigIntToSafeValue } from './bigIntArithmetics.ts';
21
10
  import type { SwapKitValueType } from './swapKitNumber.ts';
22
11
 
23
- type AssetValueParams = { decimal: number; value: SwapKitValueType } & (
24
- | { chain: Chain; symbol: string }
25
- | { identifier: string }
26
- );
27
-
28
- type TCTokenNames = (typeof ThorchainList)['tokens'][number]['identifier'];
29
-
30
- type TokenNames =
31
- | TCTokenNames
32
- | (typeof CoinGeckoList)['tokens'][number]['identifier']
33
- | (typeof MayaList)['tokens'][number]['identifier']
34
- | (typeof PancakeswapETHList)['tokens'][number]['identifier']
35
- | (typeof PancakeswapList)['tokens'][number]['identifier']
36
- | (typeof PangolinList)['tokens'][number]['identifier']
37
- | (typeof StargateARBList)['tokens'][number]['identifier']
38
- | (typeof SushiswapList)['tokens'][number]['identifier']
39
- | (typeof TraderjoeList)['tokens'][number]['identifier']
40
- | (typeof WoofiList)['tokens'][number]['identifier']
41
- | (typeof UniswapList)['tokens'][number]['identifier'];
42
-
43
- let staticTokensMap: Map<TokenNames, { decimal: number; identifier: string }> | undefined;
44
-
45
- const getStaticToken = (identifier: TokenNames) => {
46
- if (!staticTokensMap) {
47
- throw new Error('Static assets not loaded, call await AssetValue.loadStaticAssets() first');
48
- }
49
- const tokenInfo = staticTokensMap.get(identifier.toUpperCase() as TokenNames);
50
-
51
- return tokenInfo || { decimal: BaseDecimal.THOR, identifier: '' };
52
- };
53
-
54
- const createAssetValue = async (assetString: string, value: number | string = 0) => {
55
- validateIdentifier(assetString);
56
-
57
- const decimal = await getDecimal(getAssetInfo(assetString));
58
- return new AssetValue({ decimal, value, identifier: assetString });
59
- };
12
+ const staticTokensMap = new Map<
13
+ TokenNames,
14
+ { tax?: TokenTax; decimal: number; identifier: string }
15
+ >();
60
16
 
61
17
  export class AssetValue extends BigIntArithmetics {
62
18
  address?: string;
63
19
  chain: Chain;
64
- isSynthetic = false;
65
20
  isGasAsset = false;
21
+ isSynthetic = false;
66
22
  symbol: string;
23
+ tax?: TokenTax;
67
24
  ticker: string;
68
25
  type: ReturnType<typeof getAssetType>;
69
26
 
70
- constructor(params: AssetValueParams) {
71
- super(
72
- params.value instanceof BigIntArithmetics
73
- ? params.value
74
- : { decimal: params.decimal, value: params.value },
75
- );
27
+ constructor({
28
+ value,
29
+ decimal,
30
+ tax,
31
+ chain,
32
+ symbol,
33
+ identifier,
34
+ }: { decimal: number; value: SwapKitValueType; tax?: TokenTax } & (
35
+ | { chain: Chain; symbol: string; identifier?: never }
36
+ | { identifier: string; chain?: never; symbol?: never }
37
+ )) {
38
+ super(typeof value === 'object' ? value : { decimal, value });
76
39
 
77
- const identifier =
78
- 'identifier' in params ? params.identifier : `${params.chain}.${params.symbol}`;
79
- const assetInfo = getAssetInfo(identifier);
40
+ const assetInfo = getAssetInfo(identifier || `${chain}.${symbol}`);
80
41
 
81
42
  this.type = getAssetType(assetInfo);
43
+ this.tax = tax;
82
44
  this.chain = assetInfo.chain;
83
45
  this.ticker = assetInfo.ticker;
84
46
  this.symbol = assetInfo.symbol;
@@ -87,100 +49,111 @@ export class AssetValue extends BigIntArithmetics {
87
49
  this.isGasAsset = assetInfo.isGasAsset;
88
50
  }
89
51
 
90
- get assetValue() {
91
- return `${this.getValue('string')} ${this.ticker}`;
52
+ toString() {
53
+ return this.isSynthetic ? this.symbol : `${this.chain}.${this.symbol}`;
92
54
  }
93
55
 
94
- toString(short = false) {
95
- // THOR.RUNE | ETH/ETH
96
- const shortFormat = this.isSynthetic ? this.ticker : `${this.chain}.${this.ticker}`;
97
-
98
- return short
99
- ? shortFormat
100
- : // THOR.ETH/ETH | ETH.USDT-0x1234567890
101
- `${this.chain}.${this.symbol}`;
56
+ toUrl() {
57
+ return this.isSynthetic ? `${this.chain}.${this.symbol.replace('/', '.')}` : this.toString();
102
58
  }
103
59
 
104
60
  eq({ chain, symbol }: { chain: Chain; symbol: string }) {
105
61
  return this.chain === chain && this.symbol === symbol;
106
62
  }
107
63
 
108
- static async fromString(assetString: string, value: number | string = 0) {
109
- return createAssetValue(assetString, value);
64
+ chainId() {
65
+ return ChainToChainId[this.chain];
110
66
  }
111
67
 
112
- static fromStringSync(assetString: string, value: number | string = 0) {
113
- const { decimal, identifier: tokenIdentifier } = getStaticToken(
114
- assetString as unknown as TokenNames,
115
- );
68
+ // THOR.RUNE
69
+ // THOR.ETH.ETH
70
+ // ETH.THOR-0x1234567890
71
+ static fromUrl(urlAsset: string, value: NumberPrimitives = 0) {
72
+ const [chain, ticker, symbol] = urlAsset.split('.');
73
+ if (!chain || !ticker) throw new Error('Invalid asset url');
116
74
 
117
- return tokenIdentifier
118
- ? new AssetValue({ decimal, identifier: tokenIdentifier, value })
119
- : undefined;
120
- }
75
+ const assetString =
76
+ chain === Chain.THORChain && symbol ? `${chain}.${ticker}/${symbol}` : urlAsset;
121
77
 
122
- static async fromIdentifier(
123
- assetString: `${Chain}.${string}` | `${Chain}/${string}` | `${Chain}.${string}-${string}`,
124
- value: number | string = 0,
125
- ) {
126
78
  return createAssetValue(assetString, value);
127
79
  }
128
80
 
129
- static fromIdentifierSync(identifier: TokenNames, value: number | string = 0) {
130
- const { decimal, identifier: tokenIdentifier } = getStaticToken(identifier);
131
-
132
- return new AssetValue({ decimal, identifier: tokenIdentifier, value });
81
+ static fromString(assetString: string, value: NumberPrimitives = 0) {
82
+ return createAssetValue(assetString, value);
133
83
  }
134
-
135
- static fromChainOrSignature(assetString: CommonAssetString, value: number | string = 0) {
136
- const { decimal, identifier } = getCommonAssetInfo(assetString);
137
-
138
- return new AssetValue({ value, decimal, identifier });
84
+ static fromIdentifier(
85
+ assetString:
86
+ | `${Chain}.${string}`
87
+ | `${Chain}/${string}`
88
+ | `${Chain}.${string}-${string}`
89
+ | TokenNames,
90
+ value: NumberPrimitives = 0,
91
+ ) {
92
+ return createAssetValue(assetString, value);
139
93
  }
140
94
 
141
- static async fromTCQuote(identifier: TCTokenNames, value: number | string = 0) {
142
- const decimal = await getDecimal(getAssetInfo(identifier));
143
- const shiftedValue = this.shiftDecimals({ value, from: BaseDecimal.THOR, to: decimal });
144
-
145
- return new AssetValue({ value: shiftedValue, identifier, decimal });
95
+ static fromStringSync(assetString: string, value: NumberPrimitives = 0) {
96
+ const { chain, isSynthetic } = getAssetInfo(assetString);
97
+ const tokenInfo = staticTokensMap.get(assetString.toUpperCase() as TokenNames);
98
+
99
+ if (isSynthetic) return createSyntheticAssetValue(assetString, value);
100
+ // TODO: write logger that will only run in dev mode with some flag
101
+ // if (!tokenInfo) {
102
+ // console.error(
103
+ // `Asset ${assetString} is not loaded. Use AssetValue.loadStaticAssets() to load it`,
104
+ // );
105
+ // }
106
+
107
+ const { tax, decimal, identifier } = tokenInfo || {
108
+ decimal: BaseDecimal[chain],
109
+ identifier: assetString,
110
+ };
111
+ return new AssetValue({
112
+ tax,
113
+ value: safeValue(value, decimal),
114
+ identifier: isSynthetic ? assetString : identifier,
115
+ decimal: isSynthetic ? 8 : decimal,
116
+ });
146
117
  }
147
118
 
148
- static fromTCQuoteStatic(identifier: TCTokenNames, value: number | string = 0) {
149
- const tokenInfo = getStaticToken(identifier);
150
- const shiftedValue = this.shiftDecimals({
151
- value,
152
- from: BaseDecimal.THOR,
153
- to: tokenInfo.decimal,
154
- });
119
+ static fromIdentifierSync(assetString: TokenNames, value: NumberPrimitives = 0) {
120
+ const { chain, isSynthetic } = getAssetInfo(assetString);
121
+ const tokenInfo = staticTokensMap.get(assetString);
122
+
123
+ if (isSynthetic) return createSyntheticAssetValue(assetString, value);
124
+ // TODO: write logger that will only run in dev mode with some flag
125
+ // if (!tokenInfo) {
126
+ // console.error(
127
+ // `Asset ${assetString} is not loaded. - Loading with base Chain. Use AssetValue.loadStaticAssets() to load it`,
128
+ // );
129
+ // }
130
+
131
+ const { tax, decimal, identifier } = tokenInfo || {
132
+ decimal: BaseDecimal[chain],
133
+ identifier: assetString,
134
+ };
135
+ return new AssetValue({ tax, decimal, identifier, value: safeValue(value, decimal) });
136
+ }
155
137
 
156
- return new AssetValue({ ...tokenInfo, value: shiftedValue });
138
+ static fromChainOrSignature(assetString: CommonAssetString, value: NumberPrimitives = 0) {
139
+ const { decimal, identifier } = getCommonAssetInfo(assetString);
140
+ return new AssetValue({ value: safeValue(value, decimal), decimal, identifier });
157
141
  }
158
142
 
159
- static async loadStaticAssets() {
143
+ static loadStaticAssets() {
160
144
  return new Promise<{ ok: true } | { ok: false; message: string; error: any }>(
161
145
  async (resolve, reject) => {
162
146
  try {
163
- const {
164
- // Omit ThorchainList from import to avoid decimals conflict (TC uses 8 for all)
165
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
166
- ThorchainList: _ThorchainList,
167
- NativeList,
168
- ...tokensPackage
169
- } = await import('@swapkit/tokens');
170
- const tokensMap = [NativeList, ...Object.values(tokensPackage)].reduce(
171
- (acc, { tokens }) => {
172
- tokens.forEach(({ identifier, chain, ...rest }) => {
173
- const decimal = 'decimals' in rest ? rest.decimals : BaseDecimal[chain as Chain];
174
-
175
- acc.set(identifier as TokenNames, { identifier, decimal });
176
- });
147
+ const tokenPackages = await import('@swapkit/tokens');
177
148
 
178
- return acc;
179
- },
180
- new Map<TokenNames, { decimal: number; identifier: string }>(),
181
- );
182
-
183
- staticTokensMap = tokensMap;
149
+ Object.values(tokenPackages).forEach((tokenList) => {
150
+ tokenList?.tokens?.forEach(({ identifier, chain, ...rest }) => {
151
+ staticTokensMap.set(identifier.toUpperCase() as TokenNames, {
152
+ identifier,
153
+ decimal: 'decimals' in rest ? rest.decimals : BaseDecimal[chain as Chain],
154
+ });
155
+ });
156
+ });
184
157
 
185
158
  resolve({ ok: true });
186
159
  } catch (error) {
@@ -197,46 +170,90 @@ export class AssetValue extends BigIntArithmetics {
197
170
  }
198
171
  }
199
172
 
200
- export const getMinAmountByChain = (chain: Chain) => {
173
+ export function getMinAmountByChain(chain: Chain) {
201
174
  const asset = AssetValue.fromChainOrSignature(chain);
202
175
 
203
176
  switch (chain) {
204
177
  case Chain.Bitcoin:
205
178
  case Chain.Litecoin:
206
179
  case Chain.BitcoinCash:
207
- return asset.add(10001);
180
+ return asset.set(0.00010001);
208
181
 
209
182
  case Chain.Dogecoin:
210
- return asset.add(100000001);
183
+ return asset.set(1.00000001);
211
184
 
212
185
  case Chain.Avalanche:
213
186
  case Chain.Ethereum:
214
- return asset.add(10 * 10 ** 9);
187
+ return asset.set(0.00000001);
215
188
 
216
189
  case Chain.THORChain:
217
190
  case Chain.Maya:
218
- return asset.add(0);
191
+ return asset.set(0);
192
+
193
+ case Chain.Cosmos:
194
+ return asset.set(0.000001);
219
195
 
220
196
  default:
221
- return asset.add(1);
197
+ return asset.set(0.00000001);
198
+ }
199
+ }
200
+
201
+ async function createAssetValue(identifier: string, value: NumberPrimitives = 0) {
202
+ validateIdentifier(identifier);
203
+
204
+ const staticToken = staticTokensMap.get(identifier.toUpperCase() as TokenNames);
205
+ const decimal = staticToken?.decimal || (await getDecimal(getAssetInfo(identifier)));
206
+ if (!staticToken) {
207
+ staticTokensMap.set(identifier.toUpperCase() as TokenNames, { identifier, decimal });
222
208
  }
223
- };
224
209
 
225
- const getAssetInfo = (identifier: string) => {
210
+ return new AssetValue({ decimal, value: safeValue(value, decimal), identifier });
211
+ }
212
+
213
+ function createSyntheticAssetValue(identifier: string, value: NumberPrimitives = 0) {
214
+ const [synthChain, symbol] =
215
+ identifier.split('.')[0].toUpperCase() === Chain.THORChain
216
+ ? identifier.split('.').slice(1)!.join().split('/')
217
+ : identifier.split('/');
218
+
219
+ if (!synthChain || !symbol) throw new Error('Invalid asset identifier');
220
+
221
+ return new AssetValue({
222
+ decimal: 8,
223
+ value: safeValue(value, 8),
224
+ identifier: `${Chain.THORChain}.${synthChain}/${symbol}`,
225
+ });
226
+ }
227
+
228
+ function safeValue(value: NumberPrimitives, decimal: number) {
229
+ return typeof value === 'bigint'
230
+ ? formatBigIntToSafeValue({ value, bigIntDecimal: decimal, decimal })
231
+ : value;
232
+ }
233
+
234
+ function getAssetInfo(identifier: string) {
226
235
  const isSynthetic = identifier.slice(0, 14).includes('/');
227
- const adjustedIdentifier = identifier.includes('.')
228
- ? identifier
229
- : `${Chain.THORChain}.${identifier}`;
236
+ const [synthChain, synthSymbol] =
237
+ identifier.split('.')[0].toUpperCase() === Chain.THORChain
238
+ ? identifier.split('.').slice(1)!.join().split('/')
239
+ : identifier.split('/');
240
+
241
+ if (isSynthetic && (!synthChain || !synthSymbol)) throw new Error('Invalid asset identifier');
242
+
243
+ const adjustedIdentifier =
244
+ identifier.includes('.') && !isSynthetic ? identifier : `${Chain.THORChain}.${synthSymbol}`;
230
245
 
231
246
  const [chain, symbol] = adjustedIdentifier.split('.') as [Chain, string];
232
- const [ticker, address] = symbol.split('-') as [string, string?];
247
+ const [ticker, address] = (isSynthetic ? synthSymbol : symbol).split('-') as [string, string?];
233
248
 
234
249
  return {
235
250
  address: address?.toLowerCase(),
236
251
  chain,
237
252
  isGasAsset: isGasAsset({ chain, symbol }),
238
253
  isSynthetic,
239
- symbol: address ? `${ticker}-${address?.toLowerCase() ?? ''}` : symbol,
240
- ticker: isSynthetic ? symbol : ticker,
254
+ symbol:
255
+ (isSynthetic ? `${synthChain}/` : '') +
256
+ (address ? `${ticker}-${address?.toLowerCase() ?? ''}` : symbol),
257
+ ticker,
241
258
  };
242
- };
259
+ }