@swapkit/helpers 1.0.0-rc.5 → 1.0.0-rc.50

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.
@@ -17,10 +17,18 @@ import type { CommonAssetString } from '../helpers/asset.ts';
17
17
  import { getAssetType, getCommonAssetInfo, getDecimal, isGasAsset } from '../helpers/asset.ts';
18
18
  import { validateIdentifier } from '../helpers/validators.ts';
19
19
 
20
- import { BigIntArithmetics } from './bigIntArithmetics.ts';
20
+ import type { NumberPrimitives } from './bigIntArithmetics.ts';
21
+ import { BigIntArithmetics, formatBigIntToSafeValue } from './bigIntArithmetics.ts';
21
22
  import type { SwapKitValueType } from './swapKitNumber.ts';
22
23
 
23
- type AssetValueParams = { decimal: number; value: SwapKitValueType } & (
24
+ type TokenTax = { buy: number; sell: number };
25
+
26
+ const safeValue = (value: NumberPrimitives, decimal: number) =>
27
+ typeof value === 'bigint'
28
+ ? formatBigIntToSafeValue({ value, bigIntDecimal: decimal, decimal })
29
+ : value;
30
+
31
+ type AssetValueParams = { decimal: number; value: SwapKitValueType; tax?: TokenTax } & (
24
32
  | { chain: Chain; symbol: string }
25
33
  | { identifier: string }
26
34
  );
@@ -40,7 +48,9 @@ type TokenNames =
40
48
  | (typeof WoofiList)['tokens'][number]['identifier']
41
49
  | (typeof UniswapList)['tokens'][number]['identifier'];
42
50
 
43
- let staticTokensMap: Map<TokenNames, { decimal: number; identifier: string }> | undefined;
51
+ let staticTokensMap:
52
+ | Map<TokenNames, { tax?: TokenTax; decimal: number; identifier: string }>
53
+ | undefined;
44
54
 
45
55
  const getStaticToken = (identifier: TokenNames) => {
46
56
  if (!staticTokensMap) {
@@ -51,31 +61,35 @@ const getStaticToken = (identifier: TokenNames) => {
51
61
  return tokenInfo || { decimal: BaseDecimal.THOR, identifier: '' };
52
62
  };
53
63
 
54
- const createAssetValue = async (assetString: string, value: number | string = 0) => {
64
+ const createAssetValue = async (assetString: string, value: NumberPrimitives = 0) => {
55
65
  validateIdentifier(assetString);
56
66
 
57
67
  const decimal = await getDecimal(getAssetInfo(assetString));
58
- return new AssetValue({ decimal, value, identifier: assetString });
68
+ const parsedValue = safeValue(value, decimal);
69
+
70
+ return new AssetValue({ decimal, value: parsedValue, identifier: assetString });
59
71
  };
60
72
 
61
73
  export class AssetValue extends BigIntArithmetics {
62
74
  address?: string;
63
75
  chain: Chain;
64
- isSynthetic = false;
65
76
  isGasAsset = false;
77
+ isSynthetic = false;
66
78
  symbol: string;
79
+ tax?: TokenTax;
67
80
  ticker: string;
68
81
  type: ReturnType<typeof getAssetType>;
69
82
 
70
83
  constructor(params: AssetValueParams) {
84
+ const identifier =
85
+ 'identifier' in params ? params.identifier : `${params.chain}.${params.symbol}`;
86
+
71
87
  super(
72
88
  params.value instanceof BigIntArithmetics
73
89
  ? params.value
74
90
  : { decimal: params.decimal, value: params.value },
75
91
  );
76
92
 
77
- const identifier =
78
- 'identifier' in params ? params.identifier : `${params.chain}.${params.symbol}`;
79
93
  const assetInfo = getAssetInfo(identifier);
80
94
 
81
95
  this.type = getAssetType(assetInfo);
@@ -85,94 +99,94 @@ export class AssetValue extends BigIntArithmetics {
85
99
  this.address = assetInfo.address;
86
100
  this.isSynthetic = assetInfo.isSynthetic;
87
101
  this.isGasAsset = assetInfo.isGasAsset;
88
- }
89
102
 
90
- get assetValue() {
91
- return `${this.getValue('string')} ${this.ticker}`;
103
+ this.tax = params.tax;
92
104
  }
93
105
 
94
106
  toString() {
95
- return `${this.chain}.${this.symbol}`;
107
+ return this.isSynthetic ? this.symbol : `${this.chain}.${this.symbol}`;
108
+ }
109
+
110
+ toUrl() {
111
+ return this.isSynthetic ? `${this.chain}.${this.symbol.replace('/', '.')}` : this.toString();
96
112
  }
97
113
 
98
114
  eq({ chain, symbol }: { chain: Chain; symbol: string }) {
99
115
  return this.chain === chain && this.symbol === symbol;
100
116
  }
101
117
 
102
- static async fromString(assetString: string, value: number | string = 0) {
118
+ // THOR.RUNE
119
+ // THOR.ETH.ETH
120
+ // ETH.THOR-0x1234567890
121
+ static fromUrl(urlAsset: string, value: NumberPrimitives = 0) {
122
+ const [chain, ticker, symbol] = urlAsset.split('.');
123
+ if (!chain || !ticker) throw new Error('Invalid asset url');
124
+
125
+ const assetString =
126
+ chain === Chain.THORChain && symbol ? `${chain}.${ticker}/${symbol}` : urlAsset;
127
+
103
128
  return createAssetValue(assetString, value);
104
129
  }
105
130
 
106
- static fromStringSync(assetString: string, value: number | string = 0) {
107
- const { decimal, identifier: tokenIdentifier } = getStaticToken(
108
- assetString as unknown as TokenNames,
109
- );
131
+ static fromString(assetString: string, value: NumberPrimitives = 0) {
132
+ return createAssetValue(assetString, value);
133
+ }
134
+
135
+ static fromStringSync(assetString: string, value: NumberPrimitives = 0) {
136
+ const { isSynthetic } = getAssetInfo(assetString);
137
+ const {
138
+ tax,
139
+ decimal,
140
+ identifier: tokenIdentifier,
141
+ } = getStaticToken(assetString as unknown as TokenNames);
142
+
143
+ const parsedValue = safeValue(value, decimal);
144
+
145
+ const asset = tokenIdentifier
146
+ ? new AssetValue({ tax, decimal, identifier: tokenIdentifier, value: parsedValue })
147
+ : isSynthetic
148
+ ? new AssetValue({ tax, decimal: 8, identifier: assetString, value: parsedValue })
149
+ : undefined;
110
150
 
111
- return tokenIdentifier
112
- ? new AssetValue({ decimal, identifier: tokenIdentifier, value })
113
- : undefined;
151
+ return asset;
114
152
  }
115
153
 
116
- static async fromIdentifier(
154
+ static fromIdentifier(
117
155
  assetString: `${Chain}.${string}` | `${Chain}/${string}` | `${Chain}.${string}-${string}`,
118
- value: number | string = 0,
156
+ value: NumberPrimitives = 0,
119
157
  ) {
120
158
  return createAssetValue(assetString, value);
121
159
  }
122
160
 
123
- static fromIdentifierSync(identifier: TokenNames, value: number | string = 0) {
161
+ static fromIdentifierSync(identifier: TokenNames, value: NumberPrimitives = 0) {
124
162
  const { decimal, identifier: tokenIdentifier } = getStaticToken(identifier);
163
+ const parsedValue = safeValue(value, decimal);
125
164
 
126
- return new AssetValue({ decimal, identifier: tokenIdentifier, value });
165
+ return new AssetValue({ decimal, identifier: tokenIdentifier, value: parsedValue });
127
166
  }
128
167
 
129
- static fromChainOrSignature(assetString: CommonAssetString, value: number | string = 0) {
168
+ static fromChainOrSignature(assetString: CommonAssetString, value: NumberPrimitives = 0) {
130
169
  const { decimal, identifier } = getCommonAssetInfo(assetString);
170
+ const parsedValue = safeValue(value, decimal);
131
171
 
132
- return new AssetValue({ value, decimal, identifier });
133
- }
134
-
135
- static async fromTCQuote(identifier: TCTokenNames, value: number | string = 0) {
136
- const decimal = await getDecimal(getAssetInfo(identifier));
137
- const shiftedValue = this.shiftDecimals({ value, from: BaseDecimal.THOR, to: decimal });
138
-
139
- return new AssetValue({ value: shiftedValue, identifier, decimal });
140
- }
141
-
142
- static fromTCQuoteStatic(identifier: TCTokenNames, value: number | string = 0) {
143
- const tokenInfo = getStaticToken(identifier);
144
- const shiftedValue = this.shiftDecimals({
145
- value,
146
- from: BaseDecimal.THOR,
147
- to: tokenInfo.decimal,
148
- });
149
-
150
- return new AssetValue({ ...tokenInfo, value: shiftedValue });
172
+ return new AssetValue({ value: parsedValue, decimal, identifier });
151
173
  }
152
174
 
153
- static async loadStaticAssets() {
175
+ static loadStaticAssets() {
154
176
  return new Promise<{ ok: true } | { ok: false; message: string; error: any }>(
155
177
  async (resolve, reject) => {
156
178
  try {
157
- const {
158
- // Omit ThorchainList from import to avoid decimals conflict (TC uses 8 for all)
159
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
160
- ThorchainList: _ThorchainList,
161
- NativeList,
162
- ...tokensPackage
163
- } = await import('@swapkit/tokens');
164
- const tokensMap = [NativeList, ...Object.values(tokensPackage)].reduce(
165
- (acc, { tokens }) => {
166
- tokens.forEach(({ identifier, chain, ...rest }) => {
167
- const decimal = 'decimals' in rest ? rest.decimals : BaseDecimal[chain as Chain];
168
-
169
- acc.set(identifier as TokenNames, { identifier, decimal });
179
+ const tokenPackages = await import('@swapkit/tokens');
180
+ const tokensMap = Object.values(tokenPackages).reduce((acc, tokenList) => {
181
+ tokenList?.tokens?.forEach(({ identifier, chain, ...rest }) => {
182
+ acc.set(identifier as TokenNames, {
183
+ identifier,
184
+ decimal: 'decimals' in rest ? rest.decimals : BaseDecimal[chain as Chain],
170
185
  });
186
+ });
171
187
 
172
- return acc;
173
- },
174
- new Map<TokenNames, { decimal: number; identifier: string }>(),
175
- );
188
+ return acc;
189
+ }, new Map<TokenNames, { decimal: number; identifier: string }>());
176
190
 
177
191
  staticTokensMap = tokensMap;
178
192
 
@@ -198,39 +212,41 @@ export const getMinAmountByChain = (chain: Chain) => {
198
212
  case Chain.Bitcoin:
199
213
  case Chain.Litecoin:
200
214
  case Chain.BitcoinCash:
201
- return asset.add(10001);
215
+ return asset.set(0.00010001);
202
216
 
203
217
  case Chain.Dogecoin:
204
- return asset.add(100000001);
218
+ return asset.set(1.00000001);
205
219
 
206
220
  case Chain.Avalanche:
207
221
  case Chain.Ethereum:
208
- return asset.add(10 * 10 ** 9);
222
+ return asset.set(0.00000001);
209
223
 
210
224
  case Chain.THORChain:
211
225
  case Chain.Maya:
212
- return asset.add(0);
226
+ return asset.set(0);
213
227
 
214
228
  default:
215
- return asset.add(1);
229
+ return asset.set(0.00000001);
216
230
  }
217
231
  };
218
232
 
219
233
  const getAssetInfo = (identifier: string) => {
220
234
  const isSynthetic = identifier.slice(0, 14).includes('/');
221
- const adjustedIdentifier = identifier.includes('.')
222
- ? identifier
223
- : `${Chain.THORChain}.${identifier}`;
235
+ const [synthChain, synthSymbol] = identifier.split('.').pop()!.split('/');
236
+ const adjustedIdentifier =
237
+ identifier.includes('.') && !isSynthetic ? identifier : `${Chain.THORChain}.${synthSymbol}`;
224
238
 
225
239
  const [chain, symbol] = adjustedIdentifier.split('.') as [Chain, string];
226
- const [ticker, address] = symbol.split('-') as [string, string?];
240
+ const [ticker, address] = (isSynthetic ? synthSymbol : symbol).split('-') as [string, string?];
227
241
 
228
242
  return {
229
243
  address: address?.toLowerCase(),
230
244
  chain,
231
245
  isGasAsset: isGasAsset({ chain, symbol }),
232
246
  isSynthetic,
233
- symbol: address ? `${ticker}-${address?.toLowerCase() ?? ''}` : symbol,
234
- ticker: isSynthetic ? symbol : ticker,
247
+ symbol:
248
+ (isSynthetic ? `${synthChain}/` : '') +
249
+ (address ? `${ticker}-${address?.toLowerCase() ?? ''}` : symbol),
250
+ ticker,
235
251
  };
236
252
  };
@@ -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);
@@ -69,38 +72,30 @@ export class BigIntArithmetics {
69
72
  from,
70
73
  to,
71
74
  }: {
72
- value: InitialisationValueType;
75
+ value: InstanceType<typeof SwapKitNumber>;
73
76
  from: number;
74
77
  to: number;
75
78
  }) {
76
- return BigIntArithmetics.fromBigInt(
77
- (new BigIntArithmetics(value).bigIntValue * toMultiplier(to)) / toMultiplier(from),
79
+ return this.fromBigInt(
80
+ (value.getBaseValue('bigint') * toMultiplier(to)) / toMultiplier(from),
78
81
  to,
79
82
  );
80
83
  }
81
84
 
82
85
  constructor(params: SKBigIntParams) {
83
86
  const value = getStringValue(params);
84
- this.decimal = typeof params === 'object' ? params.decimal : undefined;
87
+ const isComplex = typeof params === 'object';
88
+ this.decimal = isComplex ? params.decimal : undefined;
85
89
 
86
90
  // 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
- );
91
+ this.decimalMultiplier =
92
+ isComplex && 'decimalMultiplier' in params
93
+ ? params.decimalMultiplier
94
+ : toMultiplier(Math.max(getFloatDecimals(toSafeValue(value)), this.decimal || 0));
90
95
  this.#setValue(value);
91
96
  }
92
97
 
93
- get baseValue() {
94
- return this.getBaseValue('string') as string;
95
- }
96
- get baseValueNumber() {
97
- return this.getBaseValue('number') as number;
98
- }
99
- get baseValueBigInt() {
100
- return this.getBaseValue('bigint') as bigint;
101
- }
102
-
103
- set(value: SKBigIntParams) {
98
+ set(value: SKBigIntParams): this {
104
99
  // @ts-expect-error False positive
105
100
  return new this.constructor({ decimal: this.decimal, value, identifier: this.toString() });
106
101
  }
@@ -117,22 +112,23 @@ export class BigIntArithmetics {
117
112
  return this.#arithmetics('div', ...args);
118
113
  }
119
114
  gt(value: InitialisationValueType) {
120
- return this.bigIntValue > this.getBigIntValue(value);
115
+ return this.#comparison('gt', value);
121
116
  }
122
117
  gte(value: InitialisationValueType) {
123
- return this.bigIntValue >= this.getBigIntValue(value);
118
+ return this.#comparison('gte', value);
124
119
  }
125
120
  lt(value: InitialisationValueType) {
126
- return this.bigIntValue < this.getBigIntValue(value);
121
+ return this.#comparison('lt', value);
127
122
  }
128
123
  lte(value: InitialisationValueType) {
129
- return this.bigIntValue <= this.getBigIntValue(value);
124
+ return this.#comparison('lte', value);
130
125
  }
131
126
  eqValue(value: InitialisationValueType) {
132
- return this.bigIntValue === this.getBigIntValue(value);
127
+ return this.#comparison('eqValue', value);
133
128
  }
134
129
 
135
- getValue<T extends 'number' | 'string' | 'bigint'>(type: T): NumberPrimitivesType[T] {
130
+ // @ts-expect-error False positive
131
+ getValue<T extends AllowedNumberTypes>(type: T): NumberPrimitivesType[T] {
136
132
  const value = this.formatBigIntToSafeValue(
137
133
  this.bigIntValue,
138
134
  this.decimal || decimalFromMultiplier(this.decimalMultiplier),
@@ -140,38 +136,125 @@ export class BigIntArithmetics {
140
136
 
141
137
  switch (type) {
142
138
  case 'number':
143
- // @ts-expect-error False positive
144
- return Number(value);
139
+ return Number(value) as NumberPrimitivesType[T];
145
140
  case 'string':
146
- // @ts-expect-error False positive
147
- return value;
148
- default:
149
- // @ts-expect-error False positive
150
- return this.bigIntValue;
141
+ return value as NumberPrimitivesType[T];
142
+ case 'bigint':
143
+ return ((this.bigIntValue * 10n ** BigInt(this.decimal || 8n)) /
144
+ this.decimalMultiplier) as NumberPrimitivesType[T];
151
145
  }
152
146
  }
153
147
 
154
- getBaseValue<T extends 'number' | 'string' | 'bigint'>(type: T): NumberPrimitivesType[T] {
155
- const divisor = this.decimalMultiplier / toMultiplier(this.decimal || 0);
148
+ // @ts-expect-error
149
+ getBaseValue<T extends AllowedNumberTypes>(type: T): NumberPrimitivesType[T] {
150
+ const divisor = this.decimalMultiplier / toMultiplier(this.decimal || BaseDecimal.THOR);
156
151
  const baseValue = this.bigIntValue / divisor;
157
152
 
158
153
  switch (type) {
159
154
  case 'number':
160
- // @ts-expect-error False positive
161
- return Number(baseValue);
155
+ return Number(baseValue) as NumberPrimitivesType[T];
162
156
  case 'string':
163
- // @ts-expect-error False positive
164
- return baseValue.toString();
165
- default:
166
- // @ts-expect-error False positive
167
- return this.bigIntValue;
157
+ return baseValue.toString() as NumberPrimitivesType[T];
158
+ case 'bigint':
159
+ return baseValue as NumberPrimitivesType[T];
168
160
  }
169
161
  }
170
162
 
171
163
  getBigIntValue(value: InitialisationValueType, decimal?: number) {
172
164
  if (!decimal && typeof value === 'object') return value.bigIntValue;
173
165
 
174
- return this.#toBigInt(this.#toSafeValue(getStringValue(value)), decimal);
166
+ const stringValue = getStringValue(value);
167
+ const safeValue = toSafeValue(stringValue);
168
+
169
+ if (safeValue === '0' || safeValue === 'undefined') return 0n;
170
+ return this.#toBigInt(safeValue, decimal);
171
+ }
172
+
173
+ toSignificant(significantDigits: number = 6) {
174
+ const [int, dec] = this.getValue('string').split('.');
175
+ const integer = int || '';
176
+ const decimal = dec || '';
177
+ const valueLength = parseInt(integer) ? integer.length + decimal.length : decimal.length;
178
+
179
+ if (valueLength <= significantDigits) {
180
+ return this.getValue('string');
181
+ }
182
+
183
+ if (integer.length >= significantDigits) {
184
+ return integer.slice(0, significantDigits).padEnd(integer.length, '0');
185
+ }
186
+
187
+ if (parseInt(integer)) {
188
+ return `${integer}.${decimal.slice(0, significantDigits - integer.length)}`.padEnd(
189
+ significantDigits - integer.length,
190
+ '0',
191
+ );
192
+ }
193
+
194
+ const trimmedDecimal = parseInt(decimal);
195
+ const slicedDecimal = `${trimmedDecimal}`.slice(0, significantDigits);
196
+
197
+ return `0.${slicedDecimal.padStart(
198
+ decimal.length - `${trimmedDecimal}`.length + slicedDecimal.length,
199
+ '0',
200
+ )}`;
201
+ }
202
+
203
+ toFixed(fixedDigits: number = 6) {
204
+ const [int, dec] = this.getValue('string').split('.');
205
+ const integer = int || '';
206
+ const decimal = dec || '';
207
+
208
+ if (parseInt(integer)) {
209
+ return `${integer}.${decimal.slice(0, fixedDigits)}`.padEnd(fixedDigits, '0');
210
+ }
211
+
212
+ const trimmedDecimal = parseInt(decimal);
213
+ const slicedDecimal = `${trimmedDecimal}`.slice(0, fixedDigits);
214
+
215
+ return `0.${slicedDecimal.padStart(
216
+ decimal.length - `${trimmedDecimal}`.length + slicedDecimal.length,
217
+ '0',
218
+ )}`;
219
+ }
220
+
221
+ toAbbreviation(digits = 2) {
222
+ const value = this.getValue('number');
223
+ const abbreviations = ['', 'K', 'M', 'B', 'T', 'Q', 'Qi', 'S'];
224
+ const tier = Math.floor(Math.log10(Math.abs(value)) / 3);
225
+ const suffix = abbreviations[tier];
226
+
227
+ if (!suffix) return this.getValue('string');
228
+
229
+ const scale = 10 ** (tier * 3);
230
+ const scaled = value / scale;
231
+
232
+ return `${scaled.toFixed(digits)}${suffix}`;
233
+ }
234
+
235
+ toCurrency(
236
+ currency = '$',
237
+ {
238
+ currencyPosition = 'start',
239
+ decimal = 2,
240
+ decimalSeparator = '.',
241
+ thousandSeparator = ',',
242
+ } = {},
243
+ ) {
244
+ const value = this.getValue('number');
245
+ const [int, dec = ''] = value.toFixed(6).split('.');
246
+ const integer = int.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
247
+
248
+ const parsedValue =
249
+ !int && !dec
250
+ ? '0.00'
251
+ : int === '0'
252
+ ? `${parseFloat(`0.${dec}`)}`.replace('.', decimalSeparator)
253
+ : `${integer}${parseInt(dec) ? `${decimalSeparator}${dec.slice(0, decimal)}` : ''}`;
254
+
255
+ return `${currencyPosition === 'start' ? currency : ''}${parsedValue}${
256
+ currencyPosition === 'end' ? currency : ''
257
+ }`;
175
258
  }
176
259
 
177
260
  formatBigIntToSafeValue(value: bigint, decimal?: number) {
@@ -207,43 +290,14 @@ export class BigIntArithmetics {
207
290
  )}.${decimalString}`.replace(/\.?0*$/, '');
208
291
  }
209
292
 
210
- toSignificant(significantDigits: number = 6) {
211
- const [int, dec] = this.getValue('string').split('.');
212
- const integer = int || '';
213
- const decimal = dec || '';
214
- const valueLength = parseInt(integer) ? integer.length + decimal.length : decimal.length;
215
-
216
- if (valueLength <= significantDigits) {
217
- return this.getValue('string');
218
- }
219
-
220
- if (integer.length >= significantDigits) {
221
- return integer.slice(0, significantDigits).padEnd(integer.length, '0');
222
- }
223
-
224
- if (parseInt(integer)) {
225
- return `${integer}.${decimal.slice(0, significantDigits - integer.length)}`.padEnd(
226
- valueLength - significantDigits,
227
- '0',
228
- );
229
- }
230
-
231
- const trimmedDecimal = parseInt(decimal);
232
- const slicedDecimal = `${trimmedDecimal}`.slice(0, significantDigits);
233
-
234
- return `0.${slicedDecimal.padStart(
235
- decimal.length - `${trimmedDecimal}`.length + slicedDecimal.length,
236
- '0',
237
- )}`;
238
- }
239
-
240
293
  #arithmetics(method: 'add' | 'sub' | 'mul' | 'div', ...args: InitialisationValueType[]): this {
241
294
  const precisionDecimal = this.#retrievePrecisionDecimal(this, ...args);
242
- const precisionDecimalMultiplier = toMultiplier(precisionDecimal);
295
+ const decimal = Math.max(precisionDecimal, decimalFromMultiplier(this.decimalMultiplier));
296
+ const precisionDecimalMultiplier = toMultiplier(decimal);
243
297
 
244
298
  const result = args.reduce(
245
299
  (acc: bigint, arg) => {
246
- const value = this.getBigIntValue(arg, precisionDecimal);
300
+ const value = this.getBigIntValue(arg, decimal);
247
301
 
248
302
  switch (method) {
249
303
  case 'add':
@@ -273,65 +327,92 @@ export class BigIntArithmetics {
273
327
  );
274
328
 
275
329
  const value = formatBigIntToSafeValue({
276
- bigIntDecimal: precisionDecimal,
277
- decimal: Math.max(precisionDecimal, decimalFromMultiplier(this.decimalMultiplier)),
330
+ bigIntDecimal: decimal,
331
+ decimal,
278
332
  value: result,
279
333
  });
280
334
 
281
335
  // @ts-expect-error False positive
282
- return new this.constructor({ decimal: this.decimal, value, identifier: this.toString() });
336
+ return new this.constructor({
337
+ decimalMultiplier: toMultiplier(decimal),
338
+ decimal: this.decimal,
339
+ value,
340
+ identifier: this.toString(),
341
+ });
342
+ }
343
+
344
+ #comparison(method: 'gt' | 'gte' | 'lt' | 'lte' | 'eqValue', ...args: InitialisationValueType[]) {
345
+ const decimal = this.#retrievePrecisionDecimal(this, ...args);
346
+ const value = this.getBigIntValue(args[0], decimal);
347
+ const compareToValue = this.getBigIntValue(this, decimal);
348
+
349
+ switch (method) {
350
+ case 'gt':
351
+ return compareToValue > value;
352
+ case 'gte':
353
+ return compareToValue >= value;
354
+ case 'lt':
355
+ return compareToValue < value;
356
+ case 'lte':
357
+ return compareToValue <= value;
358
+ case 'eqValue':
359
+ return compareToValue === value;
360
+ }
283
361
  }
284
362
 
285
363
  #setValue(value: InitialisationValueType) {
286
- const safeValue = this.#toSafeValue(value) || '0';
364
+ const safeValue = toSafeValue(value) || '0';
287
365
  this.bigIntValue = this.#toBigInt(safeValue);
288
366
  }
289
367
 
290
368
  #retrievePrecisionDecimal(...args: InitialisationValueType[]) {
291
369
  const decimals = args
292
- .map((arg) =>
293
- typeof arg === 'object'
370
+ .map((arg) => {
371
+ const isObject = typeof arg === 'object';
372
+ const value = isObject
294
373
  ? arg.decimal || decimalFromMultiplier(arg.decimalMultiplier)
295
- : this.#getFloatDecimals(this.#toSafeValue(arg)),
296
- )
374
+ : getFloatDecimals(toSafeValue(arg));
375
+
376
+ return value;
377
+ })
297
378
  .filter(Boolean) as number[];
379
+
298
380
  return Math.max(...decimals, DEFAULT_DECIMAL);
299
381
  }
300
382
 
301
383
  #toBigInt(value: string, decimal?: number) {
302
384
  const multiplier = decimal ? toMultiplier(decimal) : this.decimalMultiplier;
303
385
  const padDecimal = decimalFromMultiplier(multiplier);
304
- const [integerPart, decimalPart = ''] = value.split('.');
386
+ const [integerPart = '', decimalPart = ''] = value.split('.');
305
387
 
306
388
  return BigInt(`${integerPart}${decimalPart.padEnd(padDecimal, '0')}`);
307
389
  }
390
+ }
308
391
 
309
- #toSafeValue(value: InitialisationValueType) {
310
- const parsedValue =
311
- typeof value === 'number'
312
- ? Number(value).toLocaleString('fullwide', {
313
- useGrouping: false,
314
- maximumFractionDigits: 20,
315
- })
316
- : getStringValue(value);
317
-
318
- const splitValue = `${parsedValue}`.replaceAll(',', '.').split('.');
319
-
320
- return splitValue.length > 1
321
- ? `${splitValue.slice(0, -1).join('')}.${splitValue.at(-1)}`
322
- : splitValue[0];
323
- }
392
+ const numberFormatter = Intl.NumberFormat('fullwide', {
393
+ useGrouping: false,
394
+ maximumFractionDigits: 20,
395
+ });
324
396
 
325
- #getFloatDecimals(value: string) {
326
- const decimals = value.split('.')[1]?.length || 0;
327
- return Math.max(decimals, DEFAULT_DECIMAL);
328
- }
397
+ function toSafeValue(value: InitialisationValueType) {
398
+ const parsedValue =
399
+ typeof value === 'number' ? numberFormatter.format(value) : getStringValue(value);
400
+ const splitValue = `${parsedValue}`.replaceAll(',', '.').split('.');
401
+
402
+ return splitValue.length > 1
403
+ ? `${splitValue.slice(0, -1).join('')}.${splitValue.at(-1)}`
404
+ : splitValue[0];
405
+ }
406
+
407
+ function getFloatDecimals(value: string) {
408
+ const decimals = value.split('.')[1]?.length || 0;
409
+ return Math.max(decimals, DEFAULT_DECIMAL);
329
410
  }
330
411
 
331
- function getStringValue(value: SKBigIntParams) {
332
- return typeof value === 'object'
333
- ? 'getValue' in value
334
- ? value.getValue('string')
335
- : value.value
336
- : value;
412
+ function getStringValue(param: SKBigIntParams) {
413
+ return typeof param === 'object'
414
+ ? 'getValue' in param
415
+ ? param.getValue('string')
416
+ : param.value
417
+ : param;
337
418
  }