@swapkit/helpers 1.0.0-rc.5 → 1.0.0-rc.51
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.
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +51 -24
- package/dist/index.es.js +853 -453
- package/dist/index.es.js.map +1 -0
- package/package.json +12 -9
- package/src/helpers/asset.ts +46 -15
- package/src/helpers/liquidity.ts +12 -10
- package/src/helpers/memo.ts +15 -3
- package/src/helpers/others.ts +0 -48
- package/src/helpers/request.ts +15 -0
- package/src/index.ts +1 -0
- package/src/modules/__tests__/assetValue.test.ts +117 -33
- package/src/modules/__tests__/swapKitNumber.test.ts +174 -48
- package/src/modules/assetValue.ts +89 -73
- package/src/modules/bigIntArithmetics.ts +189 -108
- package/src/modules/swapKitError.ts +2 -1
- package/src/modules/swapKitNumber.ts +8 -1
|
@@ -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 {
|
|
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
|
|
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:
|
|
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:
|
|
64
|
+
const createAssetValue = async (assetString: string, value: NumberPrimitives = 0) => {
|
|
55
65
|
validateIdentifier(assetString);
|
|
56
66
|
|
|
57
67
|
const decimal = await getDecimal(getAssetInfo(assetString));
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
107
|
-
|
|
108
|
-
|
|
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
|
|
112
|
-
? new AssetValue({ decimal, identifier: tokenIdentifier, value })
|
|
113
|
-
: undefined;
|
|
151
|
+
return asset;
|
|
114
152
|
}
|
|
115
153
|
|
|
116
|
-
static
|
|
154
|
+
static fromIdentifier(
|
|
117
155
|
assetString: `${Chain}.${string}` | `${Chain}/${string}` | `${Chain}.${string}-${string}`,
|
|
118
|
-
value:
|
|
156
|
+
value: NumberPrimitives = 0,
|
|
119
157
|
) {
|
|
120
158
|
return createAssetValue(assetString, value);
|
|
121
159
|
}
|
|
122
160
|
|
|
123
|
-
static fromIdentifierSync(identifier: TokenNames, value:
|
|
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:
|
|
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
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
|
|
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.
|
|
215
|
+
return asset.set(0.00010001);
|
|
202
216
|
|
|
203
217
|
case Chain.Dogecoin:
|
|
204
|
-
return asset.
|
|
218
|
+
return asset.set(1.00000001);
|
|
205
219
|
|
|
206
220
|
case Chain.Avalanche:
|
|
207
221
|
case Chain.Ethereum:
|
|
208
|
-
return asset.
|
|
222
|
+
return asset.set(0.00000001);
|
|
209
223
|
|
|
210
224
|
case Chain.THORChain:
|
|
211
225
|
case Chain.Maya:
|
|
212
|
-
return asset.
|
|
226
|
+
return asset.set(0);
|
|
213
227
|
|
|
214
228
|
default:
|
|
215
|
-
return asset.
|
|
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
|
|
222
|
-
|
|
223
|
-
: `${Chain.THORChain}.${
|
|
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:
|
|
234
|
-
|
|
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:
|
|
75
|
+
value: InstanceType<typeof SwapKitNumber>;
|
|
73
76
|
from: number;
|
|
74
77
|
to: number;
|
|
75
78
|
}) {
|
|
76
|
-
return
|
|
77
|
-
(
|
|
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
|
-
|
|
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 =
|
|
88
|
-
|
|
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
|
-
|
|
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
|
|
115
|
+
return this.#comparison('gt', value);
|
|
121
116
|
}
|
|
122
117
|
gte(value: InitialisationValueType) {
|
|
123
|
-
return this
|
|
118
|
+
return this.#comparison('gte', value);
|
|
124
119
|
}
|
|
125
120
|
lt(value: InitialisationValueType) {
|
|
126
|
-
return this
|
|
121
|
+
return this.#comparison('lt', value);
|
|
127
122
|
}
|
|
128
123
|
lte(value: InitialisationValueType) {
|
|
129
|
-
return this
|
|
124
|
+
return this.#comparison('lte', value);
|
|
130
125
|
}
|
|
131
126
|
eqValue(value: InitialisationValueType) {
|
|
132
|
-
return this
|
|
127
|
+
return this.#comparison('eqValue', value);
|
|
133
128
|
}
|
|
134
129
|
|
|
135
|
-
|
|
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
|
-
|
|
144
|
-
return Number(value);
|
|
139
|
+
return Number(value) as NumberPrimitivesType[T];
|
|
145
140
|
case 'string':
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
155
|
-
|
|
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
|
-
|
|
161
|
-
return Number(baseValue);
|
|
155
|
+
return Number(baseValue) as NumberPrimitivesType[T];
|
|
162
156
|
case 'string':
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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:
|
|
277
|
-
decimal
|
|
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({
|
|
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 =
|
|
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
|
-
:
|
|
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
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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(
|
|
332
|
-
return typeof
|
|
333
|
-
? 'getValue' in
|
|
334
|
-
?
|
|
335
|
-
:
|
|
336
|
-
:
|
|
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
|
}
|