@swapkit/helpers 1.0.0-rc.1 → 1.0.0-rc.100

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.
Files changed (40) hide show
  1. package/dist/index.js +2452 -0
  2. package/dist/index.js.map +30 -0
  3. package/package.json +26 -36
  4. package/src/helpers/__tests__/asset.test.ts +149 -105
  5. package/src/helpers/__tests__/memo.test.ts +52 -40
  6. package/src/helpers/__tests__/others.test.ts +42 -37
  7. package/src/helpers/__tests__/validators.test.ts +24 -0
  8. package/src/helpers/asset.ts +139 -91
  9. package/src/helpers/derivationPath.ts +53 -0
  10. package/src/helpers/liquidity.ts +50 -43
  11. package/src/helpers/memo.ts +31 -28
  12. package/src/helpers/others.ts +35 -57
  13. package/src/helpers/validators.ts +15 -6
  14. package/src/helpers/web3wallets.ts +177 -0
  15. package/src/index.ts +14 -8
  16. package/src/modules/__tests__/assetValue.test.ts +420 -117
  17. package/src/modules/__tests__/bigIntArithmetics.test.ts +30 -0
  18. package/src/modules/__tests__/swapKitNumber.test.ts +351 -149
  19. package/src/modules/assetValue.ts +243 -171
  20. package/src/modules/bigIntArithmetics.ts +313 -153
  21. package/src/modules/requestClient.ts +39 -0
  22. package/src/modules/swapKitError.ts +33 -5
  23. package/src/modules/swapKitNumber.ts +6 -3
  24. package/src/types/abis/erc20.ts +99 -0
  25. package/src/types/abis/mayaEvmVaults.ts +331 -0
  26. package/src/types/abis/tcEthVault.ts +496 -0
  27. package/src/types/chains.ts +220 -0
  28. package/src/types/commonTypes.ts +119 -0
  29. package/src/types/derivationPath.ts +56 -0
  30. package/src/types/errors/apiV1.ts +0 -0
  31. package/src/types/index.ts +10 -0
  32. package/src/types/network.ts +43 -0
  33. package/src/types/sdk.ts +44 -0
  34. package/src/types/tokens.ts +30 -0
  35. package/src/types/wallet.ts +47 -0
  36. package/LICENSE +0 -201
  37. package/dist/index.cjs +0 -1
  38. package/dist/index.d.ts +0 -333
  39. package/dist/index.es.js +0 -661
  40. package/src/helpers/number.ts +0 -40
@@ -1,142 +1,197 @@
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';
15
-
16
- import type { CommonAssetString } from '../helpers/asset.ts';
17
- import { getAssetType, getCommonAssetInfo, getDecimal, isGasAsset } from '../helpers/asset.ts';
18
- import { validateIdentifier } from '../helpers/validators.ts';
19
-
20
- import { BigIntArithmetics } from './bigIntArithmetics.ts';
21
- import type { SwapKitValueType } from './swapKitNumber.ts';
22
-
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
- };
1
+ import type { CommonAssetString } from "../helpers/asset.ts";
2
+ import { getAssetType, getCommonAssetInfo, getDecimal, isGasAsset } from "../helpers/asset.ts";
3
+ import { validateIdentifier } from "../helpers/validators.ts";
4
+ import { BaseDecimal, Chain, type ChainId, ChainToChainId } from "../types/chains.ts";
5
+ import type { TokenNames, TokenTax } from "../types/tokens.ts";
53
6
 
54
- const createAssetValue = async (assetString: string, value: number | string = 0) => {
55
- validateIdentifier(assetString);
7
+ import type { NumberPrimitives } from "./bigIntArithmetics.ts";
8
+ import { BigIntArithmetics, formatBigIntToSafeValue } from "./bigIntArithmetics.ts";
9
+ import { SwapKitNumber, type SwapKitValueType } from "./swapKitNumber.ts";
56
10
 
57
- const decimal = await getDecimal(getAssetInfo(assetString));
58
- return new AssetValue({ decimal, value, identifier: assetString });
59
- };
11
+ const staticTokensMap = new Map<
12
+ TokenNames,
13
+ { tax?: TokenTax; decimal: number; identifier: string }
14
+ >();
60
15
 
