@swapkit/helpers 1.0.0-rc.7 → 1.0.0-rc.70

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,112 @@ 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
+
112
+ return new AssetValue({
113
+ tax,
114
+ value: safeValue(value, decimal),
115
+ identifier: isSynthetic ? assetString : identifier,
116
+ decimal: isSynthetic ? 8 : decimal,
117
+ });
146
118
  }
147
119
 
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
- });
120
+ static fromIdentifierSync(assetString: TokenNames, value: NumberPrimitives = 0) {
121
+ const { chain, isSynthetic } = getAssetInfo(assetString);
122
+ const tokenInfo = staticTokensMap.get(assetString);
123
+
124
+ if (isSynthetic) return createSyntheticAssetValue(assetString, value);
125
+ // TODO: write logger that will only run in dev mode with some flag
126
+ // if (!tokenInfo) {
127
+ // console.error(
128
+ // `Asset ${assetString} is not loaded. - Loading with base Chain. Use AssetValue.loadStaticAssets() to load it`,
129
+ // );
130
+ // }
131
+
132
+ const { tax, decimal, identifier } = tokenInfo || {
133
+ decimal: BaseDecimal[chain],
134
+ identifier: assetString,
135
+ };
136
+ return new AssetValue({ tax, decimal, identifier, value: safeValue(value, decimal) });
137
+ }
155
138
 
156
- return new AssetValue({ ...tokenInfo, value: shiftedValue });
139
+ static fromChainOrSignature(assetString: CommonAssetString, value: NumberPrimitives = 0) {
140
+ const { decimal, identifier } = getCommonAssetInfo(assetString);
141
+ return new AssetValue({ value: safeValue(value, decimal), decimal, identifier });
157
142
  }
158
143
 
159
- static async loadStaticAssets() {
144
+ static loadStaticAssets() {
160
145
  return new Promise<{ ok: true } | { ok: false; message: string; error: any }>(
161
146
  async (resolve, reject) => {
162
147
  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
- });
148
+ const tokenPackages = await import('@swapkit/tokens');
177
149
 
178
- return acc;
179
- },
180
- new Map<TokenNames, { decimal: number; identifier: string }>(),
181
- );
182
-
183
- staticTokensMap = tokensMap;
150
+ Object.values(tokenPackages).forEach((tokenList) => {
151
+ tokenList?.tokens?.forEach(({ identifier, chain, ...rest }) => {
152
+ staticTokensMap.set(identifier.toUpperCase() as TokenNames, {
153
+ identifier,
154
+ decimal: 'decimals' in rest ? rest.decimals : BaseDecimal[chain as Chain],
155
+ });
156
+ });
157
+ });
184
158
 
185
159
  resolve({ ok: true });
186
160
  } catch (error) {
@@ -197,46 +171,96 @@ export class AssetValue extends BigIntArithmetics {
197
171
  }
198
172
  }
199
173
 
200
- export const getMinAmountByChain = (chain: Chain) => {
174
+ export function getMinAmountByChain(chain: Chain) {
201
175
  const asset = AssetValue.fromChainOrSignature(chain);
202
176
 
203
177
  switch (chain) {
204
178
  case Chain.Bitcoin:
205
179
  case Chain.Litecoin:
206
180
  case Chain.BitcoinCash:
207
- return asset.add(10001);
181
+ return asset.set(0.00010001);
208
182
 
209
183
  case Chain.Dogecoin:
210
- return asset.add(100000001);
184
+ return asset.set(1.00000001);
211
185
 
212
186
  case Chain.Avalanche:
213
187
  case Chain.Ethereum:
214
- return asset.add(10 * 10 ** 9);
188
+ return asset.set(0.00000001);
215
189
 
216
190
  case Chain.THORChain:
217
191
  case Chain.Maya:
218
- return asset.add(0);
192
+ return asset.set(0);
193
+
194
+ case Chain.Cosmos:
195
+ return asset.set(0.000001);
219
196
 
220
197
  default:
221
- return asset.add(1);
198
+ return asset.set(0.00000001);
199
+ }
200
+ }
201
+
202
+ async function createAssetValue(identifier: string, value: NumberPrimitives = 0) {
203
+ validateIdentifier(identifier);
204
+
205
+ const staticToken = staticTokensMap.get(identifier.toUpperCase() as TokenNames);
206
+ const decimal = staticToken?.decimal || (await getDecimal(getAssetInfo(identifier)));
207
+ if (!staticToken) {
208
+ staticTokensMap.set(identifier.toUpperCase() as TokenNames, { identifier, decimal });
222
209
  }
223
- };
224
210
 
225
- const getAssetInfo = (identifier: string) => {
211
+ return new AssetValue({ decimal, value: safeValue(value, decimal), identifier });
212
+ }
213
+
214
+ function createSyntheticAssetValue(identifier: string, value: NumberPrimitives = 0) {
215
+ const [synthChain, symbol] =
216
+ identifier.split('.')[0].toUpperCase() === Chain.THORChain
217
+ ? identifier.split('.').slice(1)!.join().split('/')
218
+ : identifier.split('/');
219
+
220
+ if (!synthChain || !symbol) throw new Error('Invalid asset identifier');
221
+
222
+ return new AssetValue({
223
+ decimal: 8,
224
+ value: safeValue(value, 8),
225
+ identifier: `${Chain.THORChain}.${synthChain}/${symbol}`,
226
+ });
227
+ }
228
+
229
+ function safeValue(value: NumberPrimitives, decimal: number) {
230
+ return typeof value === 'bigint'
231
+ ? formatBigIntToSafeValue({ value, bigIntDecimal: decimal, decimal })
232
+ : value;
233
+ }
234
+
235
+ // TODO refactor & split into smaller functions
236
+ function getAssetInfo(identifier: string) {
226
237
  const isSynthetic = identifier.slice(0, 14).includes('/');
227
- const adjustedIdentifier = identifier.includes('.')
228
- ? identifier
229
- : `${Chain.THORChain}.${identifier}`;
230
238
 
231
- const [chain, symbol] = adjustedIdentifier.split('.') as [Chain, string];
232
- const [ticker, address] = symbol.split('-') as [string, string?];
239
+ const [synthChain, synthSymbol] =
240
+ identifier.split('.')[0].toUpperCase() === Chain.THORChain
241
+ ? identifier.split('.').slice(1)!.join().split('/')
242
+ : identifier.split('/');
243
+
244
+ if (isSynthetic && (!synthChain || !synthSymbol)) throw new Error('Invalid asset identifier');
245
+
246
+ const adjustedIdentifier =
247
+ identifier.includes('.') && !isSynthetic ? identifier : `${Chain.THORChain}.${synthSymbol}`;
248
+
249
+ const [chain, ...rest] = adjustedIdentifier.split('.') as [Chain, string];
250
+ const [ticker, address] = (isSynthetic ? synthSymbol : rest.join('.')).split('-') as [
251
+ string,
252
+ string?,
253
+ ];
254
+ const symbol = isSynthetic ? synthSymbol : rest.join('.');
233
255
 
234
256
  return {
235
257
  address: address?.toLowerCase(),
236
258
  chain,
237
259
  isGasAsset: isGasAsset({ chain, symbol }),
238
260
  isSynthetic,
239
- symbol: address ? `${ticker}-${address?.toLowerCase() ?? ''}` : symbol,
240
- ticker: isSynthetic ? symbol : ticker,
261
+ symbol:
262
+ (isSynthetic ? `${synthChain}/` : '') +
263
+ (address ? `${ticker}-${address?.toLowerCase() ?? ''}` : symbol),
264
+ ticker,
241
265
  };
242
- };
266
+ }