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

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,3 +1,5 @@
1
+ import { BaseDecimal } from '@swapkit/types';
2
+
1
3
  import type { SwapKitNumber } from './swapKitNumber.ts';
2
4
 
3
5
  type NumberPrimitivesType = {
@@ -5,10 +7,11 @@ type NumberPrimitivesType = {
5
7
  number: number;
6
8
  string: string;
7
9
  };
8
- type NumberPrimitives = bigint | number | string;
10
+ export type NumberPrimitives = bigint | number | string;
9
11
  type InitialisationValueType = NumberPrimitives | BigIntArithmetics | SwapKitNumber;
10
12
 
11
13
  type SKBigIntParams = InitialisationValueType | { decimal?: number; value: number | string };
14
+ type AllowedNumberTypes = 'bigint' | 'number' | 'string';
12
15
 
13
16
  const DEFAULT_DECIMAL = 8;
14
17
  const toMultiplier = (decimal: number) => 10n ** BigInt(decimal);
@@ -23,6 +26,7 @@ export function formatBigIntToSafeValue({
23
26
  bigIntDecimal?: number;
24
27
  decimal?: number;
25
28
  }) {
29
+ if (decimal === 0) return value.toString();
26
30
  const isNegative = value < 0n;
27
31
  let valueString = value.toString().substring(isNegative ? 1 : 0);
28
32
 
@@ -69,47 +73,30 @@ export class BigIntArithmetics {
69
73
  from,
70
74
  to,
71
75
  }: {
72
- value: InitialisationValueType;
76
+ value: InstanceType<typeof SwapKitNumber>;
73
77
  from: number;
74
78
  to: number;
75
79
  }) {
76
- return BigIntArithmetics.fromBigInt(
77
- (new BigIntArithmetics(value).bigIntValue * toMultiplier(to)) / toMultiplier(from),
80
+ return this.fromBigInt(
81
+ (value.getBaseValue('bigint') * toMultiplier(to)) / toMultiplier(from),
78
82
  to,
79
83
  );
80
84
  }
81
85
 
82
86
  constructor(params: SKBigIntParams) {
83
87
  const value = getStringValue(params);
84
- this.decimal = typeof params === 'object' ? params.decimal : undefined;
88
+ const isComplex = typeof params === 'object';
89
+ this.decimal = isComplex ? params.decimal : undefined;
85
90
 
86
91
  // use the multiplier to keep track of decimal point - defaults to 8 if lower than 8
87
- this.decimalMultiplier = toMultiplier(
88
- Math.max(this.#getFloatDecimals(this.#toSafeValue(value)), this.decimal || 0),
89
- );
92
+ this.decimalMultiplier =
93
+ isComplex && 'decimalMultiplier' in params
94
+ ? params.decimalMultiplier
95
+ : toMultiplier(Math.max(getFloatDecimals(toSafeValue(value)), this.decimal || 0));
90
96
  this.#setValue(value);
91
97
  }
92
98
 
93
- /**
94
- * @deprecated Use `getBaseValue('string')` instead
95
- */
96
- get baseValue() {
97
- return this.getBaseValue('string') as string;
98
- }
99
- /**
100
- * @deprecated Use `getBaseValue('number')` instead
101
- */
102
- get baseValueNumber() {
103
- return this.getBaseValue('number') as number;
104
- }
105
- /**
106
- * @deprecated Use `getBaseValue('bigint')` instead
107
- */
108
- get baseValueBigInt() {
109
- return this.getBaseValue('bigint') as bigint;
110
- }
111
-
112
- set(value: SKBigIntParams) {
99
+ set(value: SKBigIntParams): this {
113
100
  // @ts-expect-error False positive
114
101
  return new this.constructor({ decimal: this.decimal, value, identifier: this.toString() });
115
102
  }
@@ -126,22 +113,23 @@ export class BigIntArithmetics {
126
113
  return this.#arithmetics('div', ...args);
127
114
  }
128
115
  gt(value: InitialisationValueType) {
129
- return this.bigIntValue > this.getBigIntValue(value);
116
+ return this.#comparison('gt', value);
130
117
  }
131
118
  gte(value: InitialisationValueType) {
132
- return this.bigIntValue >= this.getBigIntValue(value);
119
+ return this.#comparison('gte', value);
133
120
  }
134
121
  lt(value: InitialisationValueType) {
135
- return this.bigIntValue < this.getBigIntValue(value);
122
+ return this.#comparison('lt', value);
136
123
  }
137
124
  lte(value: InitialisationValueType) {
138
- return this.bigIntValue <= this.getBigIntValue(value);
125
+ return this.#comparison('lte', value);
139
126
  }
140
127
  eqValue(value: InitialisationValueType) {
141
- return this.bigIntValue === this.getBigIntValue(value);
128
+ return this.#comparison('eqValue', value);
142
129
  }
143
130
 
144
- getValue<T extends 'number' | 'string' | 'bigint'>(type: T): NumberPrimitivesType[T] {
131
+ // @ts-expect-error False positive
132
+ getValue<T extends AllowedNumberTypes>(type: T): NumberPrimitivesType[T] {
145
133
  const value = this.formatBigIntToSafeValue(
146
134
  this.bigIntValue,
147
135
  this.decimal || decimalFromMultiplier(this.decimalMultiplier),
@@ -149,31 +137,27 @@ export class BigIntArithmetics {
149
137
 
150
138
  switch (type) {
151
139
  case 'number':
152
- // @ts-expect-error False positive
153
- return Number(value);
140
+ return Number(value) as NumberPrimitivesType[T];
154
141
  case 'string':
155
- // @ts-expect-error False positive
156
- return value;
157
- default:
158
- // @ts-expect-error False positive
159
- return this.bigIntValue;
142
+ return value as NumberPrimitivesType[T];
143
+ case 'bigint':
144
+ return ((this.bigIntValue * 10n ** BigInt(this.decimal || 8n)) /
145
+ this.decimalMultiplier) as NumberPrimitivesType[T];
160
146
  }
161
147
  }
162
148
 
163
- getBaseValue<T extends 'number' | 'string' | 'bigint'>(type: T): NumberPrimitivesType[T] {
164
- const divisor = this.decimalMultiplier / toMultiplier(this.decimal || 0);
149
+ // @ts-expect-error
150
+ getBaseValue<T extends AllowedNumberTypes>(type: T): NumberPrimitivesType[T] {
151
+ const divisor = this.decimalMultiplier / toMultiplier(this.decimal || BaseDecimal.THOR);
165
152
  const baseValue = this.bigIntValue / divisor;
166
153
 
167
154
  switch (type) {
168
155
  case 'number':
169
- // @ts-expect-error False positive
170
- return Number(baseValue);
156
+ return Number(baseValue) as NumberPrimitivesType[T];
171
157
  case 'string':
172
- // @ts-expect-error False positive
173
- return baseValue.toString();
174
- default:
175
- // @ts-expect-error False positive
176
- return this.bigIntValue;
158
+ return baseValue.toString() as NumberPrimitivesType[T];
159
+ case 'bigint':
160
+ return baseValue as NumberPrimitivesType[T];
177
161
  }
178
162
  }
179
163
 
@@ -181,12 +165,99 @@ export class BigIntArithmetics {
181
165
  if (!decimal && typeof value === 'object') return value.bigIntValue;
182
166
 
183
167
  const stringValue = getStringValue(value);
184
- const safeValue = this.#toSafeValue(stringValue);
168
+ const safeValue = toSafeValue(stringValue);
185
169
 
186
170
  if (safeValue === '0' || safeValue === 'undefined') return 0n;
187
171
  return this.#toBigInt(safeValue, decimal);
188
172
  }
189
173
 
174
+ toSignificant(significantDigits: number = 6) {
175
+ const [int, dec] = this.getValue('string').split('.');
176
+ const integer = int || '';
177
+ const decimal = dec || '';
178
+ const valueLength = parseInt(integer) ? integer.length + decimal.length : decimal.length;
179
+
180
+ if (valueLength <= significantDigits) {
181
+ return this.getValue('string');
182
+ }
183
+
184
+ if (integer.length >= significantDigits) {
185
+ return integer.slice(0, significantDigits).padEnd(integer.length, '0');
186
+ }
187
+
188
+ if (parseInt(integer)) {
189
+ return `${integer}.${decimal.slice(0, significantDigits - integer.length)}`.padEnd(
190
+ significantDigits - integer.length,
191
+ '0',
192
+ );
193
+ }
194
+
195
+ const trimmedDecimal = parseInt(decimal);
196
+ const slicedDecimal = `${trimmedDecimal}`.slice(0, significantDigits);
197
+
198
+ return `0.${slicedDecimal.padStart(
199
+ decimal.length - `${trimmedDecimal}`.length + slicedDecimal.length,
200
+ '0',
201
+ )}`;
202
+ }
203
+
204
+ toFixed(fixedDigits: number = 6) {
205
+ const [int, dec] = this.getValue('string').split('.');
206
+ const integer = int || '';
207
+ const decimal = dec || '';
208
+
209
+ if (parseInt(integer)) {
210
+ return `${integer}.${decimal.slice(0, fixedDigits)}`.padEnd(fixedDigits, '0');
211
+ }
212
+
213
+ const trimmedDecimal = parseInt(decimal);
214
+ const slicedDecimal = `${trimmedDecimal}`.slice(0, fixedDigits);
215
+
216
+ return `0.${slicedDecimal.padStart(
217
+ decimal.length - `${trimmedDecimal}`.length + slicedDecimal.length,
218
+ '0',
219
+ )}`;
220
+ }
221
+
222
+ toAbbreviation(digits = 2) {
223
+ const value = this.getValue('number');
224
+ const abbreviations = ['', 'K', 'M', 'B', 'T', 'Q', 'Qi', 'S'];
225
+ const tier = Math.floor(Math.log10(Math.abs(value)) / 3);
226
+ const suffix = abbreviations[tier];
227
+
228
+ if (!suffix) return this.getValue('string');
229
+
230
+ const scale = 10 ** (tier * 3);
231
+ const scaled = value / scale;
232
+
233
+ return `${scaled.toFixed(digits)}${suffix}`;
234
+ }
235
+
236
+ toCurrency(
237
+ currency = '$',
238
+ {
239
+ currencyPosition = 'start',
240
+ decimal = 2,
241
+ decimalSeparator = '.',
242
+ thousandSeparator = ',',
243
+ } = {},
244
+ ) {
245
+ const value = this.getValue('number');
246
+ const [int, dec = ''] = value.toFixed(6).split('.');
247
+ const integer = int.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
248
+
249
+ const parsedValue =
250
+ !int && !dec
251
+ ? '0.00'
252
+ : int === '0'
253
+ ? `${parseFloat(`0.${dec}`)}`.replace('.', decimalSeparator)
254
+ : `${integer}${parseInt(dec) ? `${decimalSeparator}${dec.slice(0, decimal)}` : ''}`;
255
+
256
+ return `${currencyPosition === 'start' ? currency : ''}${parsedValue}${
257
+ currencyPosition === 'end' ? currency : ''
258
+ }`;
259
+ }
260
+
190
261
  formatBigIntToSafeValue(value: bigint, decimal?: number) {
191
262
  const bigIntDecimal = decimal || this.decimal || DEFAULT_DECIMAL;
192
263
  const decimalToUseForConversion = Math.max(
@@ -220,43 +291,14 @@ export class BigIntArithmetics {
220
291
  )}.${decimalString}`.replace(/\.?0*$/, '');
221
292
  }
222
293
 
223
- toSignificant(significantDigits: number = 6) {
224
- const [int, dec] = this.getValue('string').split('.');
225
- const integer = int || '';
226
- const decimal = dec || '';
227
- const valueLength = parseInt(integer) ? integer.length + decimal.length : decimal.length;
228
-
229
- if (valueLength <= significantDigits) {
230
- return this.getValue('string');
231
- }
232
-
233
- if (integer.length >= significantDigits) {
234
- return integer.slice(0, significantDigits).padEnd(integer.length, '0');
235
- }
236
-
237
- if (parseInt(integer)) {
238
- return `${integer}.${decimal.slice(0, significantDigits - integer.length)}`.padEnd(
239
- valueLength - significantDigits,
240
- '0',
241
- );
242
- }
243
-
244
- const trimmedDecimal = parseInt(decimal);
245
- const slicedDecimal = `${trimmedDecimal}`.slice(0, significantDigits);
246
-
247
- return `0.${slicedDecimal.padStart(
248
- decimal.length - `${trimmedDecimal}`.length + slicedDecimal.length,
249
- '0',
250
- )}`;
251
- }
252
-
253
294
  #arithmetics(method: 'add' | 'sub' | 'mul' | 'div', ...args: InitialisationValueType[]): this {
254
295
  const precisionDecimal = this.#retrievePrecisionDecimal(this, ...args);
255
- const precisionDecimalMultiplier = toMultiplier(precisionDecimal);
296
+ const decimal = Math.max(precisionDecimal, decimalFromMultiplier(this.decimalMultiplier));
297
+ const precisionDecimalMultiplier = toMultiplier(decimal);
256
298
 
257
299
  const result = args.reduce(
258
300
  (acc: bigint, arg) => {
259
- const value = this.getBigIntValue(arg, precisionDecimal);
301
+ const value = this.getBigIntValue(arg, decimal);
260
302
 
261
303
  switch (method) {
262
304
  case 'add':
@@ -286,28 +328,56 @@ export class BigIntArithmetics {
286
328
  );
287
329
 
288
330
  const value = formatBigIntToSafeValue({
289
- bigIntDecimal: precisionDecimal,
290
- decimal: Math.max(precisionDecimal, decimalFromMultiplier(this.decimalMultiplier)),
331
+ bigIntDecimal: decimal,
332
+ decimal,
291
333
  value: result,
292
334
  });
293
335
 
294
336
  // @ts-expect-error False positive
295
- return new this.constructor({ decimal: this.decimal, value, identifier: this.toString() });
337
+ return new this.constructor({
338
+ decimalMultiplier: toMultiplier(decimal),
339
+ decimal: this.decimal,
340
+ value,
341
+ identifier: this.toString(),
342
+ });
343
+ }
344
+
345
+ #comparison(method: 'gt' | 'gte' | 'lt' | 'lte' | 'eqValue', ...args: InitialisationValueType[]) {
346
+ const decimal = this.#retrievePrecisionDecimal(this, ...args);
347
+ const value = this.getBigIntValue(args[0], decimal);
348
+ const compareToValue = this.getBigIntValue(this, decimal);
349
+
350
+ switch (method) {
351
+ case 'gt':
352
+ return compareToValue > value;
353
+ case 'gte':
354
+ return compareToValue >= value;
355
+ case 'lt':
356
+ return compareToValue < value;
357
+ case 'lte':
358
+ return compareToValue <= value;
359
+ case 'eqValue':
360
+ return compareToValue === value;
361
+ }
296
362
  }
297
363
 
298
364
  #setValue(value: InitialisationValueType) {
299
- const safeValue = this.#toSafeValue(value) || '0';
365
+ const safeValue = toSafeValue(value) || '0';
300
366
  this.bigIntValue = this.#toBigInt(safeValue);
301
367
  }
302
368
 
303
369
  #retrievePrecisionDecimal(...args: InitialisationValueType[]) {
304
370
  const decimals = args
305
- .map((arg) =>
306
- typeof arg === 'object'
371
+ .map((arg) => {
372
+ const isObject = typeof arg === 'object';
373
+ const value = isObject
307
374
  ? arg.decimal || decimalFromMultiplier(arg.decimalMultiplier)
308
- : this.#getFloatDecimals(this.#toSafeValue(arg)),
309
- )
375
+ : getFloatDecimals(toSafeValue(arg));
376
+
377
+ return value;
378
+ })
310
379
  .filter(Boolean) as number[];
380
+
311
381
  return Math.max(...decimals, DEFAULT_DECIMAL);
312
382
  }
313
383
 
@@ -318,33 +388,32 @@ export class BigIntArithmetics {
318
388
 
319
389
  return BigInt(`${integerPart}${decimalPart.padEnd(padDecimal, '0')}`);
320
390
  }
391
+ }
321
392
 
322
- #toSafeValue(value: InitialisationValueType) {
323
- const parsedValue =
324
- typeof value === 'number'
325
- ? Number(value).toLocaleString('fullwide', {
326
- useGrouping: false,
327
- maximumFractionDigits: 20,
328
- })
329
- : getStringValue(value);
330
-
331
- const splitValue = `${parsedValue}`.replaceAll(',', '.').split('.');
332
-
333
- return splitValue.length > 1
334
- ? `${splitValue.slice(0, -1).join('')}.${splitValue.at(-1)}`
335
- : splitValue[0];
336
- }
393
+ const numberFormatter = Intl.NumberFormat('fullwide', {
394
+ useGrouping: false,
395
+ maximumFractionDigits: 20,
396
+ });
337
397
 
338
- #getFloatDecimals(value: string) {
339
- const decimals = value.split('.')[1]?.length || 0;
340
- return Math.max(decimals, DEFAULT_DECIMAL);
341
- }
398
+ function toSafeValue(value: InitialisationValueType) {
399
+ const parsedValue =
400
+ typeof value === 'number' ? numberFormatter.format(value) : getStringValue(value);
401
+ const splitValue = `${parsedValue}`.replaceAll(',', '.').split('.');
402
+
403
+ return splitValue.length > 1
404
+ ? `${splitValue.slice(0, -1).join('')}.${splitValue.at(-1)}`
405
+ : splitValue[0];
406
+ }
407
+
408
+ function getFloatDecimals(value: string) {
409
+ const decimals = value.split('.')[1]?.length || 0;
410
+ return Math.max(decimals, DEFAULT_DECIMAL);
342
411
  }
343
412
 
344
- function getStringValue(value: SKBigIntParams) {
345
- return typeof value === 'object'
346
- ? 'getValue' in value
347
- ? value.getValue('string')
348
- : value.value
349
- : value;
413
+ function getStringValue(param: SKBigIntParams) {
414
+ return typeof param === 'object'
415
+ ? 'getValue' in param
416
+ ? param.getValue('string')
417
+ : param.value
418
+ : param;
350
419
  }
@@ -19,6 +19,7 @@ const errorMessages = {
19
19
  core_wallet_trezor_not_installed: 10106,
20
20
  core_wallet_keplr_not_installed: 10107,
21
21
  core_wallet_okx_not_installed: 10108,
22
+ core_wallet_keepkey_not_installed: 10109,
22
23
  /**
23
24
  * Core - Swap
24
25
  */
@@ -45,12 +46,18 @@ const errorMessages = {
45
46
  core_transaction_deposit_to_pool_error: 10310,
46
47
  core_transaction_deposit_insufficient_funds_error: 10311,
47
48
  core_transaction_deposit_gas_error: 10312,
48
- core_transaction_deposit_server_error: 10313,
49
+ core_transaction_invalid_sender_address: 10313,
50
+ core_transaction_deposit_server_error: 10314,
51
+ core_transaction_user_rejected: 10315,
49
52
 
50
53
  /**
51
54
  * Wallets
52
55
  */
53
56
  wallet_ledger_connection_error: 20001,
57
+ wallet_ledger_connection_claimed: 20002,
58
+ wallet_ledger_get_address_error: 20003,
59
+ wallet_ledger_device_not_found: 20004,
60
+ wallet_ledger_device_locked: 20005,
54
61
 
55
62
  /**
56
63
  * Helpers
@@ -58,11 +65,13 @@ const errorMessages = {
58
65
  helpers_number_different_decimals: 99101,
59
66
  } as const;
60
67
 
61
- export type Keys = keyof typeof errorMessages;
68
+ export type ErrorKeys = keyof typeof errorMessages;
62
69
 
63
70
  export class SwapKitError extends Error {
64
- constructor(errorKey: Keys, sourceError?: any) {
65
- console.error(sourceError);
71
+ constructor(errorKey: ErrorKeys, sourceError?: any) {
72
+ if (sourceError) {
73
+ console.error(sourceError, { stack: sourceError?.stack, message: sourceError?.message });
74
+ }
66
75
 
67
76
  super(errorKey, { cause: { code: errorMessages[errorKey], message: errorKey } });
68
77
  Object.setPrototypeOf(this, SwapKitError.prototype);
@@ -1,4 +1,4 @@
1
- import { BigIntArithmetics } from './bigIntArithmetics.ts';
1
+ import { BigIntArithmetics, formatBigIntToSafeValue } from './bigIntArithmetics.ts';
2
2
 
3
3
  export type SwapKitValueType = BigIntArithmetics | string | number;
4
4
 
@@ -6,4 +6,11 @@ export class SwapKitNumber extends BigIntArithmetics {
6
6
  eq(value: SwapKitValueType) {
7
7
  return this.eqValue(value);
8
8
  }
9
+
10
+ static fromBigInt(value: bigint, decimal?: number) {
11
+ return new SwapKitNumber({
12
+ decimal,
13
+ value: formatBigIntToSafeValue({ value, bigIntDecimal: decimal, decimal }),
14
+ });
15
+ }
9
16
  }
package/src/types.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type {
2
+ ChainflipList,
3
+ CoinGeckoList,
4
+ MayaList,
5
+ PancakeswapETHList,
6
+ PancakeswapList,
7
+ PangolinList,
8
+ StargateARBList,
9
+ SushiswapList,
10
+ ThorchainList,
11
+ TraderjoeList,
12
+ UniswapList,
13
+ WoofiList,
14
+ } from '@swapkit/tokens';
15
+
16
+ export type TokenTax = { buy: number; sell: number };
17
+
18
+ export type TokenNames =
19
+ | (typeof ThorchainList)['tokens'][number]['identifier']
20
+ | (typeof CoinGeckoList)['tokens'][number]['identifier']
21
+ | (typeof MayaList)['tokens'][number]['identifier']
22
+ | (typeof PancakeswapETHList)['tokens'][number]['identifier']
23
+ | (typeof PancakeswapList)['tokens'][number]['identifier']
24
+ | (typeof PangolinList)['tokens'][number]['identifier']
25
+ | (typeof StargateARBList)['tokens'][number]['identifier']
26
+ | (typeof SushiswapList)['tokens'][number]['identifier']
27
+ | (typeof TraderjoeList)['tokens'][number]['identifier']
28
+ | (typeof WoofiList)['tokens'][number]['identifier']
29
+ | (typeof UniswapList)['tokens'][number]['identifier']
30
+ | (typeof ChainflipList)['tokens'][number]['identifier'];