@swapkit/helpers 1.0.0-rc.8 → 1.0.0-rc.80

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';
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
- };
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
- };
1
+ import { BaseDecimal, Chain, ChainToChainId } from "@swapkit/types";
2
+
3
+ import type { CommonAssetString } from "../helpers/asset.ts";
4
+ import { getAssetType, getCommonAssetInfo, getDecimal, isGasAsset } from "../helpers/asset.ts";
5
+ import { validateIdentifier } from "../helpers/validators.ts";
6
+ import type { TokenNames, TokenTax } from "../types.ts";
7
+
8
+ import type { NumberPrimitives } from "./bigIntArithmetics.ts";
9
+ import { BigIntArithmetics, formatBigIntToSafeValue } from "./bigIntArithmetics.ts";
10
+ import { SwapKitNumber, type SwapKitValueType } from "./swapKitNumber.ts";
11
+
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,102 +49,152 @@ 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");
74
+
75
+ const assetString =
76
+ chain === Chain.THORChain && symbol ? `${chain}.${ticker}/${symbol}` : urlAsset;
116
77
 
117
- return tokenIdentifier
118
- ? new AssetValue({ decimal, identifier: tokenIdentifier, value })
119
- : undefined;
78
+ return createAssetValue(assetString, value);
120
79
  }
121
80
 
122
- static async fromIdentifier(
123
- assetString: `${Chain}.${string}` | `${Chain}/${string}` | `${Chain}.${string}-${string}`,
124
- value: number | string = 0,
81
+ static fromString(assetString: string, value: NumberPrimitives = 0) {
82
+ return createAssetValue(assetString, value);
83
+ }
84
+ static fromIdentifier(
85
+ assetString:
86
+ | `${Chain}.${string}`
87
+ | `${Chain}/${string}`
88
+ | `${Chain}.${string}-${string}`
89
+ | TokenNames,
90
+ value: NumberPrimitives = 0,
125
91
  ) {
126
92
  return createAssetValue(assetString, value);
127
93
  }
128
94
 
129
- static fromIdentifierSync(identifier: TokenNames, value: number | string = 0) {
130
- const { decimal, identifier: tokenIdentifier } = getStaticToken(identifier);
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
+ });
118
+ }
131
119
 
132
- return new AssetValue({ decimal, identifier: tokenIdentifier, value });
120
+ static async fromStringWithBase(
121
+ assetString: string,
122
+ value: NumberPrimitives = 0,
123
+ baseDecimal: number = BaseDecimal.THOR,
124
+ ) {
125
+ const shiftedAmount = BigIntArithmetics.shiftDecimals({
126
+ value: SwapKitNumber.fromBigInt(BigInt(value)),
127
+ from: 0,
128
+ to: baseDecimal,
129
+ }).getBaseValue("string");
130
+ const assetValue = await AssetValue.fromString(assetString, value);
131
+
132
+ return assetValue.set(shiftedAmount);
133
133
  }
134
134
 
135
- static fromChainOrSignature(assetString: CommonAssetString, value: number | string = 0) {
136
- const { decimal, identifier } = getCommonAssetInfo(assetString);
135
+ static fromStringWithBaseSync(
136
+ assetString: string,
137
+ value: NumberPrimitives = 0,
138
+ baseDecimal: number = BaseDecimal.THOR,
139
+ ) {
140
+ const { chain, isSynthetic } = getAssetInfo(assetString);
141
+ const tokenInfo = staticTokensMap.get(assetString.toUpperCase() as TokenNames);
137
142
 
138
- return new AssetValue({ value, decimal, identifier });
139
- }
143
+ if (isSynthetic) return createSyntheticAssetValue(assetString, value);
140
144
 
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 });
145
+ const { tax, decimal, identifier } = tokenInfo || {
146
+ decimal: BaseDecimal[chain],
147
+ identifier: assetString,
148
+ };
144
149
 
145
- return new AssetValue({ value: shiftedValue, identifier, decimal });
150
+ return new AssetValue({
151
+ tax,
152
+ value: safeValue(BigInt(value), baseDecimal),
153
+ identifier,
154
+ decimal,
155
+ });
146
156
  }
147
157
 
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
- });
158
+ static fromIdentifierSync(assetString: TokenNames, value: NumberPrimitives = 0) {
159
+ const { chain, isSynthetic } = getAssetInfo(assetString);
160
+ const tokenInfo = staticTokensMap.get(assetString);
161
+
162
+ if (isSynthetic) return createSyntheticAssetValue(assetString, value);
163
+ // TODO: write logger that will only run in dev mode with some flag
164
+ // if (!tokenInfo) {
165
+ // console.error(
166
+ // `Asset ${assetString} is not loaded. - Loading with base Chain. Use AssetValue.loadStaticAssets() to load it`,
167
+ // );
168
+ // }
169
+
170
+ const { tax, decimal, identifier } = tokenInfo || {
171
+ decimal: BaseDecimal[chain],
172
+ identifier: assetString,
173
+ };
174
+ return new AssetValue({ tax, decimal, identifier, value: safeValue(value, decimal) });
175
+ }
155
176
 
156
- return new AssetValue({ ...tokenInfo, value: shiftedValue });
177
+ static fromChainOrSignature(assetString: CommonAssetString, value: NumberPrimitives = 0) {
178
+ const { decimal, identifier } = getCommonAssetInfo(assetString);
179
+ return new AssetValue({ value: safeValue(value, decimal), decimal, identifier });
157
180
  }
158
181
 
