@tcswap/helpers 4.5.15

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.
Files changed (139) hide show
  1. package/dist/api/index.cjs +4 -0
  2. package/dist/api/index.cjs.map +16 -0
  3. package/dist/api/index.js +4 -0
  4. package/dist/api/index.js.map +16 -0
  5. package/dist/chunk-pfmeq01a.js +5 -0
  6. package/dist/chunk-pfmeq01a.js.map +9 -0
  7. package/dist/chunk-vb4wtm2w.js +4 -0
  8. package/dist/chunk-vb4wtm2w.js.map +9 -0
  9. package/dist/contracts.cjs +4 -0
  10. package/dist/contracts.cjs.map +10 -0
  11. package/dist/contracts.js +4 -0
  12. package/dist/contracts.js.map +10 -0
  13. package/dist/index.cjs +7 -0
  14. package/dist/index.cjs.map +30 -0
  15. package/dist/index.js +7 -0
  16. package/dist/index.js.map +30 -0
  17. package/dist/tokens.cjs +4 -0
  18. package/dist/tokens.cjs.map +10 -0
  19. package/dist/tokens.js +4 -0
  20. package/dist/tokens.js.map +10 -0
  21. package/dist/types/api/index.d.ts +502 -0
  22. package/dist/types/api/index.d.ts.map +1 -0
  23. package/dist/types/api/memoless/endpoints.d.ts +56 -0
  24. package/dist/types/api/memoless/endpoints.d.ts.map +1 -0
  25. package/dist/types/api/memoless/types.d.ts +85 -0
  26. package/dist/types/api/memoless/types.d.ts.map +1 -0
  27. package/dist/types/api/midgard/endpoints.d.ts +80 -0
  28. package/dist/types/api/midgard/endpoints.d.ts.map +1 -0
  29. package/dist/types/api/midgard/types.d.ts +543 -0
  30. package/dist/types/api/midgard/types.d.ts.map +1 -0
  31. package/dist/types/api/thornode/endpoints.d.ts +34 -0
  32. package/dist/types/api/thornode/endpoints.d.ts.map +1 -0
  33. package/dist/types/api/thornode/types.d.ts +264 -0
  34. package/dist/types/api/thornode/types.d.ts.map +1 -0
  35. package/dist/types/api/uswap/endpoints.d.ts +372 -0
  36. package/dist/types/api/uswap/endpoints.d.ts.map +1 -0
  37. package/dist/types/api/uswap/types.d.ts +1487 -0
  38. package/dist/types/api/uswap/types.d.ts.map +1 -0
  39. package/dist/types/contracts.d.ts +2 -0
  40. package/dist/types/contracts.d.ts.map +1 -0
  41. package/dist/types/index.d.ts +32 -0
  42. package/dist/types/index.d.ts.map +1 -0
  43. package/dist/types/modules/assetValue.d.ts +82 -0
  44. package/dist/types/modules/assetValue.d.ts.map +1 -0
  45. package/dist/types/modules/bigIntArithmetics.d.ts +60 -0
  46. package/dist/types/modules/bigIntArithmetics.d.ts.map +1 -0
  47. package/dist/types/modules/feeMultiplier.d.ts +48 -0
  48. package/dist/types/modules/feeMultiplier.d.ts.map +1 -0
  49. package/dist/types/modules/requestClient.d.ts +33 -0
  50. package/dist/types/modules/requestClient.d.ts.map +1 -0
  51. package/dist/types/modules/uSwapConfig.d.ts +249 -0
  52. package/dist/types/modules/uSwapConfig.d.ts.map +1 -0
  53. package/dist/types/modules/uSwapError.d.ts +879 -0
  54. package/dist/types/modules/uSwapError.d.ts.map +1 -0
  55. package/dist/types/modules/uSwapNumber.d.ts +10 -0
  56. package/dist/types/modules/uSwapNumber.d.ts.map +1 -0
  57. package/dist/types/tokens.d.ts +2 -0
  58. package/dist/types/tokens.d.ts.map +1 -0
  59. package/dist/types/types/commonTypes.d.ts +16 -0
  60. package/dist/types/types/commonTypes.d.ts.map +1 -0
  61. package/dist/types/types/derivationPath.d.ts +4 -0
  62. package/dist/types/types/derivationPath.d.ts.map +1 -0
  63. package/dist/types/types/errors/apiV1.d.ts +2 -0
  64. package/dist/types/types/errors/apiV1.d.ts.map +1 -0
  65. package/dist/types/types/index.d.ts +6 -0
  66. package/dist/types/types/index.d.ts.map +1 -0
  67. package/dist/types/types/quotes.d.ts +180 -0
  68. package/dist/types/types/quotes.d.ts.map +1 -0
  69. package/dist/types/types/sdk.d.ts +35 -0
  70. package/dist/types/types/sdk.d.ts.map +1 -0
  71. package/dist/types/types/wallet.d.ts +130 -0
  72. package/dist/types/types/wallet.d.ts.map +1 -0
  73. package/dist/types/utils/asset.d.ts +37 -0
  74. package/dist/types/utils/asset.d.ts.map +1 -0
  75. package/dist/types/utils/chains.d.ts +13 -0
  76. package/dist/types/utils/chains.d.ts.map +1 -0
  77. package/dist/types/utils/derivationPath.d.ts +21 -0
  78. package/dist/types/utils/derivationPath.d.ts.map +1 -0
  79. package/dist/types/utils/explorerUrls.d.ts +10 -0
  80. package/dist/types/utils/explorerUrls.d.ts.map +1 -0
  81. package/dist/types/utils/liquidity.d.ts +62 -0
  82. package/dist/types/utils/liquidity.d.ts.map +1 -0
  83. package/dist/types/utils/memo.d.ts +65 -0
  84. package/dist/types/utils/memo.d.ts.map +1 -0
  85. package/dist/types/utils/others.d.ts +15 -0
  86. package/dist/types/utils/others.d.ts.map +1 -0
  87. package/dist/types/utils/validators.d.ts +6 -0
  88. package/dist/types/utils/validators.d.ts.map +1 -0
  89. package/dist/types/utils/wallets.d.ts +36 -0
  90. package/dist/types/utils/wallets.d.ts.map +1 -0
  91. package/package.json +67 -0
  92. package/src/api/index.ts +15 -0
  93. package/src/api/memoless/endpoints.ts +62 -0
  94. package/src/api/memoless/types.ts +83 -0
  95. package/src/api/midgard/endpoints.ts +352 -0
  96. package/src/api/midgard/types.ts +515 -0
  97. package/src/api/thornode/endpoints.ts +109 -0
  98. package/src/api/thornode/types.ts +247 -0
  99. package/src/api/uswap/endpoints.ts +252 -0
  100. package/src/api/uswap/types.ts +626 -0
  101. package/src/contracts.ts +1 -0
  102. package/src/index.ts +32 -0
  103. package/src/modules/__tests__/assetValue.test.ts +2452 -0
  104. package/src/modules/__tests__/bigIntArithmetics.test.ts +410 -0
  105. package/src/modules/__tests__/feeMultiplier.test.ts +131 -0
  106. package/src/modules/__tests__/uSwapConfig.test.ts +429 -0
  107. package/src/modules/__tests__/uSwapNumber.test.ts +439 -0
  108. package/src/modules/assetValue.ts +536 -0
  109. package/src/modules/bigIntArithmetics.ts +366 -0
  110. package/src/modules/feeMultiplier.ts +84 -0
  111. package/src/modules/requestClient.ts +116 -0
  112. package/src/modules/uSwapConfig.ts +189 -0
  113. package/src/modules/uSwapError.ts +474 -0
  114. package/src/modules/uSwapNumber.ts +17 -0
  115. package/src/tokens.ts +1 -0
  116. package/src/types/commonTypes.ts +10 -0
  117. package/src/types/derivationPath.ts +11 -0
  118. package/src/types/errors/apiV1.ts +0 -0
  119. package/src/types/index.ts +5 -0
  120. package/src/types/quotes.ts +182 -0
  121. package/src/types/sdk.ts +38 -0
  122. package/src/types/wallet.ts +124 -0
  123. package/src/utils/__tests__/asset.test.ts +186 -0
  124. package/src/utils/__tests__/derivationPath.test.ts +142 -0
  125. package/src/utils/__tests__/explorerUrls.test.ts +59 -0
  126. package/src/utils/__tests__/liquidity.test.ts +302 -0
  127. package/src/utils/__tests__/memo.test.ts +99 -0
  128. package/src/utils/__tests__/others.test.ts +169 -0
  129. package/src/utils/__tests__/validators.test.ts +84 -0
  130. package/src/utils/__tests__/wallets.test.ts +625 -0
  131. package/src/utils/asset.ts +399 -0
  132. package/src/utils/chains.ts +104 -0
  133. package/src/utils/derivationPath.ts +101 -0
  134. package/src/utils/explorerUrls.ts +32 -0
  135. package/src/utils/liquidity.ts +154 -0
  136. package/src/utils/memo.ts +102 -0
  137. package/src/utils/others.ts +64 -0
  138. package/src/utils/validators.ts +36 -0
  139. package/src/utils/wallets.ts +238 -0
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Modifications © 2025 Horizontal Systems.
3
+ */
4
+
5
+ import { match } from "ts-pattern";
6
+ import type { USwapNumber } from "./uSwapNumber";
7
+
8
+ type NumberPrimitivesType = { bigint: bigint; number: number; string: string };
9
+ export type NumberPrimitives = bigint | number | string;
10
+ type InitialisationValueType = NumberPrimitives | BigIntArithmetics | USwapNumber;
11
+
12
+ type USwapBigIntParams = InitialisationValueType | { decimal?: number; value: number | string };
13
+ type AllowedNumberTypes = "bigint" | "number" | "string";
14
+
15
+ const DEFAULT_DECIMAL = 8;
16
+ const PRECISION_BUFFER = 10;
17
+
18
+ export function formatBigIntToSafeValue({
19
+ value,
20
+ bigIntDecimal = DEFAULT_DECIMAL,
21
+ decimal = DEFAULT_DECIMAL,
22
+ }: {
23
+ value: bigint;
24
+ bigIntDecimal?: number;
25
+ decimal?: number;
26
+ }) {
27
+ if (decimal === 0) return value.toString();
28
+
29
+ const isNegative = value < 0n;
30
+ let valueString = value.toString().substring(isNegative ? 1 : 0);
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
+ const roundDigit = Number.parseInt(decimalString[bigIntDecimal] || "0", 10);
41
+ if (roundDigit >= 5) {
42
+ const lastDigit = Number.parseInt(decimalString[bigIntDecimal - 1] || "0", 10);
43
+ decimalString = `${decimalString.substring(0, bigIntDecimal - 1)}${lastDigit + 1}`;
44
+ } else {
45
+ decimalString = decimalString.substring(0, bigIntDecimal);
46
+ }
47
+
48
+ return `${isNegative ? "-" : ""}${valueString.slice(0, decimalIndex)}.${decimalString}`.replace(/\.?0*$/, "");
49
+ }
50
+
51
+ export class BigIntArithmetics {
52
+ decimalMultiplier: bigint = 10n ** 8n;
53
+ bigIntValue = 0n;
54
+ decimal?: number;
55
+
56
+ static fromBigInt(value: bigint, decimal?: number) {
57
+ return new BigIntArithmetics({
58
+ decimal,
59
+ value: formatBigIntToSafeValue({ bigIntDecimal: decimal, decimal, value }),
60
+ });
61
+ }
62
+
63
+ static shiftDecimals({ value, from, to }: { value: InstanceType<typeof USwapNumber>; from: number; to: number }) {
64
+ return BigIntArithmetics.fromBigInt((value.getBaseValue("bigint") * toMultiplier(to)) / toMultiplier(from), to);
65
+ }
66
+
67
+ constructor(params: USwapBigIntParams) {
68
+ const value = getStringValue(params);
69
+ const isComplex = typeof params === "object";
70
+ this.decimal = isComplex ? params.decimal : undefined;
71
+
72
+ this.decimalMultiplier =
73
+ isComplex && "decimalMultiplier" in params
74
+ ? params.decimalMultiplier
75
+ : toMultiplier(Math.max(getFloatDecimals(toSafeValue(value)), this.decimal || 0));
76
+
77
+ this.#setValue(value);
78
+ }
79
+
80
+ set(value: USwapBigIntParams): this {
81
+ return new (this.constructor as any)({
82
+ decimal: this.decimal,
83
+ identifier: (this as any).toString?.({ includeSynthProtocol: true }),
84
+ value,
85
+ });
86
+ }
87
+
88
+ add(...args: InitialisationValueType[]) {
89
+ return this.#arithmetics("add", ...args);
90
+ }
91
+
92
+ sub(...args: InitialisationValueType[]) {
93
+ return this.#arithmetics("sub", ...args);
94
+ }
95
+
96
+ mul(...args: InitialisationValueType[]) {
97
+ return this.#arithmetics("mul", ...args);
98
+ }
99
+
100
+ div(...args: InitialisationValueType[]) {
101
+ return this.#arithmetics("div", ...args);
102
+ }
103
+
104
+ gt(value: InitialisationValueType) {
105
+ return this.#comparison("gt", value);
106
+ }
107
+
108
+ gte(value: InitialisationValueType) {
109
+ return this.#comparison("gte", value);
110
+ }
111
+
112
+ lt(value: InitialisationValueType) {
113
+ return this.#comparison("lt", value);
114
+ }
115
+
116
+ lte(value: InitialisationValueType) {
117
+ return this.#comparison("lte", value);
118
+ }
119
+
120
+ eqValue(value: InitialisationValueType) {
121
+ return this.#comparison("eqValue", value);
122
+ }
123
+
124
+ getValue<T extends AllowedNumberTypes>(type: T, decimal?: number): NumberPrimitivesType[T] {
125
+ const currentDecimal = decimalFromMultiplier(this.decimalMultiplier);
126
+ const requestedDecimal = decimal !== undefined ? decimal : this.decimal;
127
+
128
+ let outputDecimal = requestedDecimal !== undefined ? requestedDecimal : currentDecimal;
129
+
130
+ if (requestedDecimal !== undefined && requestedDecimal < currentDecimal) {
131
+ const testValue = this.formatBigIntToSafeValue(this.bigIntValue, requestedDecimal);
132
+ if (testValue === "0" && this.bigIntValue !== 0n) {
133
+ outputDecimal = currentDecimal;
134
+ }
135
+ }
136
+
137
+ const value = this.formatBigIntToSafeValue(this.bigIntValue, outputDecimal);
138
+
139
+ return match(type as AllowedNumberTypes)
140
+ .with("number", () => Number(value) as NumberPrimitivesType[T])
141
+ .with("string", () => value as NumberPrimitivesType[T])
142
+ .with("bigint", () => {
143
+ const scaledValue = (this.bigIntValue * 10n ** BigInt(this.decimal || 8n)) / this.decimalMultiplier;
144
+ return scaledValue as NumberPrimitivesType[T];
145
+ })
146
+ .otherwise(() => value as NumberPrimitivesType[T]);
147
+ }
148
+
149
+ getBaseValue<T extends AllowedNumberTypes>(type: T, decimal?: number): NumberPrimitivesType[T] {
150
+ const divisor = this.decimalMultiplier / toMultiplier(decimal || this.decimal || DEFAULT_DECIMAL);
151
+ const baseValue = divideBigIntWithRounding(this.bigIntValue, divisor);
152
+
153
+ return match(type as AllowedNumberTypes)
154
+ .with("number", () => Number(baseValue) as NumberPrimitivesType[T])
155
+ .with("string", () => baseValue.toString() as NumberPrimitivesType[T])
156
+ .otherwise(() => baseValue as NumberPrimitivesType[T]);
157
+ }
158
+
159
+ getBigIntValue(value: InitialisationValueType, decimal?: number) {
160
+ if (!decimal && typeof value === "object") return value.bigIntValue;
161
+
162
+ const stringValue = getStringValue(value);
163
+ const safeValue = toSafeValue(stringValue);
164
+
165
+ if (safeValue === "0" || safeValue === "undefined") return 0n;
166
+ return this.#toBigInt(safeValue, decimal);
167
+ }
168
+
169
+ toSignificant(significantDigits = 6) {
170
+ const valueStr = this.getValue("string");
171
+ const [int = "", dec = ""] = valueStr.split(".");
172
+ const hasInteger = Number.parseInt(int, 10) > 0;
173
+ const totalLength = hasInteger ? int.length + dec.length : dec.length;
174
+
175
+ if (totalLength <= significantDigits) return valueStr;
176
+ if (int.length >= significantDigits) return int.slice(0, significantDigits).padEnd(int.length, "0");
177
+ if (hasInteger) return `${int}.${dec.slice(0, significantDigits - int.length)}`;
178
+
179
+ const trimmed = BigInt(dec).toString();
180
+ const sliced = trimmed.slice(0, significantDigits);
181
+ const leadingZeros = dec.length - trimmed.length;
182
+
183
+ return `0.${sliced.padStart(leadingZeros + sliced.length, "0")}`;
184
+ }
185
+
186
+ toFixed(fixedDigits = 6) {
187
+ const valueStr = this.getValue("string");
188
+ const isNegative = valueStr.startsWith("-");
189
+ const [int = "0", dec = ""] = (isNegative ? valueStr.slice(1) : valueStr).split(".");
190
+ const valueRoundsToZero = int === "0" && Number.parseInt(dec.slice(0, fixedDigits), 10) === 0;
191
+ const sign = isNegative && !valueRoundsToZero ? "-" : "";
192
+
193
+ if (fixedDigits === 0) {
194
+ if (int === "0" && !dec) return "0";
195
+ const shouldRound = dec && Number.parseInt(dec[0] || "0", 10) >= 5;
196
+ return shouldRound ? `${sign}${BigInt(int) + 1n}.0` : `${sign}${int}.0`;
197
+ }
198
+
199
+ if (!dec) return `${sign}${int}.${"0".repeat(fixedDigits)}`;
200
+
201
+ const nextDigit = dec[fixedDigits];
202
+ const shouldRound = nextDigit && Number.parseInt(nextDigit, 10) >= 5;
203
+
204
+ if (!shouldRound) return `${sign}${int}.${dec.slice(0, fixedDigits).padEnd(fixedDigits, "0")}`;
205
+
206
+ const decimalValue = BigInt(dec.slice(0, fixedDigits).padEnd(fixedDigits, "0")) + 1n;
207
+ const multiplier = 10n ** BigInt(fixedDigits);
208
+
209
+ if (decimalValue >= multiplier) return `${sign}${BigInt(int) + 1n}.${"0".repeat(fixedDigits)}`;
210
+
211
+ return `${sign}${int}.${decimalValue.toString().padStart(fixedDigits, "0")}`;
212
+ }
213
+
214
+ toAbbreviation(digits = 2) {
215
+ const valueStr = this.getValue("string");
216
+ const value = Number(valueStr);
217
+ const abbreviations = ["", "K", "M", "B", "T", "Q", "Qi", "S"] as const;
218
+ const tier = Math.floor(Math.log10(Math.abs(value)) / 3);
219
+
220
+ if (tier === 0 || !abbreviations[tier]) return valueStr;
221
+
222
+ return `${(value / 10 ** (tier * 3)).toFixed(digits)}${abbreviations[tier]}`;
223
+ }
224
+
225
+ toCurrency(
226
+ currency = "$",
227
+ {
228
+ currencyPosition = "start",
229
+ decimal = 2,
230
+ decimalSeparator = ".",
231
+ thousandSeparator = ",",
232
+ trimTrailingZeros = true,
233
+ } = {},
234
+ ) {
235
+ const fixedValue = this.toFixed(decimal);
236
+ const isCurrencyAtEnd = currencyPosition === "end";
237
+ const [int = "0", dec = ""] = fixedValue.split(".");
238
+
239
+ const formattedInt = int.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
240
+ const hasDecimals = dec && Number.parseInt(dec, 10) > 0;
241
+ const formattedValue = hasDecimals ? `${formattedInt}${decimalSeparator}${dec}` : formattedInt;
242
+
243
+ // Prevent regex from taking too long for large values
244
+ const canTrimTrailingZeros = formattedValue.length < 100 && trimTrailingZeros && hasDecimals;
245
+ const value = canTrimTrailingZeros ? formattedValue.replace(/\.?0*$/, "") : formattedValue;
246
+
247
+ return isCurrencyAtEnd ? `${value}${currency}` : `${currency}${value}`;
248
+ }
249
+
250
+ formatBigIntToSafeValue(value: bigint, decimal?: number) {
251
+ const bigIntDecimal = decimal || this.decimal || DEFAULT_DECIMAL;
252
+ const decimalToUseForConversion = Math.max(bigIntDecimal, decimalFromMultiplier(this.decimalMultiplier));
253
+
254
+ return formatBigIntToSafeValue({ bigIntDecimal, decimal: decimalToUseForConversion, value });
255
+ }
256
+
257
+ #arithmetics(method: "add" | "sub" | "mul" | "div", ...args: InitialisationValueType[]): this {
258
+ const precisionDecimal = this.#retrievePrecisionDecimal(this, ...args);
259
+ const currentDecimal = decimalFromMultiplier(this.decimalMultiplier);
260
+ const targetDecimal = Math.max(precisionDecimal, currentDecimal);
261
+ const internalDecimal = targetDecimal + PRECISION_BUFFER;
262
+ const internalMultiplier = toMultiplier(internalDecimal);
263
+
264
+ const result = args.reduce(
265
+ (acc: bigint, arg) => {
266
+ const value = this.getBigIntValue(arg, internalDecimal);
267
+
268
+ return match(method)
269
+ .with("add", () => acc + value)
270
+ .with("sub", () => acc - value)
271
+ .with("mul", () => (acc * value) / internalMultiplier)
272
+ .with("div", () => {
273
+ if (value === 0n) throw new RangeError("Division by zero");
274
+ return (acc * internalMultiplier) / value;
275
+ })
276
+ .otherwise(() => acc);
277
+ },
278
+ (this.bigIntValue * internalMultiplier) / this.decimalMultiplier,
279
+ );
280
+
281
+ const value = formatBigIntToSafeValue({ bigIntDecimal: internalDecimal, decimal: internalDecimal, value: result });
282
+
283
+ // @ts-expect-error False positive
284
+ return new this.constructor({
285
+ decimal: this.decimal,
286
+ decimalMultiplier: toMultiplier(internalDecimal),
287
+ identifier: this.toString(),
288
+ value,
289
+ });
290
+ }
291
+
292
+ #comparison(method: "gt" | "gte" | "lt" | "lte" | "eqValue", ...args: InitialisationValueType[]) {
293
+ const decimal = this.#retrievePrecisionDecimal(this, ...args);
294
+ const value = this.getBigIntValue(args[0] || "0", decimal);
295
+ const compareToValue = this.getBigIntValue(this, decimal);
296
+
297
+ return match(method)
298
+ .with("gt", () => compareToValue > value)
299
+ .with("gte", () => compareToValue >= value)
300
+ .with("lt", () => compareToValue < value)
301
+ .with("lte", () => compareToValue <= value)
302
+ .with("eqValue", () => compareToValue === value)
303
+ .otherwise(() => false);
304
+ }
305
+
306
+ #setValue(value: InitialisationValueType) {
307
+ const safeValue = toSafeValue(value) || "0";
308
+ this.bigIntValue = this.#toBigInt(safeValue);
309
+ }
310
+
311
+ #retrievePrecisionDecimal(...args: InitialisationValueType[]) {
312
+ const decimals = args
313
+ .map((arg) => {
314
+ const isObject = typeof arg === "object";
315
+ const value = isObject
316
+ ? arg.decimal || decimalFromMultiplier(arg.decimalMultiplier)
317
+ : getFloatDecimals(toSafeValue(arg));
318
+
319
+ return value;
320
+ })
321
+ .filter(Boolean) as number[];
322
+
323
+ return Math.max(...decimals, DEFAULT_DECIMAL);
324
+ }
325
+
326
+ #toBigInt(value: string, decimal?: number) {
327
+ const multiplier = decimal ? toMultiplier(decimal) : this.decimalMultiplier;
328
+ const padDecimal = decimalFromMultiplier(multiplier);
329
+ const [integerPart = "", decimalPart = ""] = value.split(".");
330
+
331
+ return BigInt(`${integerPart}${decimalPart.padEnd(padDecimal, "0")}`);
332
+ }
333
+ }
334
+
335
+ const numberFormatter = Intl.NumberFormat("fullwide", { maximumFractionDigits: 20, useGrouping: false });
336
+
337
+ function toSafeValue(value: InitialisationValueType) {
338
+ const parsedValue = typeof value === "number" ? numberFormatter.format(value) : getStringValue(value);
339
+ const splitValue = `${parsedValue}`.replaceAll(",", ".").split(".");
340
+
341
+ return splitValue.length > 1 ? `${splitValue.slice(0, -1).join("")}.${splitValue.at(-1)}` : splitValue[0] || "0";
342
+ }
343
+
344
+ function getFloatDecimals(value: string) {
345
+ const decimals = value.split(".")[1]?.length || 0;
346
+ return Math.max(decimals, DEFAULT_DECIMAL);
347
+ }
348
+
349
+ function getStringValue(param: USwapBigIntParams) {
350
+ return typeof param === "object" ? ("getValue" in param ? param.getValue("string") : param.value) : param;
351
+ }
352
+
353
+ function divideBigIntWithRounding(n: bigint, d: bigint) {
354
+ if (d === 0n) throw new Error("Cannot divide by zero");
355
+
356
+ const half = d / 2n;
357
+ return (n >= 0n && d >= 0n) || (n < 0n && d < 0n) ? (n + half) / d : (n - half) / d;
358
+ }
359
+
360
+ function toMultiplier(decimal: number) {
361
+ return 10n ** BigInt(decimal);
362
+ }
363
+
364
+ function decimalFromMultiplier(multiplier: bigint) {
365
+ return Math.log10(Number.parseFloat(multiplier.toString()));
366
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Modifications © 2025 Horizontal Systems.
3
+ */
4
+
5
+ import { FeeOption } from "../types";
6
+ import { USwapConfig } from "./uSwapConfig";
7
+
8
+ export interface FeeMultiplierConfig {
9
+ [FeeOption.Average]: number;
10
+ [FeeOption.Fast]: number;
11
+ [FeeOption.Fastest]: number;
12
+ }
13
+
14
+ const DEFAULT_FEE_MULTIPLIERS: FeeMultiplierConfig = {
15
+ [FeeOption.Average]: 1.0,
16
+ [FeeOption.Fast]: 1.5,
17
+ [FeeOption.Fastest]: 2.0,
18
+ };
19
+
20
+ /**
21
+ * Get fee multiplier for the given fee option.
22
+ * Checks USwapConfig for custom multipliers first, then falls back to defaults.
23
+ *
24
+ * @param feeOption - The fee option (Average, Fast, Fastest)
25
+ * @returns The fee multiplier as a number
26
+ */
27
+ export function getFeeMultiplier(feeOption: FeeOption = FeeOption.Average): number {
28
+ const customMultipliers = USwapConfig.get("feeMultipliers");
29
+
30
+ if (customMultipliers && customMultipliers[feeOption] !== undefined) {
31
+ return customMultipliers[feeOption];
32
+ }
33
+
34
+ return DEFAULT_FEE_MULTIPLIERS[feeOption];
35
+ }
36
+
37
+ /**
38
+ * Get fee multiplier as BigInt for EVM calculations.
39
+ * Returns numerator and denominator for precise BigInt arithmetic.
40
+ *
41
+ * @param feeOption - The fee option (Average, Fast, Fastest)
42
+ * @returns Object with numerator and denominator for BigInt calculations
43
+ */
44
+ export function getFeeMultiplierAsBigInt(feeOption: FeeOption = FeeOption.Average): {
45
+ numerator: bigint;
46
+ denominator: bigint;
47
+ } {
48
+ const multiplier = getFeeMultiplier(feeOption);
49
+
50
+ // Convert decimal multiplier to fraction for precise BigInt arithmetic
51
+ // e.g., 1.5 -> 15/10, 2.0 -> 20/10
52
+ const denominator = 10n;
53
+ const numerator = BigInt(Math.round(multiplier * 10));
54
+
55
+ return { denominator, numerator };
56
+ }
57
+
58
+ /**
59
+ * Apply fee multiplier to a BigInt value (for EVM chains).
60
+ *
61
+ * @param value - The base fee value as BigInt
62
+ * @param feeOption - The fee option (Average, Fast, Fastest)
63
+ * @returns The multiplied fee value as BigInt
64
+ */
65
+ export function applyFeeMultiplierToBigInt(value: bigint, feeOption: FeeOption = FeeOption.Average) {
66
+ const { numerator, denominator } = getFeeMultiplierAsBigInt(feeOption);
67
+ return (value * numerator) / denominator;
68
+ }
69
+
70
+ /**
71
+ * Apply fee multiplier to a number value (for non-EVM chains).
72
+ *
73
+ * @param value - The base fee value as number
74
+ * @param feeOption - The fee option (Average, Fast, Fastest)
75
+ * @param floor - Whether to floor the result (default: false)
76
+ * @returns The multiplied fee value as number
77
+ */
78
+ export function applyFeeMultiplier(value: number, feeOption: FeeOption = FeeOption.Average, floor = false): number {
79
+ const multiplier = getFeeMultiplier(feeOption);
80
+ const result = value * multiplier;
81
+ return floor ? Math.floor(result) : result;
82
+ }
83
+
84
+ export { DEFAULT_FEE_MULTIPLIERS };
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Modifications © 2025 Horizontal Systems.
3
+ */
4
+
5
+ import { USwapConfig } from "./uSwapConfig";
6
+ import { USwapError } from "./uSwapError";
7
+
8
+ export type RetryConfig = { maxRetries?: number; baseDelay?: number; maxDelay?: number; backoffMultiplier?: number };
9
+
10
+ export type RequestOptions = RequestInit & {
11
+ /**
12
+ * @deprecated @V4 Use onSuccess instead - will be removed in next major
13
+ */
14
+ responseHandler?: (response: any) => any;
15
+ json?: unknown;
16
+ onError?: (error: any) => any;
17
+ onSuccess?: (response: any) => any;
18
+ searchParams?: Record<string, string>;
19
+ dynamicHeader?: () => Record<string, string> | {};
20
+ retry?: RetryConfig;
21
+ timeoutMs?: number;
22
+ abortController?: AbortController;
23
+ };
24
+
25
+ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
26
+ const calculateDelay = (attempt: number, { baseDelay, backoffMultiplier, maxDelay }: any) =>
27
+ Math.min(baseDelay * backoffMultiplier ** attempt, maxDelay);
28
+
29
+ const makeRequest = async (url: string, config: RequestInit) => {
30
+ const response = await fetch(url, config);
31
+
32
+ if (!response.ok) {
33
+ const errorBody = await response.json().catch(() => null);
34
+ const errorData = { status: response.status, statusText: response.statusText };
35
+ const errorInfo = { ...errorData, ...(errorBody && { errorData: errorBody }) };
36
+ throw new USwapError({ errorKey: "helpers_invalid_response", info: errorData }, errorInfo);
37
+ }
38
+ return response.json();
39
+ };
40
+
41
+ function fetchWithConfig(method: "GET" | "POST", extendOptions: RequestOptions = {}) {
42
+ return async function methodFetchWithConfig<T>(url: string, options: RequestOptions = {}): Promise<T> {
43
+ const {
44
+ searchParams,
45
+ json,
46
+ body,
47
+ headers,
48
+ dynamicHeader,
49
+ retry,
50
+ timeoutMs,
51
+ abortController,
52
+ onError,
53
+ onSuccess,
54
+ responseHandler,
55
+ ...fetchOptions
56
+ } = { ...extendOptions, ...options };
57
+ const requestOptions = USwapConfig.get("requestOptions");
58
+
59
+ const retryConfig = { ...requestOptions.retry, ...retry };
60
+ const isJson = !!json || url.endsWith(".json");
61
+ const requestUrl = buildUrl(url, searchParams);
62
+ const requestHeaders = buildHeaders(isJson, { ...headers, ...dynamicHeader?.() });
63
+ const requestBody = isJson ? JSON.stringify(json) : body;
64
+
65
+ let lastError: any;
66
+
67
+ for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
68
+ const controller = abortController || new AbortController();
69
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs || requestOptions.timeoutMs);
70
+
71
+ try {
72
+ const result = await makeRequest(requestUrl, {
73
+ ...fetchOptions,
74
+ body: requestBody,
75
+ headers: requestHeaders,
76
+ method,
77
+ signal: controller.signal,
78
+ });
79
+
80
+ clearTimeout(timeoutId);
81
+ return onSuccess?.(result) || responseHandler?.(result) || result;
82
+ } catch (error) {
83
+ clearTimeout(timeoutId);
84
+ lastError = error;
85
+
86
+ if (attempt >= retryConfig.maxRetries) {
87
+ return onError ? onError(error) : Promise.reject(error);
88
+ }
89
+
90
+ await sleep(calculateDelay(attempt, retryConfig));
91
+ }
92
+ }
93
+
94
+ return onError ? onError(lastError) : Promise.reject(lastError);
95
+ };
96
+ }
97
+
98
+ function buildHeaders(isJson: boolean, headers?: HeadersInit) {
99
+ return { ...headers, ...(isJson && { "Content-Type": "application/json" }) };
100
+ }
101
+
102
+ function buildUrl(url: string, searchParams?: Record<string, string>) {
103
+ const urlInstance = new URL(url);
104
+ if (searchParams) urlInstance.search = new URLSearchParams(searchParams).toString();
105
+ return urlInstance.toString();
106
+ }
107
+
108
+ export const RequestClient = {
109
+ extend: (extendOptions: RequestOptions) => ({
110
+ extend: (newOptions: RequestOptions) => RequestClient.extend({ ...extendOptions, ...newOptions }),
111
+ get: fetchWithConfig("GET", extendOptions),
112
+ post: fetchWithConfig("POST", extendOptions),
113
+ }),
114
+ get: fetchWithConfig("GET"),
115
+ post: fetchWithConfig("POST"),
116
+ };