61
16
  export class AssetValue extends BigIntArithmetics {
62
- static async fromString(assetString: string, value: number | string = 0) {
63
- return createAssetValue(assetString, value);
17
+ address?: string;
18
+ chain: Chain;
19
+ isGasAsset = false;
20
+ isSynthetic = false;
21
+ symbol: string;
22
+ tax?: TokenTax;
23
+ ticker: string;
24
+ type: ReturnType<typeof getAssetType>;
25
+ chainId: ChainId;
26
+
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 });
39
+
40
+ const assetInfo = getAssetInfo(identifier || `${chain}.${symbol}`);
41
+
42
+ this.type = getAssetType(assetInfo);
43
+ this.tax = tax;
44
+ this.chain = assetInfo.chain;
45
+ this.ticker = assetInfo.ticker;
46
+ this.symbol = assetInfo.symbol;
47
+ this.address = assetInfo.address;
48
+ this.isSynthetic = assetInfo.isSynthetic;
49
+ this.isGasAsset = assetInfo.isGasAsset;
50
+ this.chainId = ChainToChainId[assetInfo.chain];
64
51
  }
65
52
 
66
- static fromStringSync(assetString: string, value: number | string = 0) {
67
- const { decimal, identifier: tokenIdentifier } = getStaticToken(
68
- assetString as unknown as TokenNames,
69
- );
53
+ toString() {
54
+ return this.isSynthetic ? this.symbol : `${this.chain}.${this.symbol}`;
55
+ }
70
56
 
71
- return tokenIdentifier
72
- ? new AssetValue({ decimal, identifier: tokenIdentifier, value })
73
- : undefined;
57
+ toUrl() {
58
+ return this.isSynthetic ? `${this.chain}.${this.symbol.replace("/", ".")}` : this.toString();
74
59
  }
75
60
 
76
- static async fromIdentifier(
77
- assetString: `${Chain}.${string}` | `${Chain}/${string}` | `${Chain}.${string}-${string}`,
78
- value: number | string = 0,
61
+ eq({ chain, symbol }: { chain: Chain; symbol: string }) {
62
+ return this.chain === chain && this.symbol === symbol;
63
+ }
64
+
65
+ // THOR.RUNE
66
+ // THOR.ETH.ETH
67
+ // ETH.THOR-0x1234567890
68
+ static fromUrl(urlAsset: string, value: NumberPrimitives = 0) {
69
+ const [chain, ticker, symbol] = urlAsset.split(".");
70
+ if (!(chain && ticker)) throw new Error("Invalid asset url");
71
+
72
+ const assetString =
73
+ chain === Chain.THORChain && symbol ? `${chain}.${ticker}/${symbol}` : urlAsset;
74
+
75
+ return createAssetValue(assetString, value);
76
+ }
77
+
78
+ static fromString(assetString: string, value: NumberPrimitives = 0) {
79
+ return createAssetValue(assetString, value);
80
+ }
81
+ static fromIdentifier(
82
+ assetString:
83
+ | `${Chain}.${string}`
84
+ | `${Chain}/${string}`
85
+ | `${Chain}.${string}-${string}`
86
+ | TokenNames,
87
+ value: NumberPrimitives = 0,
79
88
  ) {
80
89
  return createAssetValue(assetString, value);
81
90
  }
82
91
 
83
- static fromIdentifierSync(identifier: TokenNames, value: number | string = 0) {
84
- const { decimal, identifier: tokenIdentifier } = getStaticToken(identifier);
92
+ static fromStringSync(assetString: string, value: NumberPrimitives = 0) {
93
+ const { chain, isSynthetic } = getAssetInfo(assetString);
94
+ const tokenInfo = staticTokensMap.get(assetString.toUpperCase() as TokenNames);
95
+
96
+ if (isSynthetic) return createSyntheticAssetValue(assetString, value);
97
+ // TODO: write logger that will only run in dev mode with some flag
98
+ // if (!tokenInfo) {
99
+ // console.error(
100
+ // `Asset ${assetString} is not loaded. Use AssetValue.loadStaticAssets() to load it`,
101
+ // );
102
+ // }
103
+
104
+ const { tax, decimal, identifier } = tokenInfo || {
105
+ decimal: BaseDecimal[chain],
106
+ identifier: assetString,
107
+ };
108
+
109
+ return new AssetValue({
110
+ tax,
111
+ value: safeValue(value, decimal),
112
+ identifier: isSynthetic ? assetString : identifier,
113
+ decimal: isSynthetic ? 8 : decimal,
114
+ });
115
+ }
85
116
 
86
- return new AssetValue({ decimal, identifier: tokenIdentifier, value });
117
+ static async fromStringWithBase(
118
+ assetString: string,
119
+ value: NumberPrimitives = 0,
120
+ baseDecimal: number = BaseDecimal.THOR,
121
+ ) {
122
+ const shiftedAmount = BigIntArithmetics.shiftDecimals({
123
+ value: SwapKitNumber.fromBigInt(BigInt(value)),
124
+ from: 0,
125
+ to: baseDecimal,
126
+ }).getBaseValue("string");
127
+ const assetValue = await AssetValue.fromString(assetString, value);
128
+
129
+ return assetValue.set(shiftedAmount);
87
130
  }
88
131
 
89
- static fromChainOrSignature(assetString: CommonAssetString, value: number | string = 0) {
90
- const { decimal, identifier } = getCommonAssetInfo(assetString);
132
+ static fromStringWithBaseSync(
133
+ assetString: string,
134
+ value: NumberPrimitives = 0,
135
+ baseDecimal: number = BaseDecimal.THOR,
136
+ ) {
137
+ const { chain, isSynthetic } = getAssetInfo(assetString);
138
+ const tokenInfo = staticTokensMap.get(assetString.toUpperCase() as TokenNames);
91
139
 
92
- return new AssetValue({ value, decimal, identifier });
93
- }
140
+ if (isSynthetic) return createSyntheticAssetValue(assetString, value);
94
141
 
95
- static async fromTCQuote(identifier: TCTokenNames, value: number | string = 0) {
96
- const decimal = await getDecimal(getAssetInfo(identifier));
97
- const shiftedValue = this.shiftDecimals({ value, from: BaseDecimal.THOR, to: decimal });
142
+ const { tax, decimal, identifier } = tokenInfo || {
143
+ decimal: BaseDecimal[chain],
144
+ identifier: assetString,
145
+ };
98
146
 
99
- return new AssetValue({ value: shiftedValue, identifier, decimal });
147
+ return new AssetValue({
148
+ tax,
149
+ value: safeValue(BigInt(value), baseDecimal),
150
+ identifier,
151
+ decimal,
152
+ });
100
153
  }
101
154
 
102
- static fromTCQuoteStatic(identifier: TCTokenNames, value: number | string = 0) {
103
- const tokenInfo = getStaticToken(identifier);
104
- const shiftedValue = this.shiftDecimals({
105
- value,
106
- from: BaseDecimal.THOR,
107
- to: tokenInfo.decimal,
108
- });
155
+ static fromIdentifierSync(assetString: TokenNames, value: NumberPrimitives = 0) {
156
+ const { chain, isSynthetic } = getAssetInfo(assetString);
157
+ const tokenInfo = staticTokensMap.get(assetString);
158
+
159
+ if (isSynthetic) return createSyntheticAssetValue(assetString, value);
160
+ // TODO: write logger that will only run in dev mode with some flag
161
+ // if (!tokenInfo) {
162
+ // console.error(
163
+ // `Asset ${assetString} is not loaded. - Loading with base Chain. Use AssetValue.loadStaticAssets() to load it`,
164
+ // );
165
+ // }
166
+
167
+ const { tax, decimal, identifier } = tokenInfo || {
168
+ decimal: BaseDecimal[chain],
169
+ identifier: assetString,
170
+ };
171
+ return new AssetValue({ tax, decimal, identifier, value: safeValue(value, decimal) });
172
+ }
109
173
 
110
- return new AssetValue({ ...tokenInfo, value: shiftedValue });
174
+ static fromChainOrSignature(assetString: CommonAssetString, value: NumberPrimitives = 0) {
175
+ const { decimal, identifier } = getCommonAssetInfo(assetString);
176
+ return new AssetValue({ value: safeValue(value, decimal), decimal, identifier });
111
177
  }
112
178
 
113
- static async loadStaticAssets() {
114
- return new Promise<{ ok: true } | { ok: false; message: string; error: any }>(
115
- async (resolve, reject) => {
179
+ static loadStaticAssets() {
180
+ return new Promise<{ ok: true } | { ok: false; message: string; error: Todo }>(
181
+ (resolve, reject) => {
116
182
  try {
117
- const {
118
- // Omit ThorchainList from import to avoid decimals conflict (TC uses 8 for all)
119
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
120
- ThorchainList: _ThorchainList,
121
- NativeList,
122
- ...tokensPackage
123
- } = await import('@swapkit/tokens');
124
- const tokensMap = [NativeList, ...Object.values(tokensPackage)].reduce(
125
- (acc, { tokens }) => {
126
- tokens.forEach(({ identifier, chain, ...rest }) => {
127
- const decimal = 'decimals' in rest ? rest.decimals : BaseDecimal[chain as Chain];
128
-
129
- acc.set(identifier as TokenNames, { identifier, decimal });
130
- });
131
-
132
- return acc;
133
- },
134
- new Map<TokenNames, { decimal: number; identifier: string }>(),
135
- );
136
-
137
- staticTokensMap = tokensMap;
138
-
139
- resolve({ ok: true });
183
+ import("@swapkit/tokens").then((tokenPackages) => {
184
+ for (const tokenList of Object.values(tokenPackages)) {
185
+ for (const { identifier, chain, ...rest } of tokenList.tokens) {
186
+ staticTokensMap.set(identifier.toUpperCase() as TokenNames, {
187
+ identifier,
188
+ decimal: "decimals" in rest ? rest.decimals : BaseDecimal[chain as Chain],
189
+ });
190
+ }
191
+ }
192
+
193
+ resolve({ ok: true });
194
+ });
140
195
  } catch (error) {
141
196
  console.error(error);
142
197
  reject({
@@ -149,88 +204,105 @@ export class AssetValue extends BigIntArithmetics {
149
204
  },
150
205
  );
151
206
  }
152
-
153
- address?: string;
154
- chain: Chain;
155
- isSynthetic = false;
156
- isGasAsset = false;
157
- symbol: string;
158
- ticker: string;
159
- type: ReturnType<typeof getAssetType>;
160
-
161
- constructor(params: AssetValueParams) {
162
- super(
163
- params.value instanceof BigIntArithmetics
164
- ? params.value
165
- : { decimal: params.decimal, value: params.value },
166
- );
167
-
168
- const identifier =
169
- 'identifier' in params ? params.identifier : `${params.chain}.${params.symbol}`;
170
- const assetInfo = getAssetInfo(identifier);
171
-
172
- this.type = getAssetType(assetInfo);
173
- this.chain = assetInfo.chain;
174
- this.ticker = assetInfo.ticker;
175
- this.symbol = assetInfo.symbol;
176
- this.address = assetInfo.address;
177
- this.isSynthetic = assetInfo.isSynthetic;
178
- this.isGasAsset = assetInfo.isGasAsset;
179
- }
180
-
181
- get assetValue() {
182
- return `${this.value} ${this.ticker}`;
183
- }
184
-
185
- toString() {
186
- return `${this.chain}.${this.symbol}`;
187
- }
188
-
189
- eq({ chain, symbol }: { chain: Chain; symbol: string }) {
190
- return this.chain === chain && this.symbol === symbol;
191
- }
192
207
  }
193
208
 
194
- export const getMinAmountByChain = (chain: Chain) => {
209
+ export function getMinAmountByChain(chain: Chain) {
195
210
  const asset = AssetValue.fromChainOrSignature(chain);
196
211
 
197
212
  switch (chain) {
198
213
  case Chain.Bitcoin:
199
214
  case Chain.Litecoin:
200
215
  case Chain.BitcoinCash:
201
- return asset.add(10001);
216
+ return asset.set(0.00010001);
202
217
 
203
218
  case Chain.Dogecoin:
204
- return asset.add(100000001);
219
+ return asset.set(1.00000001);
205
220
 
206
221
  case Chain.Avalanche:
207
222
  case Chain.Ethereum:
208
- return asset.add(10 * 10 ** 9);
223
+ return asset.set(0.00000001);
209
224
 
210
225
  case Chain.THORChain:
211
226
  case Chain.Maya:
212
- return asset.add(0);
227
+ return asset.set(0);
228
+
229
+ case Chain.Cosmos:
230
+ return asset.set(0.000001);
213
231
 
214
232
  default:
215
- return asset.add(1);
233
+ return asset.set(0.00000001);
234
+ }
235
+ }
236
+
237
+ async function createAssetValue(identifier: string, value: NumberPrimitives = 0) {
238
+ validateIdentifier(identifier);
239
+
240
+ const staticToken = staticTokensMap.get(identifier.toUpperCase() as TokenNames);
241
+ const decimal = staticToken?.decimal || (await getDecimal(getAssetInfo(identifier)));
242
+ if (!staticToken) {
243
+ staticTokensMap.set(identifier.toUpperCase() as TokenNames, { identifier, decimal });
216
244
  }
217
- };
218
245
 
219
- const getAssetInfo = (identifier: string) => {
220
- const isSynthetic = identifier.slice(0, 14).includes('/');
221
- const adjustedIdentifier = identifier.includes('.')
222
- ? identifier
223
- : `${Chain.THORChain}.${identifier}`;
246
+ return new AssetValue({ decimal, value: safeValue(value, decimal), identifier });
247
+ }
248
+
249
+ function createSyntheticAssetValue(identifier: string, value: NumberPrimitives = 0) {
250
+ const [synthChain, symbol] =
251
+ identifier.split(".")?.[0]?.toUpperCase() === Chain.THORChain
252
+ ? identifier.split(".").slice(1).join().split("/")
253
+ : identifier.split("/");
224
254
 
225
- const [chain, symbol] = adjustedIdentifier.split('.') as [Chain, string];
226
- const [ticker, address] = symbol.split('-') as [string, string?];
255
+ if (!(synthChain && symbol)) throw new Error("Invalid asset identifier");
256
+
257
+ return new AssetValue({
258
+ decimal: 8,
259
+ value: safeValue(value, 8),
260
+ identifier: `${Chain.THORChain}.${synthChain}/${symbol}`,
261
+ });
262
+ }
263
+
264
+ function safeValue(value: NumberPrimitives, decimal: number) {
265
+ return typeof value === "bigint"
266
+ ? formatBigIntToSafeValue({ value, bigIntDecimal: decimal, decimal })
267
+ : value;
268
+ }
269
+
270
+ // TODO refactor & split into smaller functions
271
+ function getAssetInfo(identifier: string) {
272
+ const isSynthetic = identifier.slice(0, 14).includes("/");
273
+
274
+ const isThorchain = identifier.split(".")?.[0]?.toUpperCase() === Chain.THORChain;
275
+ const isMaya = identifier.split(".")?.[0]?.toUpperCase() === Chain.Maya;
276
+
277
+ const [synthChain, synthSymbol = ""] =
278
+ isThorchain || isMaya
279
+ ? identifier.split(".").slice(1).join().split("/")
280
+ : identifier.split("/");
281
+
282
+ if (isSynthetic && !(synthChain && synthSymbol)) throw new Error("Invalid asset identifier");
283
+
284
+ const adjustedIdentifier =
285
+ identifier.includes(".") && !isSynthetic
286
+ ? identifier
287
+ : `${isMaya ? Chain.Maya : Chain.THORChain}.${synthSymbol}`;
288
+
289
+ const [chain, ...rest] = adjustedIdentifier.split(".") as [Chain, string];
290
+
291
+ const symbol = isSynthetic ? synthSymbol : rest.join(".");
292
+ const splitSymbol = symbol.split("-");
293
+ const ticker = (
294
+ splitSymbol.length === 1 ? splitSymbol[0] : splitSymbol.slice(0, -1).join("-")
295
+ ) as string;
296
+ const address = splitSymbol.length === 1 ? undefined : splitSymbol[splitSymbol.length - 1];
227
297
 
228
298
  return {
229
299
  address: address?.toLowerCase(),
230
300
  chain,
231
301
  isGasAsset: isGasAsset({ chain, symbol }),
232
302
  isSynthetic,
233
- symbol: address ? `${ticker}-${address?.toLowerCase() ?? ''}` : symbol,
234
- ticker: isSynthetic ? symbol : ticker,
303
+ symbol:
304
+ (isSynthetic ? `${synthChain}/` : "") +
305
+ (address ? `${ticker}-${address?.toLowerCase() ?? ""}` : symbol),
306
+ ticker,
235
307
  };
236
- };
308
+ }