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

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.
@@ -59,6 +59,52 @@ const createAssetValue = async (assetString: string, value: number | string = 0)
59
59
  };
60
60
 
61
61
  export class AssetValue extends BigIntArithmetics {
62
+ address?: string;
63
+ chain: Chain;
64
+ isSynthetic = false;
65
+ isGasAsset = false;
66
+ symbol: string;
67
+ ticker: string;
68
+ type: ReturnType<typeof getAssetType>;
69
+
70
+ constructor(params: AssetValueParams) {
71
+ super(
72
+ params.value instanceof BigIntArithmetics
73
+ ? params.value
74
+ : { decimal: params.decimal, value: params.value },
75
+ );
76
+
77
+ const identifier =
78
+ 'identifier' in params ? params.identifier : `${params.chain}.${params.symbol}`;
79
+ const assetInfo = getAssetInfo(identifier);
80
+
81
+ this.type = getAssetType(assetInfo);
82
+ this.chain = assetInfo.chain;
83
+ this.ticker = assetInfo.ticker;
84
+ this.symbol = assetInfo.symbol;
85
+ this.address = assetInfo.address;
86
+ this.isSynthetic = assetInfo.isSynthetic;
87
+ this.isGasAsset = assetInfo.isGasAsset;
88
+ }
89
+
90
+ get assetValue() {
91
+ return `${this.getValue('string')} ${this.ticker}`;
92
+ }
93
+
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}`;
102
+ }
103
+
104
+ eq({ chain, symbol }: { chain: Chain; symbol: string }) {
105
+ return this.chain === chain && this.symbol === symbol;
106
+ }
107
+
62
108
  static async fromString(assetString: string, value: number | string = 0) {
63
109
  return createAssetValue(assetString, value);
64
110
  }
@@ -149,46 +195,6 @@ export class AssetValue extends BigIntArithmetics {
149
195
  },
150
196
  );
151
197
  }
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
198
  }
193
199
 
194
200
  export const getMinAmountByChain = (chain: Chain) => {
@@ -1,11 +1,59 @@
1
- import { DEFAULT_DECIMAL, formatBigIntToSafeValue } from '../helpers/number.ts';
1
+ import { BaseDecimal } from '@swapkit/types';
2
2
 
3
- type AllowedValueType = bigint | number | string;
4
- type ArithmeticMethod = 'add' | 'sub' | 'mul' | 'div';
3
+ import type { SwapKitNumber } from './swapKitNumber.ts';
5
4
 
5
+ type NumberPrimitivesType = {
6
+ bigint: bigint;
7
+ number: number;
8
+ string: string;
9
+ };
10
+ type NumberPrimitives = bigint | number | string;
11
+ type InitialisationValueType = NumberPrimitives | BigIntArithmetics | SwapKitNumber;
12
+
13
+ type SKBigIntParams = InitialisationValueType | { decimal?: number; value: number | string };
14
+
15
+ const DEFAULT_DECIMAL = 8;
6
16
  const toMultiplier = (decimal: number) => 10n ** BigInt(decimal);
7
17
  const decimalFromMultiplier = (multiplier: bigint) => Math.log10(parseFloat(multiplier.toString()));
8
18
 
19
+ export function formatBigIntToSafeValue({
20
+ value,
21
+ bigIntDecimal = DEFAULT_DECIMAL,
22
+ decimal = DEFAULT_DECIMAL,
23
+ }: {
24
+ value: bigint;
25
+ bigIntDecimal?: number;
26
+ decimal?: number;
27
+ }) {
28
+ const isNegative = value < 0n;
29
+ let valueString = value.toString().substring(isNegative ? 1 : 0);
30
+
31
+ const padLength = decimal - (valueString.length - 1);
32
+
33
+ if (padLength > 0) {
34
+ valueString = '0'.repeat(padLength) + valueString;
35
+ }
36
+
37
+ const decimalIndex = valueString.length - decimal;
38
+ let decimalString = valueString.slice(-decimal);
39
+
40
+ // Check if we need to round up
41
+ if (parseInt(decimalString[bigIntDecimal]) >= 5) {
42
+ // Increment the last decimal place and slice off the rest
43
+ decimalString = `${decimalString.substring(0, bigIntDecimal - 1)}${(
44
+ parseInt(decimalString[bigIntDecimal - 1]) + 1
45
+ ).toString()}`;
46
+ } else {
47
+ // Just slice off the extra digits
48
+ decimalString = decimalString.substring(0, bigIntDecimal);
49
+ }
50
+
51
+ return `${isNegative ? '-' : ''}${valueString.slice(0, decimalIndex)}.${decimalString}`.replace(
52
+ /\.?0*$/,
53
+ '',
54
+ );
55
+ }
56
+
9
57
  export class BigIntArithmetics {
10
58
  decimalMultiplier: bigint = 10n ** 8n;
11
59
  bigIntValue: bigint = 0n;
@@ -23,7 +71,7 @@ export class BigIntArithmetics {
23
71
  from,
24
72
  to,
25
73
  }: {
26
- value: BigIntArithmetics | string | number;
74
+ value: InitialisationValueType;
27
75
  from: number;
28
76
  to: number;
29
77
  }) {
@@ -33,16 +81,9 @@ export class BigIntArithmetics {
33
81
  );
34
82
  }
35
83
 
36
- constructor(
37
- valueOrParams:
38
- | BigIntArithmetics
39
- | string
40
- | number
41
- | { decimal?: number; value: number | string },
42
- ) {
43
- const complexInit = typeof valueOrParams === 'object';
44
- const value = complexInit ? valueOrParams.value : valueOrParams;
45
- this.decimal = complexInit ? valueOrParams.decimal : undefined;
84
+ constructor(params: SKBigIntParams) {
85
+ const value = getStringValue(params);
86
+ this.decimal = typeof params === 'object' ? params.decimal : undefined;
46
87
 
47
88
  // use the multiplier to keep track of decimal point - defaults to 8 if lower than 8
48
89
  this.decimalMultiplier = toMultiplier(
@@ -51,58 +92,101 @@ export class BigIntArithmetics {
51
92
  this.#setValue(value);
52
93
  }
53
94
 
54
- get unsafeNumber() {
55
- return parseFloat((this.bigIntValue / this.decimalMultiplier).toString());
56
- }
95
+ /**
96
+ * @deprecated Use `getBaseValue('string')` instead
97
+ */
57
98
  get baseValue() {
58
- return this.#getBaseValue('string') as string;
99
+ return this.getBaseValue('string') as string;
59
100
  }
101
+ /**
102
+ * @deprecated Use `getBaseValue('number')` instead
103
+ */
60
104
  get baseValueNumber() {
61
- return this.#getBaseValue('number') as number;
105
+ return this.getBaseValue('number') as number;
62
106
  }
107
+ /**
108
+ * @deprecated Use `getBaseValue('bigint')` instead
109
+ */
63
110
  get baseValueBigInt() {
64
- return this.#getBaseValue('number') as bigint;
65
- }
66
- get value() {
67
- return this.formatBigIntToSafeValue(
68
- this.bigIntValue,
69
- this.decimal || decimalFromMultiplier(this.decimalMultiplier),
70
- );
111
+ return this.getBaseValue('bigint') as bigint;
71
112
  }
72
113
 
73
- add(...args: (BigIntArithmetics | string | number)[]) {
114
+ set(value: SKBigIntParams) {
115
+ // @ts-expect-error False positive
116
+ return new this.constructor({ decimal: this.decimal, value, identifier: this.toString() });
117
+ }
118
+ add(...args: InitialisationValueType[]) {
74
119
  return this.#arithmetics('add', ...args);
75
120
  }
76
- sub(...args: (BigIntArithmetics | string | number)[]) {
121
+ sub(...args: InitialisationValueType[]) {
77
122
  return this.#arithmetics('sub', ...args);
78
123
  }
79
- mul(...args: (BigIntArithmetics | string | number)[]) {
124
+ mul(...args: InitialisationValueType[]) {
80
125
  return this.#arithmetics('mul', ...args);
81
126
  }
82
- div(...args: (BigIntArithmetics | string | number)[]) {
127
+ div(...args: InitialisationValueType[]) {
83
128
  return this.#arithmetics('div', ...args);
84
129
  }
85
- gt(value: BigIntArithmetics | string | number) {
130
+ gt(value: InitialisationValueType) {
86
131
  return this.bigIntValue > this.getBigIntValue(value);
87
132
  }
88
- gte(value: BigIntArithmetics | string | number) {
133
+ gte(value: InitialisationValueType) {
89
134
  return this.bigIntValue >= this.getBigIntValue(value);
90
135
  }
91
- lt(value: BigIntArithmetics | string | number) {
136
+ lt(value: InitialisationValueType) {
92
137
  return this.bigIntValue < this.getBigIntValue(value);
93
138
  }
94
- lte(value: BigIntArithmetics | string | number) {
139
+ lte(value: InitialisationValueType) {
95
140
  return this.bigIntValue <= this.getBigIntValue(value);
96
141
  }
97
- eqValue(value: BigIntArithmetics | string | number) {
142
+ eqValue(value: InitialisationValueType) {
98
143
  return this.bigIntValue === this.getBigIntValue(value);
99
144
  }
100
145
 
101
- getBigIntValue(value: BigIntArithmetics | string | number, decimal?: number) {
146
+ getValue<T extends 'number' | 'string'>(type: T): NumberPrimitivesType[T] {
147
+ const value = this.formatBigIntToSafeValue(
148
+ this.bigIntValue,
149
+ this.decimal || decimalFromMultiplier(this.decimalMultiplier),
150
+ );
151
+
152
+ switch (type) {
153
+ case 'number':
154
+ // @ts-expect-error False positive
155
+ return Number(value);
156
+ case 'string':
157
+ // @ts-expect-error False positive
158
+ return value;
159
+ default:
160
+ // @ts-expect-error False positive
161
+ return (this.bigIntValue * BigInt(this.decimal || 8n)) / this.decimalMultiplier;
162
+ }
163
+ }
164
+
165
+ getBaseValue<T extends 'number' | 'string' | 'bigint'>(type: T): NumberPrimitivesType[T] {
166
+ const divisor = this.decimalMultiplier / toMultiplier(this.decimal || BaseDecimal.THOR);
167
+ const baseValue = this.bigIntValue / divisor;
168
+
169
+ switch (type) {
170
+ case 'number':
171
+ // @ts-expect-error False positive
172
+ return Number(baseValue);
173
+ case 'string':
174
+ // @ts-expect-error False positive
175
+ return baseValue.toString();
176
+ default:
177
+ // @ts-expect-error False positive
178
+ return baseValue;
179
+ }
180
+ }
181
+
182
+ getBigIntValue(value: InitialisationValueType, decimal?: number) {
102
183
  if (!decimal && typeof value === 'object') return value.bigIntValue;
103
184
 
104
- value = typeof value === 'object' ? value.value : value;
105
- return this.#toBigInt(this.#toSafeValue(value), decimal);
185
+ const stringValue = getStringValue(value);
186
+ const safeValue = this.#toSafeValue(stringValue);
187
+
188
+ if (safeValue === '0' || safeValue === 'undefined') return 0n;
189
+ return this.#toBigInt(safeValue, decimal);
106
190
  }
107
191
 
108
192
  formatBigIntToSafeValue(value: bigint, decimal?: number) {
@@ -113,16 +197,13 @@ export class BigIntArithmetics {
113
197
  );
114
198
  const isNegative = value < 0n;
115
199
 
116
- let valueString = value.toString().substring(isNegative ? 1 : 0);
117
-
200
+ const valueString = value.toString().substring(isNegative ? 1 : 0);
118
201
  const padLength = decimalToUseForConversion - (valueString.length - 1);
119
202
 
120
- if (padLength > 0) {
121
- valueString = '0'.repeat(padLength) + valueString;
122
- }
203
+ const parsedValueString = padLength > 0 ? '0'.repeat(padLength) + valueString : valueString;
123
204
 
124
- const decimalIndex = valueString.length - decimalToUseForConversion;
125
- let decimalString = valueString.slice(-decimalToUseForConversion);
205
+ const decimalIndex = parsedValueString.length - decimalToUseForConversion;
206
+ let decimalString = parsedValueString.slice(-decimalToUseForConversion);
126
207
 
127
208
  // Check if we need to round up
128
209
  if (parseInt(decimalString[bigIntDecimal]) >= 5) {
@@ -135,54 +216,90 @@ export class BigIntArithmetics {
135
216
  decimalString = decimalString.substring(0, bigIntDecimal);
136
217
  }
137
218
 
138
- return `${isNegative ? '-' : ''}${valueString.slice(0, decimalIndex)}.${decimalString}`.replace(
139
- /\.?0*$/,
140
- '',
141
- );
219
+ return `${isNegative ? '-' : ''}${parsedValueString.slice(
220
+ 0,
221
+ decimalIndex,
222
+ )}.${decimalString}`.replace(/\.?0*$/, '');
142
223
  }
143
224
 
144
- toSignificant(significantDigits?: number) {
145
- const value = this.value.split('.');
146
- const integer = value[0];
147
- const decimal = value[1];
225
+ toSignificant(significantDigits: number = 6) {
226
+ const [int, dec] = this.getValue('string').split('.');
227
+ const integer = int || '';
228
+ const decimal = dec || '';
229
+ const valueLength = parseInt(integer) ? integer.length + decimal.length : decimal.length;
230
+
231
+ if (valueLength <= significantDigits) {
232
+ return this.getValue('string');
233
+ }
234
+
235
+ if (integer.length >= significantDigits) {
236
+ return integer.slice(0, significantDigits).padEnd(integer.length, '0');
237
+ }
148
238
 
149
- if (decimal) {
150
- return `${integer}.${decimal.slice(0, significantDigits || this.decimal)}`.replace(
151
- /\.?0*$/,
152
- '',
239
+ if (parseInt(integer)) {
240
+ return `${integer}.${decimal.slice(0, significantDigits - integer.length)}`.padEnd(
241
+ valueLength - significantDigits,
242
+ '0',
153
243
  );
154
244
  }
155
245
 
156
- return integer;
246
+ const trimmedDecimal = parseInt(decimal);
247
+ const slicedDecimal = `${trimmedDecimal}`.slice(0, significantDigits);
248
+
249
+ return `0.${slicedDecimal.padStart(
250
+ decimal.length - `${trimmedDecimal}`.length + slicedDecimal.length,
251
+ '0',
252
+ )}`;
253
+ }
254
+
255
+ toFixed(fixedDigits: number = 6) {
256
+ const [int, dec] = this.getValue('string').split('.');
257
+ const integer = int || '';
258
+ const decimal = dec || '';
259
+
260
+ if (parseInt(integer)) {
261
+ return `${integer}.${decimal.slice(0, fixedDigits)}`.padEnd(fixedDigits, '0');
262
+ }
263
+
264
+ const trimmedDecimal = parseInt(decimal);
265
+ const slicedDecimal = `${trimmedDecimal}`.slice(0, fixedDigits);
266
+
267
+ return `0.${slicedDecimal.padStart(
268
+ decimal.length - `${trimmedDecimal}`.length + slicedDecimal.length,
269
+ '0',
270
+ )}`;
157
271
  }
158
272
 
159
- #arithmetics(method: ArithmeticMethod, ...args: (BigIntArithmetics | string | number)[]): this {
273
+ #arithmetics(method: 'add' | 'sub' | 'mul' | 'div', ...args: InitialisationValueType[]): this {
160
274
  const precisionDecimal = this.#retrievePrecisionDecimal(this, ...args);
161
275
  const precisionDecimalMultiplier = toMultiplier(precisionDecimal);
162
276
 
163
277
  const result = args.reduce(
164
- (acc, arg) => {
278
+ (acc: bigint, arg) => {
165
279
  const value = this.getBigIntValue(arg, precisionDecimal);
166
280
 
167
- if ('div' === method && value === 0n) throw new RangeError('Division by zero');
168
-
169
- /**
170
- * Normal arithmetic - add & sub => 200000000n +- 200000000n
171
- */
172
- if ('add' === method) return acc + value;
173
- if ('sub' === method) return acc - value;
174
-
175
- /**
176
- * Multiplication & division would end up with wrong result if we don't adjust the value
177
- * 200000000n * 200000000n => 40000000000000000n
178
- * 200000000n / 200000000n => 1n
179
- * So we do the following:
180
- * 200000000n * 200000000n = 40000000000000000n / 100000000n (decimals) => 400000000n
181
- * (200000000n * 100000000n (decimals)) / 200000000n => 100000000n
182
- */
183
- if ('mul' === method) return (acc * value) / precisionDecimalMultiplier;
184
- // 'div' === method
185
- return (acc * precisionDecimalMultiplier) / value;
281
+ switch (method) {
282
+ case 'add':
283
+ return acc + value;
284
+ case 'sub':
285
+ return acc - value;
286
+ /**
287
+ * Multiplication & division would end up with wrong result if we don't adjust the value
288
+ * 200000000n * 200000000n => 40000000000000000n
289
+ * 200000000n / 200000000n => 1n
290
+ * So we do the following:
291
+ * 200000000n * 200000000n = 40000000000000000n / 100000000n (decimals) => 400000000n
292
+ * (200000000n * 100000000n (decimals)) / 200000000n => 100000000n
293
+ */
294
+ case 'mul':
295
+ return (acc * value) / precisionDecimalMultiplier;
296
+ case 'div': {
297
+ if (value === 0n) throw new RangeError('Division by zero');
298
+ return (acc * precisionDecimalMultiplier) / value;
299
+ }
300
+ default:
301
+ return acc;
302
+ }
186
303
  },
187
304
  //normalize is to precision multiplier base
188
305
  (this.bigIntValue * precisionDecimalMultiplier) / this.decimalMultiplier,
@@ -194,16 +311,16 @@ export class BigIntArithmetics {
194
311
  value: result,
195
312
  });
196
313
 
197
- // @ts-expect-error - we know that the constructor is the same as the current class
314
+ // @ts-expect-error False positive
198
315
  return new this.constructor({ decimal: this.decimal, value, identifier: this.toString() });
199
316
  }
200
317
 
201
- #setValue(value: AllowedValueType, bigIntValue?: bigint) {
318
+ #setValue(value: InitialisationValueType) {
202
319
  const safeValue = this.#toSafeValue(value) || '0';
203
- this.bigIntValue = bigIntValue || this.#toBigInt(safeValue);
320
+ this.bigIntValue = this.#toBigInt(safeValue);
204
321
  }
205
322
 
206
- #retrievePrecisionDecimal(...args: (BigIntArithmetics | AllowedValueType)[]) {
323
+ #retrievePrecisionDecimal(...args: InitialisationValueType[]) {
207
324
  const decimals = args
208
325
  .map((arg) =>
209
326
  typeof arg === 'object'
@@ -217,19 +334,19 @@ export class BigIntArithmetics {
217
334
  #toBigInt(value: string, decimal?: number) {
218
335
  const multiplier = decimal ? toMultiplier(decimal) : this.decimalMultiplier;
219
336
  const padDecimal = decimalFromMultiplier(multiplier);
220
- const [integerPart, decimalPart = ''] = value.split('.');
337
+ const [integerPart = '', decimalPart = ''] = value.split('.');
221
338
 
222
339
  return BigInt(`${integerPart}${decimalPart.padEnd(padDecimal, '0')}`);
223
340
  }
224
341
 
225
- #toSafeValue(value: AllowedValueType) {
342
+ #toSafeValue(value: InitialisationValueType) {
226
343
  const parsedValue =
227
344
  typeof value === 'number'
228
345
  ? Number(value).toLocaleString('fullwide', {
229
346
  useGrouping: false,
230
347
  maximumFractionDigits: 20,
231
348
  })
232
- : value;
349
+ : getStringValue(value);
233
350
 
234
351
  const splitValue = `${parsedValue}`.replaceAll(',', '.').split('.');
235
352
 
@@ -242,18 +359,12 @@ export class BigIntArithmetics {
242
359
  const decimals = value.split('.')[1]?.length || 0;
243
360
  return Math.max(decimals, DEFAULT_DECIMAL);
244
361
  }
362
+ }
245
363
 
246
- #getBaseValue<T extends 'number' | 'string' | 'bigint'>(type: T) {
247
- const divisor = this.decimalMultiplier / toMultiplier(this.decimal || 0);
248
- const baseValue = this.bigIntValue / divisor;
249
-
250
- switch (type) {
251
- case 'number':
252
- return Number(baseValue);
253
- case 'string':
254
- return baseValue.toString();
255
- default:
256
- return baseValue;
257
- }
258
- }
364
+ function getStringValue(value: SKBigIntParams) {
365
+ return typeof value === 'object'
366
+ ? 'getValue' in value
367
+ ? value.getValue('string')
368
+ : value.value
369
+ : value;
259
370
  }
@@ -6,8 +6,4 @@ export class SwapKitNumber extends BigIntArithmetics {
6
6
  eq(value: SwapKitValueType) {
7
7
  return this.eqValue(value);
8
8
  }
9
-
10
- toString() {
11
- return this.value;
12
- }
13
9
  }
@@ -1,40 +0,0 @@
1
- // THORChain base amount is 1e8
2
- export const DEFAULT_DECIMAL = 8;
3
-
4
- export const formatBigIntToSafeValue = ({
5
- value,
6
- bigIntDecimal = DEFAULT_DECIMAL,
7
- decimal = DEFAULT_DECIMAL,
8
- }: {
9
- value: bigint;
10
- bigIntDecimal?: number;
11
- decimal?: number;
12
- }) => {
13
- const isNegative = value < 0n;
14
- let valueString = value.toString().substring(isNegative ? 1 : 0);
15
-
16
- const padLength = decimal - (valueString.length - 1);
17
-
18
- if (padLength > 0) {
19
- valueString = '0'.repeat(padLength) + valueString;
20
- }
21
-
22
- const decimalIndex = valueString.length - decimal;
23
- let decimalString = valueString.slice(-decimal);
24
-
25
- // Check if we need to round up
26
- if (parseInt(decimalString[bigIntDecimal]) >= 5) {
27
- // Increment the last decimal place and slice off the rest
28
- decimalString = `${decimalString.substring(0, bigIntDecimal - 1)}${(
29
- parseInt(decimalString[bigIntDecimal - 1]) + 1
30
- ).toString()}`;
31
- } else {
32
- // Just slice off the extra digits
33
- decimalString = decimalString.substring(0, bigIntDecimal);
34
- }
35
-
36
- return `${isNegative ? '-' : ''}${valueString.slice(0, decimalIndex)}.${decimalString}`.replace(
37
- /\.?0*$/,
38
- '',
39
- );
40
- };