159
- static async loadStaticAssets() {
182
+ static loadStaticAssets() {
160
183
  return new Promise<{ ok: true } | { ok: false; message: string; error: any }>(
161
- async (resolve, reject) => {
184
+ (resolve, reject) => {
162
185
  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
- });
177
-
178
- return acc;
179
- },
180
- new Map<TokenNames, { decimal: number; identifier: string }>(),
181
- );
182
-
183
- staticTokensMap = tokensMap;
184
-
185
- resolve({ ok: true });
186
+ import("@swapkit/tokens").then((tokenPackages) => {
187
+ for (const tokenList of Object.values(tokenPackages)) {
188
+ for (const { identifier, chain, ...rest } of tokenList.tokens) {
189
+ staticTokensMap.set(identifier.toUpperCase() as TokenNames, {
190
+ identifier,
191
+ decimal: "decimals" in rest ? rest.decimals : BaseDecimal[chain as Chain],
192
+ });
193
+ }
194
+ }
195
+
196
+ resolve({ ok: true });
197
+ });
186
198
  } catch (error) {
187
199
  console.error(error);
188
200
  reject({
@@ -197,46 +209,96 @@ export class AssetValue extends BigIntArithmetics {
197
209
  }
198
210
  }
199
211
 
200
- export const getMinAmountByChain = (chain: Chain) => {
212
+ export function getMinAmountByChain(chain: Chain) {
201
213
  const asset = AssetValue.fromChainOrSignature(chain);
202
214
 
203
215
  switch (chain) {
204
216
  case Chain.Bitcoin:
205
217
  case Chain.Litecoin:
206
218
  case Chain.BitcoinCash:
207
- return asset.add(10001);
219
+ return asset.set(0.00010001);
208
220
 
209
221
  case Chain.Dogecoin:
210
- return asset.add(100000001);
222
+ return asset.set(1.00000001);
211
223
 
212
224
  case Chain.Avalanche:
213
225
  case Chain.Ethereum:
214
- return asset.add(10 * 10 ** 9);
226
+ return asset.set(0.00000001);
215
227
 
216
228
  case Chain.THORChain:
217
229
  case Chain.Maya:
218
- return asset.add(0);
230
+ return asset.set(0);
231
+
232
+ case Chain.Cosmos:
233
+ return asset.set(0.000001);
219
234
 
220
235
  default:
221
- return asset.add(1);
236
+ return asset.set(0.00000001);
222
237
  }
223
- };
238
+ }
239
+
240
+ async function createAssetValue(identifier: string, value: NumberPrimitives = 0) {
241
+ validateIdentifier(identifier);
242
+
243
+ const staticToken = staticTokensMap.get(identifier.toUpperCase() as TokenNames);
244
+ const decimal = staticToken?.decimal || (await getDecimal(getAssetInfo(identifier)));
245
+ if (!staticToken) {
246
+ staticTokensMap.set(identifier.toUpperCase() as TokenNames, { identifier, decimal });
247
+ }
248
+
249
+ return new AssetValue({ decimal, value: safeValue(value, decimal), identifier });
250
+ }
224
251
 
225
- const getAssetInfo = (identifier: string) => {
226
- const isSynthetic = identifier.slice(0, 14).includes('/');
227
- const adjustedIdentifier = identifier.includes('.')
228
- ? identifier
229
- : `${Chain.THORChain}.${identifier}`;
252
+ function createSyntheticAssetValue(identifier: string, value: NumberPrimitives = 0) {
253
+ const [synthChain, symbol] =
254
+ identifier.split(".")[0].toUpperCase() === Chain.THORChain
255
+ ? identifier.split(".").slice(1).join().split("/")
256
+ : identifier.split("/");
230
257
 
231
- const [chain, symbol] = adjustedIdentifier.split('.') as [Chain, string];
232
- const [ticker, address] = symbol.split('-') as [string, string?];
258
+ if (!(synthChain && symbol)) throw new Error("Invalid asset identifier");
259
+
260
+ return new AssetValue({
261
+ decimal: 8,
262
+ value: safeValue(value, 8),
263
+ identifier: `${Chain.THORChain}.${synthChain}/${symbol}`,
264
+ });
265
+ }
266
+
267
+ function safeValue(value: NumberPrimitives, decimal: number) {
268
+ return typeof value === "bigint"
269
+ ? formatBigIntToSafeValue({ value, bigIntDecimal: decimal, decimal })
270
+ : value;
271
+ }
272
+
273
+ // TODO refactor & split into smaller functions
274
+ function getAssetInfo(identifier: string) {
275
+ const isSynthetic = identifier.slice(0, 14).includes("/");
276
+
277
+ const [synthChain, synthSymbol] =
278
+ identifier.split(".")[0].toUpperCase() === Chain.THORChain
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 ? identifier : `${Chain.THORChain}.${synthSymbol}`;
286
+
287
+ const [chain, ...rest] = adjustedIdentifier.split(".") as [Chain, string];
288
+ const [ticker, address] = (isSynthetic ? synthSymbol : rest.join(".")).split("-") as [
289
+ string,
290
+ string?,
291
+ ];
292
+ const symbol = isSynthetic ? synthSymbol : rest.join(".");
233
293
 
234
294
  return {
235
295
  address: address?.toLowerCase(),
236
296
  chain,
237
297
  isGasAsset: isGasAsset({ chain, symbol }),
238
298
  isSynthetic,
239
- symbol: address ? `${ticker}-${address?.toLowerCase() ?? ''}` : symbol,
240
- ticker: isSynthetic ? symbol : ticker,
299
+ symbol:
300
+ (isSynthetic ? `${synthChain}/` : "") +
301
+ (address ? `${ticker}-${address?.toLowerCase() ?? ""}` : symbol),
302
+ ticker,
241
303
  };
242
- };
304
+ }