@mimicprotocol/lib-ts 0.0.1-rc.9
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/README.md +90 -0
- package/index.ts +7 -0
- package/package.json +26 -0
- package/src/chains/Ethereum.ts +12 -0
- package/src/chains/Optimism.ts +12 -0
- package/src/chains/Polygon.ts +12 -0
- package/src/chains/index.ts +3 -0
- package/src/context/Context.ts +29 -0
- package/src/context/index.ts +1 -0
- package/src/environment.ts +126 -0
- package/src/evm.ts +40 -0
- package/src/helpers/constants.ts +9 -0
- package/src/helpers/index.ts +3 -0
- package/src/helpers/serialize.ts +140 -0
- package/src/helpers/strings.ts +103 -0
- package/src/intents/Call.ts +238 -0
- package/src/intents/Intent.ts +79 -0
- package/src/intents/Swap.ts +419 -0
- package/src/intents/Transfer.ts +349 -0
- package/src/intents/index.ts +4 -0
- package/src/queries/Call.ts +16 -0
- package/src/queries/index.ts +1 -0
- package/src/tokens/Token.ts +191 -0
- package/src/tokens/TokenAmount.ts +248 -0
- package/src/tokens/USD.ts +201 -0
- package/src/tokens/index.ts +3 -0
- package/src/types/Address.ts +60 -0
- package/src/types/BigInt.ts +796 -0
- package/src/types/ByteArray.ts +316 -0
- package/src/types/Bytes.ts +137 -0
- package/src/types/ChainId.ts +9 -0
- package/src/types/EvmDecodeParam.ts +30 -0
- package/src/types/EvmEncodeParam.ts +54 -0
- package/src/types/index.ts +7 -0
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
// eslint-disable-next-line no-secrets/no-secrets
|
|
2
|
+
// This file is based on code from "The Graph Tooling" (https://github.com/graphprotocol/graph-tooling/tree/7faa3098b2e6c61f09fc81b8b2d333e66b0080d1).
|
|
3
|
+
// Licensed under the MIT License.
|
|
4
|
+
// Copyright (c) 2018 Graph Protocol, Inc. and contributors.
|
|
5
|
+
// Modified by Mimic Protocol, 2025.
|
|
6
|
+
|
|
7
|
+
import { areAllZeros, bytesToHexString, isHex, normalizeScientificNotation, Serializable } from '../helpers'
|
|
8
|
+
|
|
9
|
+
import { ByteArray } from './ByteArray'
|
|
10
|
+
import { Bytes } from './Bytes'
|
|
11
|
+
|
|
12
|
+
const ZERO_ASCII = '0'.charCodeAt(0)
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Represents an arbitrary-precision integer stored as a byte array.
|
|
16
|
+
*/
|
|
17
|
+
export class BigInt extends Uint8Array implements Serializable {
|
|
18
|
+
private static readonly SERIALIZED_PREFIX: string = 'BigInt'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Parses a serialized representation of a BigInt and converts it to a BigInt.
|
|
22
|
+
*/
|
|
23
|
+
static parse(serialized: string): BigInt {
|
|
24
|
+
const isBigInt = serialized.startsWith(`${BigInt.SERIALIZED_PREFIX}(`) && serialized.endsWith(')')
|
|
25
|
+
if (!isBigInt) throw new Error('Invalid serialized BigInt')
|
|
26
|
+
return BigInt.fromString(serialized.slice(BigInt.SERIALIZED_PREFIX.length + 1, -1))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns a BigInt initialized to zero.
|
|
31
|
+
*/
|
|
32
|
+
static zero(): BigInt {
|
|
33
|
+
return BigInt.fromI32(0)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Creates a BigInt from a signed 8-bit integer (i8).
|
|
38
|
+
*/
|
|
39
|
+
static fromI8(x: i8): BigInt {
|
|
40
|
+
return BigInt.fromByteArray(ByteArray.fromI8(x))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Creates a BigInt from an unsigned 8-bit integer (u8).
|
|
45
|
+
*/
|
|
46
|
+
static fromU8(x: u8): BigInt {
|
|
47
|
+
return BigInt.fromByteArray(ByteArray.fromU8(x))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creates a BigInt from a signed 16-bit integer (i16).
|
|
52
|
+
*/
|
|
53
|
+
static fromI16(x: i16): BigInt {
|
|
54
|
+
return BigInt.fromByteArray(ByteArray.fromI16(x))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a BigInt from an unsigned 16-bit integer (u16).
|
|
59
|
+
*/
|
|
60
|
+
static fromU16(x: u16): BigInt {
|
|
61
|
+
return BigInt.fromByteArray(ByteArray.fromU16(x))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Creates a BigInt from a signed 32-bit integer (i32).
|
|
66
|
+
*/
|
|
67
|
+
static fromI32(x: i32): BigInt {
|
|
68
|
+
return BigInt.fromByteArray(ByteArray.fromI32(x))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Creates a BigInt from an unsigned 32-bit integer (u32).
|
|
73
|
+
*/
|
|
74
|
+
static fromU32(x: u32): BigInt {
|
|
75
|
+
return BigInt.fromUnsignedBytes(ByteArray.fromU32(x))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates a BigInt from a signed 64-bit integer (i64).
|
|
80
|
+
*/
|
|
81
|
+
static fromI64(x: i64): BigInt {
|
|
82
|
+
return BigInt.fromByteArray(ByteArray.fromI64(x))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Creates a BigInt from an unsigned 64-bit integer (u64).
|
|
87
|
+
*/
|
|
88
|
+
static fromU64(x: u64): BigInt {
|
|
89
|
+
return BigInt.fromUnsignedBytes(ByteArray.fromU64(x))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Converts a Bytes instance containing a signed integer to a BigInt.
|
|
94
|
+
*/
|
|
95
|
+
static fromSignedBytes(bytes: Bytes): BigInt {
|
|
96
|
+
return BigInt.fromByteArray(changetype<ByteArray>(bytes))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Converts a ByteArray to a BigInt.
|
|
101
|
+
*/
|
|
102
|
+
static fromByteArray(byteArray: ByteArray): BigInt {
|
|
103
|
+
return changetype<BigInt>(byteArray)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Converts an unsigned ByteArray to a BigInt, appending a zero byte for sign extension.
|
|
108
|
+
*/
|
|
109
|
+
static fromUnsignedBytes(bytes: ByteArray): BigInt {
|
|
110
|
+
const signedBytes = new BigInt(bytes.length + 1)
|
|
111
|
+
for (let i = 0; i < bytes.length; i++) signedBytes[i] = bytes[i]
|
|
112
|
+
signedBytes[bytes.length] = 0
|
|
113
|
+
return signedBytes
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Parses a string representation of a number and converts it to a BigInt.
|
|
118
|
+
* Supports decimal and scientific notation formats.
|
|
119
|
+
*/
|
|
120
|
+
static fromString(str: string): BigInt {
|
|
121
|
+
const hexIndex = str.toLowerCase().indexOf('0x')
|
|
122
|
+
if (hexIndex == 0 || hexIndex == 1) return BigInt.fromHexString(str)
|
|
123
|
+
return this.fromStringDecimal(str, 0)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Parses a string representation of a number with precision and converts it to a BigInt.
|
|
128
|
+
* Supports decimal and scientific notation formats.
|
|
129
|
+
*/
|
|
130
|
+
static fromStringDecimal(str: string, precision: u8): BigInt {
|
|
131
|
+
if (str === '0') return this.zero()
|
|
132
|
+
str = normalizeScientificNotation(str)
|
|
133
|
+
|
|
134
|
+
const parts = str.split('.')
|
|
135
|
+
if (parts.length > 2) throw new Error(`Invalid string. Received: ${str}`)
|
|
136
|
+
|
|
137
|
+
const isNegative = parts[0].startsWith('-')
|
|
138
|
+
const wholePart = isNegative ? parts[0].substring(1) : parts[0]
|
|
139
|
+
let result = BigInt.fromStringRaw(wholePart).upscale(precision)
|
|
140
|
+
|
|
141
|
+
if (parts.length > 1 && parts[1].length > 0) {
|
|
142
|
+
const decimalDigits = parts[1]
|
|
143
|
+
if (decimalDigits.length > <i32>precision && !areAllZeros(decimalDigits)) {
|
|
144
|
+
throw new Error(`Too many decimal places. Max allowed: ${precision}, found: ${decimalDigits.length}`)
|
|
145
|
+
}
|
|
146
|
+
const decimalPart = parts[1].padEnd(precision, '0')
|
|
147
|
+
result = result.plus(BigInt.fromString(decimalPart))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return isNegative ? result.neg() : result
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Parses a hexadecimal string representation of a number and converts it to a BigInt.
|
|
155
|
+
*/
|
|
156
|
+
static fromHexString(hex: string): BigInt {
|
|
157
|
+
hex = hex.toLowerCase()
|
|
158
|
+
if (!hex || hex === '0x' || hex === '-0x') return BigInt.zero()
|
|
159
|
+
|
|
160
|
+
// Remove prefix
|
|
161
|
+
const isNegative = hex.startsWith('-')
|
|
162
|
+
if (isNegative) hex = hex.substring(1)
|
|
163
|
+
else if (hex.startsWith('+')) hex = hex.substring(1)
|
|
164
|
+
if (hex.startsWith('0x')) hex = hex.substring(2)
|
|
165
|
+
|
|
166
|
+
if (!isHex(hex)) throw new Error(`Invalid hex string: '${hex}'`)
|
|
167
|
+
|
|
168
|
+
// ByteArray will still assert even length
|
|
169
|
+
const bytes = ByteArray.fromHexString(hex)
|
|
170
|
+
const result = BigInt.fromUnsignedBytes(bytes)
|
|
171
|
+
return isNegative && !result.isZero() ? result.neg() : result
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
private static fromStringRaw(str: string): BigInt {
|
|
175
|
+
if (str.length == 0) throw new Error('Received invalid empty string')
|
|
176
|
+
let result = BigInt.zero()
|
|
177
|
+
for (let i = 0; i < str.length; i++) {
|
|
178
|
+
const c = str.charCodeAt(i)
|
|
179
|
+
if (c < 48 || c > 57) throw new Error(`Invalid digit '${str.charAt(i)}'`)
|
|
180
|
+
result = result.times(BigInt.fromI32(10)).plus(BigInt.fromI32(c - 48))
|
|
181
|
+
}
|
|
182
|
+
return result
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private static addUnsigned(a: BigInt, b: BigInt): BigInt {
|
|
186
|
+
if (a.isZero()) return b.clone()
|
|
187
|
+
if (b.isZero()) return a.clone()
|
|
188
|
+
|
|
189
|
+
const maxLen = max(a.length, b.length)
|
|
190
|
+
const result = new BigInt(maxLen + 1)
|
|
191
|
+
let carry: u32 = 0
|
|
192
|
+
for (let i = 0; i < maxLen; i++) {
|
|
193
|
+
const ai = i < a.length ? a[i] : 0
|
|
194
|
+
const bi = i < b.length ? b[i] : 0
|
|
195
|
+
const sum = <u32>ai + <u32>bi + carry
|
|
196
|
+
result[i] = <u8>(sum & 0xff)
|
|
197
|
+
carry = sum >> 8
|
|
198
|
+
}
|
|
199
|
+
if (carry != 0) result[maxLen] = <u8>carry
|
|
200
|
+
return result
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private static subUnsigned(a: BigInt, b: BigInt): BigInt {
|
|
204
|
+
const result = new BigInt(a.length)
|
|
205
|
+
let borrow: i32 = 0
|
|
206
|
+
for (let i = 0; i < a.length; i++) {
|
|
207
|
+
const ai = <i32>(i < a.length ? a[i] : 0)
|
|
208
|
+
const bi = <i32>(i < b.length ? b[i] : 0)
|
|
209
|
+
let diff = ai - bi - borrow
|
|
210
|
+
borrow = 0
|
|
211
|
+
if (diff < 0) {
|
|
212
|
+
diff += 256
|
|
213
|
+
borrow = 1
|
|
214
|
+
}
|
|
215
|
+
result[i] = <u8>(diff & 0xff)
|
|
216
|
+
}
|
|
217
|
+
return result
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private static mulUnsigned(a: BigInt, b: BigInt): BigInt {
|
|
221
|
+
if (a.length < b.length) return BigInt.mulUnsigned(b, a)
|
|
222
|
+
if (b.length === 1 && b[0] === 2) return a.leftShift(1)
|
|
223
|
+
|
|
224
|
+
const result = new BigInt(a.length + b.length)
|
|
225
|
+
for (let i = 0; i < a.length; i++) {
|
|
226
|
+
let carry: u32 = 0
|
|
227
|
+
for (let j = 0; j < b.length || carry != 0; j++) {
|
|
228
|
+
const bj = j < b.length ? b[j] : 0
|
|
229
|
+
const sum = <u32>result[i + j] + <u32>a[i] * <u32>bj + carry
|
|
230
|
+
result[i + j] = <u8>(sum & 0xff)
|
|
231
|
+
carry = sum >> 8
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return result
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private static divUnsigned(a: BigInt, b: BigInt): BigInt {
|
|
238
|
+
assert(!b.isZero(), 'Trying to divide by zero')
|
|
239
|
+
if (BigInt.compare(a, b) < 0) return BigInt.zero()
|
|
240
|
+
|
|
241
|
+
let quotient = BigInt.zero()
|
|
242
|
+
let remainder = BigInt.zero()
|
|
243
|
+
|
|
244
|
+
for (let i = a.length - 1; i >= 0; i--) {
|
|
245
|
+
remainder = remainder.leftShift(8)
|
|
246
|
+
remainder = BigInt.addUnsigned(remainder, BigInt.fromI32(a[i]))
|
|
247
|
+
|
|
248
|
+
let digit = BigInt.zero()
|
|
249
|
+
while (BigInt.compare(remainder, b) >= 0) {
|
|
250
|
+
remainder = BigInt.subUnsigned(remainder, b)
|
|
251
|
+
digit = BigInt.addUnsigned(digit, BigInt.fromI32(1))
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
quotient = quotient.leftShift(8)
|
|
255
|
+
quotient = BigInt.addUnsigned(quotient, digit)
|
|
256
|
+
}
|
|
257
|
+
return quotient
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Compares two BigInt values.
|
|
262
|
+
* @param a - The first BigInt to compare
|
|
263
|
+
* @param b - The second BigInt to compare
|
|
264
|
+
* @returns -1 if a < b, 0 if a == b, 1 if a > b
|
|
265
|
+
*/
|
|
266
|
+
static compare(a: BigInt, b: BigInt): i32 {
|
|
267
|
+
const aIsNeg = a.length > 0 && a[a.length - 1] >> 7 == 1
|
|
268
|
+
const bIsNeg = b.length > 0 && b[b.length - 1] >> 7 == 1
|
|
269
|
+
if (!aIsNeg && bIsNeg) return 1
|
|
270
|
+
if (aIsNeg && !bIsNeg) return -1
|
|
271
|
+
|
|
272
|
+
let aRelevantBytes = a.length
|
|
273
|
+
while (
|
|
274
|
+
aRelevantBytes > 0 &&
|
|
275
|
+
((!aIsNeg && a[aRelevantBytes - 1] == 0) || (aIsNeg && a[aRelevantBytes - 1] == 255))
|
|
276
|
+
) {
|
|
277
|
+
aRelevantBytes -= 1
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let bRelevantBytes = b.length
|
|
281
|
+
while (
|
|
282
|
+
bRelevantBytes > 0 &&
|
|
283
|
+
((!bIsNeg && b[bRelevantBytes - 1] == 0) || (bIsNeg && b[bRelevantBytes - 1] == 255))
|
|
284
|
+
) {
|
|
285
|
+
bRelevantBytes -= 1
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (aRelevantBytes > bRelevantBytes) return aIsNeg ? -1 : 1
|
|
289
|
+
if (bRelevantBytes > aRelevantBytes) return aIsNeg ? 1 : -1
|
|
290
|
+
|
|
291
|
+
const relevantBytes = aRelevantBytes
|
|
292
|
+
for (let i = 1; i <= relevantBytes; i++) {
|
|
293
|
+
if (a[relevantBytes - i] < b[relevantBytes - i]) return -1
|
|
294
|
+
if (a[relevantBytes - i] > b[relevantBytes - i]) return 1
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return 0
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Checks if this BigInt represents a negative number.
|
|
302
|
+
* @returns True if the number is negative, false otherwise
|
|
303
|
+
*/
|
|
304
|
+
isNegative(): boolean {
|
|
305
|
+
return this.length > 0 && (this[this.length - 1] & 0x80) == 0x80
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Checks if this BigInt represents zero.
|
|
310
|
+
* @returns True if the number is zero, false otherwise
|
|
311
|
+
*/
|
|
312
|
+
isZero(): boolean {
|
|
313
|
+
if (this.length == 0) return true
|
|
314
|
+
for (let i = 0; i < this.length; i++) if (this[i] !== 0) return false
|
|
315
|
+
return true
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Checks if this BigInt can fit within the range of a signed 32-bit integer.
|
|
320
|
+
* @returns True if the value fits in i32 range, false otherwise
|
|
321
|
+
*/
|
|
322
|
+
isI32(): boolean {
|
|
323
|
+
return BigInt.fromI32(i32.MIN_VALUE) <= this && this <= BigInt.fromI32(i32.MAX_VALUE)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Tells the absolute value of this BigInt.
|
|
328
|
+
* @returns A new BigInt representing the absolute value
|
|
329
|
+
*/
|
|
330
|
+
abs(): BigInt {
|
|
331
|
+
return this.isNegative() ? this.neg() : this
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Raises this BigInt to the power of the given exponent.
|
|
336
|
+
* @param exp - The exponent (unsigned 8-bit integer)
|
|
337
|
+
* @returns A new BigInt representing this^exp
|
|
338
|
+
*/
|
|
339
|
+
pow(exp: u8): BigInt {
|
|
340
|
+
if (exp === 0) return BigInt.fromI32(1)
|
|
341
|
+
if (exp === 1) return this.clone()
|
|
342
|
+
if (exp === 2) return this.times(this)
|
|
343
|
+
|
|
344
|
+
let base = this.clone()
|
|
345
|
+
let e = exp
|
|
346
|
+
let result = BigInt.fromI32(1)
|
|
347
|
+
|
|
348
|
+
while (e > 0) {
|
|
349
|
+
if ((e & 1) == 1) result = result.times(base)
|
|
350
|
+
base = base.times(base)
|
|
351
|
+
e >>= 1
|
|
352
|
+
}
|
|
353
|
+
return result
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Multiplies this BigInt by 10^precision (moves decimal point right).
|
|
358
|
+
* @param precision - Number of decimal places to scale up
|
|
359
|
+
* @returns A new BigInt scaled up by the specified precision
|
|
360
|
+
*/
|
|
361
|
+
upscale(precision: u8): BigInt {
|
|
362
|
+
return this.times(BigInt.fromI32(10).pow(precision))
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Divides this BigInt by 10^precision (moves decimal point left).
|
|
367
|
+
* @param precision - Number of decimal places to scale down
|
|
368
|
+
* @returns A new BigInt scaled down by the specified precision
|
|
369
|
+
*/
|
|
370
|
+
downscale(precision: u8): BigInt {
|
|
371
|
+
return this.div(BigInt.fromI32(10).pow(precision))
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Creates a deep copy of this BigInt.
|
|
376
|
+
* @returns A new BigInt instance with the same value
|
|
377
|
+
*/
|
|
378
|
+
clone(): BigInt {
|
|
379
|
+
const clone = new BigInt(this.length)
|
|
380
|
+
memory.copy(clone.dataStart, this.dataStart, this.length)
|
|
381
|
+
return clone
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Creates a new BigInt from a portion of this BigInt's byte array.
|
|
386
|
+
* @param start - Starting index (inclusive)
|
|
387
|
+
* @param end - Ending index (exclusive)
|
|
388
|
+
* @returns A new BigInt containing the specified byte range
|
|
389
|
+
*/
|
|
390
|
+
subarray(start: i32, end: i32): BigInt {
|
|
391
|
+
const length = end - start
|
|
392
|
+
const result = new BigInt(length)
|
|
393
|
+
memory.copy(result.dataStart, this.dataStart + start, length)
|
|
394
|
+
return result
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Adds another BigInt to this BigInt.
|
|
399
|
+
* @param other - The BigInt to add
|
|
400
|
+
* @returns A new BigInt representing the sum
|
|
401
|
+
*/
|
|
402
|
+
@operator('+')
|
|
403
|
+
plus(other: BigInt): BigInt {
|
|
404
|
+
const aIsNeg = this.isNegative()
|
|
405
|
+
const bIsNeg = other.isNegative()
|
|
406
|
+
if (aIsNeg === bIsNeg) {
|
|
407
|
+
const resultAbs = BigInt.addUnsigned(this.abs(), other.abs())
|
|
408
|
+
return aIsNeg ? resultAbs.neg() : resultAbs
|
|
409
|
+
}
|
|
410
|
+
const cmp = BigInt.compare(this.abs(), other.abs())
|
|
411
|
+
if (cmp === 0) {
|
|
412
|
+
return BigInt.zero()
|
|
413
|
+
} else if (cmp > 0) {
|
|
414
|
+
const resultAbs = BigInt.subUnsigned(this.abs(), other.abs())
|
|
415
|
+
return this.isNegative() ? resultAbs.neg() : resultAbs
|
|
416
|
+
} else {
|
|
417
|
+
const resultAbs = BigInt.subUnsigned(other.abs(), this.abs())
|
|
418
|
+
return other.isNegative() ? resultAbs.neg() : resultAbs
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Subtracts another BigInt from this BigInt.
|
|
424
|
+
* @param other - The BigInt to subtract
|
|
425
|
+
* @returns A new BigInt representing the difference
|
|
426
|
+
*/
|
|
427
|
+
@operator('-')
|
|
428
|
+
minus(other: BigInt): BigInt {
|
|
429
|
+
return this.plus(other.neg())
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Multiplies this BigInt by another BigInt.
|
|
434
|
+
* @param other - The BigInt to multiply by
|
|
435
|
+
* @returns A new BigInt representing the product
|
|
436
|
+
*/
|
|
437
|
+
@operator('*')
|
|
438
|
+
times(other: BigInt): BigInt {
|
|
439
|
+
if (other.isZero() || this.isZero()) return BigInt.zero()
|
|
440
|
+
|
|
441
|
+
if (other.length == 1) {
|
|
442
|
+
if (other[0] == 1) return this.clone()
|
|
443
|
+
if (other[0] == 2) return this.leftShift(1)
|
|
444
|
+
if (other[0] == 4) return this.leftShift(2)
|
|
445
|
+
if (other[0] == 8) return this.leftShift(3)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const aIsNeg = this.isNegative()
|
|
449
|
+
const bIsNeg = other.isNegative()
|
|
450
|
+
const signIsNeg = (aIsNeg && !bIsNeg) || (!aIsNeg && bIsNeg)
|
|
451
|
+
const resultAbs = BigInt.mulUnsigned(this.abs(), other.abs())
|
|
452
|
+
return signIsNeg ? resultAbs.neg() : resultAbs
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Divides this BigInt by another BigInt.
|
|
457
|
+
* @param other - The BigInt to divide by (cannot be zero)
|
|
458
|
+
* @returns A new BigInt representing the quotient
|
|
459
|
+
*/
|
|
460
|
+
@operator('/')
|
|
461
|
+
div(other: BigInt): BigInt {
|
|
462
|
+
assert(!other.isZero(), 'Trying to divide by zero')
|
|
463
|
+
const aIsNeg = this.isNegative()
|
|
464
|
+
const bIsNeg = other.isNegative()
|
|
465
|
+
const signIsNeg = (aIsNeg && !bIsNeg) || (!aIsNeg && bIsNeg)
|
|
466
|
+
const resultAbs = BigInt.divUnsigned(this.abs(), other.abs())
|
|
467
|
+
return signIsNeg ? resultAbs.neg() : resultAbs
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Calculates the remainder when dividing this BigInt by another BigInt.
|
|
472
|
+
* @param other - The BigInt to divide by (cannot be zero)
|
|
473
|
+
* @returns A new BigInt representing the remainder
|
|
474
|
+
*/
|
|
475
|
+
@operator('%')
|
|
476
|
+
mod(other: BigInt): BigInt {
|
|
477
|
+
assert(!other.isZero(), '')
|
|
478
|
+
return this.minus(this.div(other).times(other))
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Checks if this BigInt is equal to another BigInt.
|
|
483
|
+
* @param other - The BigInt to compare with
|
|
484
|
+
* @returns True if both BigInts have the same value
|
|
485
|
+
*/
|
|
486
|
+
@operator('==')
|
|
487
|
+
equals(other: BigInt): boolean {
|
|
488
|
+
return BigInt.compare(this, other) == 0
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Checks if this BigInt is not equal to another BigInt.
|
|
493
|
+
* @param other - The BigInt to compare with
|
|
494
|
+
* @returns True if the BigInts have different values
|
|
495
|
+
*/
|
|
496
|
+
@operator('!=')
|
|
497
|
+
notEqual(other: BigInt): boolean {
|
|
498
|
+
return !(this == other)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Checks if this BigInt is less than another BigInt.
|
|
503
|
+
* @param other - The BigInt to compare with
|
|
504
|
+
* @returns True if this BigInt is smaller
|
|
505
|
+
*/
|
|
506
|
+
@operator('<')
|
|
507
|
+
lt(other: BigInt): boolean {
|
|
508
|
+
return BigInt.compare(this, other) == -1
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Checks if this BigInt is greater than another BigInt.
|
|
513
|
+
* @param other - The BigInt to compare with
|
|
514
|
+
* @returns True if this BigInt is larger
|
|
515
|
+
*/
|
|
516
|
+
@operator('>')
|
|
517
|
+
gt(other: BigInt): boolean {
|
|
518
|
+
return BigInt.compare(this, other) == 1
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Checks if this BigInt is less than or equal to another BigInt.
|
|
523
|
+
* @param other - The BigInt to compare with
|
|
524
|
+
* @returns True if this BigInt is smaller or equal
|
|
525
|
+
*/
|
|
526
|
+
@operator('<=')
|
|
527
|
+
le(other: BigInt): boolean {
|
|
528
|
+
return !(this > other)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Checks if this BigInt is greater than or equal to another BigInt.
|
|
533
|
+
* @param other - The BigInt to compare with
|
|
534
|
+
* @returns True if this BigInt is larger or equal
|
|
535
|
+
*/
|
|
536
|
+
@operator('>=')
|
|
537
|
+
ge(other: BigInt): boolean {
|
|
538
|
+
return !(this < other)
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Tells the negation (opposite sign) of this BigInt.
|
|
543
|
+
* @returns A new BigInt with the opposite sign
|
|
544
|
+
*/
|
|
545
|
+
@operator.prefix('-')
|
|
546
|
+
neg(): BigInt {
|
|
547
|
+
const result = new BigInt(this.length)
|
|
548
|
+
for (let i = 0; i < this.length; i++) {
|
|
549
|
+
result[i] = ~this[i]
|
|
550
|
+
}
|
|
551
|
+
let carry: u32 = 1
|
|
552
|
+
for (let i = 0; i < result.length && carry != 0; i++) {
|
|
553
|
+
const sum = <u32>result[i] + carry
|
|
554
|
+
result[i] = <u8>(sum & 0xff)
|
|
555
|
+
carry = sum >> 8
|
|
556
|
+
}
|
|
557
|
+
return result
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Performs a bitwise OR operation with another BigInt.
|
|
562
|
+
* @param other - The BigInt to perform bitwise OR with
|
|
563
|
+
* @returns A new BigInt representing the bitwise OR result
|
|
564
|
+
*/
|
|
565
|
+
@operator('|')
|
|
566
|
+
bitOr(other: BigInt): BigInt {
|
|
567
|
+
const maxLen = max(this.length, other.length)
|
|
568
|
+
const result = new BigInt(maxLen)
|
|
569
|
+
for (let i = 0; i < maxLen; i++) {
|
|
570
|
+
const aByte = i < this.length ? this[i] : this.isNegative() ? 0xff : 0x00
|
|
571
|
+
const bByte = i < other.length ? other[i] : other.isNegative() ? 0xff : 0x00
|
|
572
|
+
result[i] = aByte | bByte
|
|
573
|
+
}
|
|
574
|
+
return result
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Performs a bitwise AND operation with another BigInt.
|
|
579
|
+
* @param other - The BigInt to perform bitwise AND with
|
|
580
|
+
* @returns A new BigInt representing the bitwise AND result
|
|
581
|
+
*/
|
|
582
|
+
@operator('&')
|
|
583
|
+
bitAnd(other: BigInt): BigInt {
|
|
584
|
+
const maxLen = max(this.length, other.length)
|
|
585
|
+
const result = new BigInt(maxLen)
|
|
586
|
+
for (let i = 0; i < maxLen; i++) {
|
|
587
|
+
const aByte = i < this.length ? this[i] : this.isNegative() ? 0xff : 0x00
|
|
588
|
+
const bByte = i < other.length ? other[i] : other.isNegative() ? 0xff : 0x00
|
|
589
|
+
result[i] = aByte & bByte
|
|
590
|
+
}
|
|
591
|
+
return result
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Shifts this BigInt left by the specified number of bits.
|
|
596
|
+
* @param bits - Number of bits to shift left
|
|
597
|
+
* @returns A new BigInt shifted left (equivalent to multiplying by 2^bits)
|
|
598
|
+
*/
|
|
599
|
+
@operator('<<')
|
|
600
|
+
leftShift(bits: u8): BigInt {
|
|
601
|
+
if (bits == 0) return this
|
|
602
|
+
const byteShift = bits / 8
|
|
603
|
+
const bitShift = bits % 8
|
|
604
|
+
const newLen = this.length + <i32>byteShift + 1
|
|
605
|
+
const result = new BigInt(newLen)
|
|
606
|
+
let carry = 0
|
|
607
|
+
for (let i = 0; i < this.length; i++) {
|
|
608
|
+
const cur = (this[i] << bitShift) | carry
|
|
609
|
+
result[i + byteShift] = <u8>(cur & 0xff)
|
|
610
|
+
carry = (cur >> 8) & 0xff
|
|
611
|
+
}
|
|
612
|
+
if (carry != 0) {
|
|
613
|
+
result[this.length + byteShift] = <u8>carry
|
|
614
|
+
}
|
|
615
|
+
return result
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Shifts this BigInt right by the specified number of bits.
|
|
620
|
+
* @param bits - Number of bits to shift right
|
|
621
|
+
* @returns A new BigInt shifted right (equivalent to dividing by 2^bits)
|
|
622
|
+
*/
|
|
623
|
+
@operator('>>')
|
|
624
|
+
rightShift(bits: u8): BigInt {
|
|
625
|
+
if (bits == 0) return this
|
|
626
|
+
|
|
627
|
+
const byteShift = (bits >> 3) as i32
|
|
628
|
+
const bitShift = bits & 0b111
|
|
629
|
+
const negative = this.isNegative()
|
|
630
|
+
const result = new BigInt(this.length)
|
|
631
|
+
|
|
632
|
+
if (byteShift >= this.length) {
|
|
633
|
+
for (let i = 0; i < this.length; i++) {
|
|
634
|
+
result[i] = negative ? 0xff : 0x00
|
|
635
|
+
}
|
|
636
|
+
return result
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
let carry: u16 = 0
|
|
640
|
+
for (let i = this.length - 1; i >= 0; i--) {
|
|
641
|
+
let cur = <u16>(this[i] & 0xff)
|
|
642
|
+
|
|
643
|
+
if (negative && i == this.length - 1) {
|
|
644
|
+
cur |= 0xff00
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
cur |= carry << 8
|
|
648
|
+
carry = cur & ((1 << bitShift) - 1)
|
|
649
|
+
cur = cur >> bitShift
|
|
650
|
+
const pos = i - byteShift
|
|
651
|
+
|
|
652
|
+
if (pos >= 0) {
|
|
653
|
+
result[pos] = <u8>(cur & 0xff)
|
|
654
|
+
}
|
|
655
|
+
if (i == 0) break
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
for (let i = this.length - 1; i >= this.length - byteShift; i--) {
|
|
659
|
+
if (i >= 0 && i < result.length) {
|
|
660
|
+
result[i] = negative ? 0xff : 0x00
|
|
661
|
+
}
|
|
662
|
+
if (i == 0) break
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return result
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Converts this BigInt to a Bytes representation.
|
|
670
|
+
* @returns A new Bytes instance containing the raw byte data
|
|
671
|
+
*/
|
|
672
|
+
toBytes(): Bytes {
|
|
673
|
+
return Bytes.fromUint8Array(changetype<Uint8Array>(this))
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Converts this BigInt to a signed 32-bit integer.
|
|
678
|
+
* @returns The i32 representation (behavior undefined if value doesn't fit)
|
|
679
|
+
*/
|
|
680
|
+
toI32(): i32 {
|
|
681
|
+
const byteArray = this.toBytes()
|
|
682
|
+
return byteArray.toI32()
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Converts this BigInt to an unsigned 32-bit integer.
|
|
687
|
+
* @returns The u32 representation (behavior undefined if value doesn't fit)
|
|
688
|
+
*/
|
|
689
|
+
toU32(): u32 {
|
|
690
|
+
const byteArray = this.toBytes()
|
|
691
|
+
return byteArray.toU32()
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Converts this BigInt to a signed 64-bit integer.
|
|
696
|
+
* @returns The i64 representation (behavior undefined if value doesn't fit)
|
|
697
|
+
*/
|
|
698
|
+
toI64(): i64 {
|
|
699
|
+
const byteArray = this.toBytes()
|
|
700
|
+
return byteArray.toI64()
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Converts this BigInt to an unsigned 64-bit integer.
|
|
705
|
+
* @returns The u64 representation (behavior undefined if value doesn't fit)
|
|
706
|
+
*/
|
|
707
|
+
toU64(): u64 {
|
|
708
|
+
const byteArray = this.toBytes()
|
|
709
|
+
return byteArray.toU64()
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Converts this BigInt to a hexadecimal string representation.
|
|
714
|
+
* @returns Hex string with '0x' prefix, or '0x' for zero
|
|
715
|
+
*/
|
|
716
|
+
toHexString(): string {
|
|
717
|
+
if (this.isZero()) return '0x'
|
|
718
|
+
const abs = this.isNegative() ? this.neg() : this
|
|
719
|
+
let end = abs.length
|
|
720
|
+
while (end > 1 && abs[end - 1] === 0) end--
|
|
721
|
+
const trimmed = abs.subarray(0, end)
|
|
722
|
+
const hex = bytesToHexString(trimmed)
|
|
723
|
+
return this.isNegative() ? '-' + hex : hex
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Converts this BigInt to a decimal string representation.
|
|
728
|
+
* @returns Decimal string representation of the number
|
|
729
|
+
*/
|
|
730
|
+
toString(): string {
|
|
731
|
+
if (this.isZero()) return '0'
|
|
732
|
+
|
|
733
|
+
let absValue = this.isNegative() ? this.neg() : this.clone()
|
|
734
|
+
const digits = new Array<i32>()
|
|
735
|
+
while (!absValue.isZero()) {
|
|
736
|
+
let carry = 0
|
|
737
|
+
|
|
738
|
+
for (let i = absValue.length - 1; i >= 0; i--) {
|
|
739
|
+
const current = (carry << 8) + absValue[i]
|
|
740
|
+
absValue[i] = <u8>(current / 10)
|
|
741
|
+
carry = current % 10
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
digits.push(ZERO_ASCII + carry)
|
|
745
|
+
|
|
746
|
+
while (absValue.length > 1 && absValue[absValue.length - 1] == 0) {
|
|
747
|
+
absValue = absValue.subarray(0, absValue.length - 1)
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
if (this.isNegative()) digits.push('-'.charCodeAt(0))
|
|
752
|
+
digits.reverse()
|
|
753
|
+
return String.fromCharCodes(digits)
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Converts this BigInt to a decimal string with specified precision.
|
|
758
|
+
* @param precision - Number of decimal places to format
|
|
759
|
+
* @returns Decimal string with the specified precision, trailing zeros removed
|
|
760
|
+
*/
|
|
761
|
+
toStringDecimal(precision: u8): string {
|
|
762
|
+
if (this.isZero()) return '0'
|
|
763
|
+
|
|
764
|
+
const isNegative = this.isNegative()
|
|
765
|
+
const absAmount = this.abs()
|
|
766
|
+
|
|
767
|
+
const str = absAmount.toString()
|
|
768
|
+
if (str.length <= (precision as i32)) {
|
|
769
|
+
let decimalPart = str.padStart(precision, '0')
|
|
770
|
+
|
|
771
|
+
let lastNonZero = decimalPart.length - 1
|
|
772
|
+
while (lastNonZero >= 0 && decimalPart.charCodeAt(lastNonZero) === ZERO_ASCII) lastNonZero--
|
|
773
|
+
|
|
774
|
+
decimalPart = decimalPart.substring(0, lastNonZero + 1)
|
|
775
|
+
return (isNegative ? '-' : '') + '0' + (decimalPart.length ? '.' + decimalPart : '')
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const wholePart = str.slice(0, str.length - precision)
|
|
779
|
+
let decimalPart = str.slice(str.length - precision)
|
|
780
|
+
|
|
781
|
+
// Remove trailing zeros manually
|
|
782
|
+
let lastNonZero = decimalPart.length - 1
|
|
783
|
+
while (lastNonZero >= 0 && decimalPart.charCodeAt(lastNonZero) === ZERO_ASCII) lastNonZero--
|
|
784
|
+
|
|
785
|
+
decimalPart = decimalPart.substring(0, lastNonZero + 1)
|
|
786
|
+
|
|
787
|
+
// If the decimal part is empty, return only the whole part
|
|
788
|
+
return decimalPart.length > 0
|
|
789
|
+
? `${isNegative ? '-' : ''}${wholePart}.${decimalPart}`
|
|
790
|
+
: `${isNegative ? '-' : ''}${wholePart}`
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
serialize(): string {
|
|
794
|
+
return `${BigInt.SERIALIZED_PREFIX}(${this.toString()})`
|
|
795
|
+
}
|
|
796
|
+
}
|