@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.
@@ -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
+ }