@btc-vision/btc-runtime 1.9.0 → 1.9.2

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 (31) hide show
  1. package/package.json +13 -4
  2. package/runtime/constants/Exports.ts +86 -0
  3. package/runtime/contracts/OP1155.ts +1042 -0
  4. package/runtime/contracts/OP20.ts +64 -38
  5. package/runtime/contracts/OP721.ts +882 -0
  6. package/runtime/contracts/OP_NET.ts +5 -0
  7. package/runtime/contracts/ReentrancyGuard.ts +136 -0
  8. package/runtime/contracts/interfaces/IOP1155.ts +33 -0
  9. package/runtime/contracts/interfaces/IOP721.ts +29 -0
  10. package/runtime/contracts/interfaces/OP1155InitParameters.ts +11 -0
  11. package/runtime/contracts/interfaces/OP721InitParameters.ts +15 -0
  12. package/runtime/env/BlockchainEnvironment.ts +32 -3
  13. package/runtime/events/predefined/ApprovedForAll.ts +16 -0
  14. package/runtime/events/predefined/TransferredBatchEvent.ts +35 -0
  15. package/runtime/events/predefined/TransferredSingleEvent.ts +18 -0
  16. package/runtime/events/predefined/URIEvent.ts +23 -0
  17. package/runtime/events/predefined/index.ts +4 -0
  18. package/runtime/index.ts +9 -0
  19. package/runtime/math/abi.ts +23 -0
  20. package/runtime/math/bytes.ts +4 -0
  21. package/runtime/memory/AddressMemoryMap.ts +20 -0
  22. package/runtime/nested/storage/StorageMap.ts +3 -23
  23. package/runtime/nested/storage/StorageSet.ts +6 -3
  24. package/runtime/script/Script.ts +1 -1
  25. package/runtime/secp256k1/ECPoint.ts +3 -3
  26. package/runtime/shared-libraries/OP20Utils.ts +1 -2
  27. package/runtime/storage/AdvancedStoredString.ts +8 -189
  28. package/runtime/storage/BaseStoredString.ts +206 -0
  29. package/runtime/storage/StoredString.ts +15 -194
  30. package/runtime/storage/arrays/StoredPackedArray.ts +19 -5
  31. package/runtime/types/SafeMath.ts +125 -94
@@ -1,4 +1,9 @@
1
- import { bigEndianAdd, GET_EMPTY_BUFFER, readLengthAndStartIndex, writeLengthAndStartIndex, } from '../../math/bytes';
1
+ import {
2
+ bigEndianAdd,
3
+ GET_EMPTY_BUFFER,
4
+ readLengthAndStartIndex,
5
+ writeLengthAndStartIndex,
6
+ } from '../../math/bytes';
2
7
  import { Blockchain } from '../../env';
3
8
  import { Revert } from '../../types/Revert';
4
9
  import { encodePointer } from '../../math/abi';
@@ -87,7 +92,8 @@ export abstract class StoredPackedArray<T> {
87
92
  @operator('[]')
88
93
  public get(index: u32): T {
89
94
  // max length used on purpose to prevent unbounded usage
90
- if (index > this.MAX_LENGTH) {
95
+ // we allow index to be equal to MAX_LENGTH because, we allow it on the set as well.
96
+ if (index >= this.MAX_LENGTH) {
91
97
  throw new Revert('get: out of range');
92
98
  }
93
99
 
@@ -104,7 +110,7 @@ export abstract class StoredPackedArray<T> {
104
110
 
105
111
  @inline
106
112
  public get_physical(index: u32): T {
107
- if (index > this.MAX_LENGTH) {
113
+ if (index >= this.MAX_LENGTH) {
108
114
  throw new Revert('get: index exceeds MAX_LENGTH (packed array)');
109
115
  }
110
116
 
@@ -121,7 +127,7 @@ export abstract class StoredPackedArray<T> {
121
127
  @inline
122
128
  @operator('[]=')
123
129
  public set(index: u32, value: T): void {
124
- if (index > this.MAX_LENGTH) {
130
+ if (index >= this.MAX_LENGTH) {
125
131
  throw new Revert('set: index exceeds MAX_LENGTH (packed array)');
126
132
  }
127
133
 
@@ -143,7 +149,7 @@ export abstract class StoredPackedArray<T> {
143
149
 
144
150
  @inline
145
151
  public set_physical(index: u32, value: T): void {
146
- if (index > this.MAX_LENGTH) {
152
+ if (index >= this.MAX_LENGTH) {
147
153
  throw new Revert('set: index exceeds MAX_LENGTH (packed array)');
148
154
  }
149
155
 
@@ -298,6 +304,10 @@ export abstract class StoredPackedArray<T> {
298
304
  */
299
305
  @inline
300
306
  public delete_physical(index: u32): void {
307
+ if (index >= this.MAX_LENGTH) {
308
+ throw new Revert('delete: index exceeds MAX_LENGTH (packed array)');
309
+ }
310
+
301
311
  const cap = this.getSlotCapacity();
302
312
  const slotIndex = index / cap;
303
313
  const subIndex = <u32>(index % cap);
@@ -368,6 +378,10 @@ export abstract class StoredPackedArray<T> {
368
378
 
369
379
  @inline
370
380
  public setStartingIndex(index: u32): void {
381
+ if (index >= this.MAX_LENGTH) {
382
+ throw new Revert('setStartingIndex: out of range');
383
+ }
384
+
371
385
  this._startIndex = index;
372
386
  this._isChangedStartIndex = true;
373
387
  }
@@ -54,13 +54,38 @@ export class SafeMath {
54
54
  }
55
55
 
56
56
  // Computes (a * b) % modulus with full precision
57
- public static mulmod(a: u256, b: u256, modulus: u256): u256 {
57
+ /*public static mulmod(a: u256, b: u256, modulus: u256): u256 {
58
58
  if (u256.eq(modulus, u256.Zero)) throw new Revert('SafeMath: modulo by zero');
59
59
 
60
60
  const mul = SafeMath.mul(a, b);
61
61
  return SafeMath.mod(mul, modulus);
62
+ }*/ // CAN OVERFLOW!
63
+
64
+ public static mulmod(a: u256, b: u256, modulus: u256): u256 {
65
+ if (u256.eq(modulus, u256.Zero)) throw new Revert('SafeMath: modulo by zero');
66
+
67
+ // Keep invariants: 0 <= a,b < modulus
68
+ a = SafeMath.mod(a, modulus);
69
+ b = SafeMath.mod(b, modulus);
70
+ if (a.isZero() || b.isZero()) return u256.Zero;
71
+
72
+ let res = u256.Zero;
73
+
74
+ // LSB-first ladder: at most 256 iterations; all steps keep values < modulus.
75
+ while (!b.isZero()) {
76
+ if (u256.ne(u256.and(b, u256.One), u256.Zero)) {
77
+ res = SafeMath.addModNoCarry(res, a, modulus); // res = (res + a) % m, no overflow
78
+ }
79
+ b = u256.shr(b, 1);
80
+ if (!b.isZero()) {
81
+ a = SafeMath.doubleModNoCarry(a, modulus); // a = (2a) % m, no overflow
82
+ }
83
+ }
84
+ return res;
62
85
  }
63
86
 
87
+ // (x + y) % m without ever computing a potentially-overflowing x + y.
88
+
64
89
  @unsafe
65
90
  @operator('%')
66
91
  public static mod(a: u256, b: u256): u256 {
@@ -73,38 +98,89 @@ export class SafeMath {
73
98
  return SafeMath.sub(a, product);
74
99
  }
75
100
 
101
+ // (2x) % m without overflow.
102
+
76
103
  public static modInverse(k: u256, p: u256): u256 {
77
- let s = u256.Zero;
78
- let old_s = u256.One;
79
- let r = p;
80
- let old_r = k;
104
+ // Input validation
105
+ if (p.isZero() || u256.eq(p, u256.One)) {
106
+ throw new Revert('SafeMath: modulus must be > 1');
107
+ }
108
+
109
+ if (k.isZero()) {
110
+ throw new Revert('SafeMath: no inverse for zero');
111
+ }
112
+
113
+ let s: u256 = u256.Zero;
114
+ let old_s: u256 = u256.One;
115
+ let s_negative: boolean = false;
116
+ let old_s_negative: boolean = false;
117
+ let r: u256 = p.clone();
118
+ let old_r: u256 = k.clone();
81
119
 
82
120
  while (!r.isZero()) {
83
121
  const quotient = SafeMath.div(old_r, r);
84
122
 
85
- // --- Update r ---
86
- {
87
- // old_r - (quotient * r)
88
- const tmp = r;
89
- r = u256.sub(old_r, u256.mul(quotient, r)); // unchecked subtract
90
- old_r = tmp;
123
+ // Update r (always remains positive)
124
+ const tmp_r = r.clone();
125
+ r = SafeMath.sub(old_r, SafeMath.mul(quotient, r));
126
+ old_r = tmp_r;
127
+
128
+ // Update s with correct sign tracking
129
+ const tmp_s = s.clone();
130
+ const tmp_s_negative = s_negative;
131
+ const product = SafeMath.mul(quotient, s);
132
+
133
+ // Compute: old_s - (quotient * s)
134
+ // Taking into account the signs of old_s and s
135
+
136
+ if (!old_s_negative && !s_negative) {
137
+ // (+old_s) - (+product)
138
+ if (u256.ge(old_s, product)) {
139
+ s = SafeMath.sub(old_s, product);
140
+ s_negative = false;
141
+ } else {
142
+ s = SafeMath.sub(product, old_s);
143
+ s_negative = true;
144
+ }
145
+ } else if (old_s_negative && s_negative) {
146
+ // (-old_s) - (-product) = -old_s + product
147
+ if (u256.ge(product, old_s)) {
148
+ s = SafeMath.sub(product, old_s);
149
+ s_negative = false;
150
+ } else {
151
+ s = SafeMath.sub(old_s, product);
152
+ s_negative = true;
153
+ }
154
+ } else if (!old_s_negative && s_negative) {
155
+ // (+old_s) - (-product) = old_s + product
156
+ s = SafeMath.add(old_s, product);
157
+ s_negative = false;
158
+ } else {
159
+ // old_s_negative && !s_negative
160
+ // (-old_s) - (+product) = -(old_s + product)
161
+ s = SafeMath.add(old_s, product);
162
+ s_negative = true;
91
163
  }
92
164
 
93
- // --- Update s ---
94
- {
95
- // old_s - (quotient * s)
96
- const tmp = s;
97
- s = u256.sub(old_s, u256.mul(quotient, s)); // unchecked subtract
98
- old_s = tmp;
99
- }
165
+ old_s = tmp_s;
166
+ old_s_negative = tmp_s_negative;
100
167
  }
101
168
 
102
- // At this point, `old_r` is the gcd(k, p). If gcd != 1 => no inverse
103
- // (in a prime field p, gcd=1 if k != 0).
104
- // We could enforce this by checking `old_r == 1` but we'll leave it to the caller.
169
+ // Check if inverse exists (gcd must be 1)
170
+ if (!u256.eq(old_r, u256.One)) {
171
+ throw new Revert('SafeMath: no modular inverse exists');
172
+ }
173
+
174
+ // Reduce modulo p, handling negative values
175
+ if (old_s_negative) {
176
+ // For negative values: result = p - (|old_s| mod p)
177
+ const mod_result = SafeMath.mod(old_s, p);
178
+ if (mod_result.isZero()) {
179
+ return u256.Zero;
180
+ }
181
+ return SafeMath.sub(p, mod_result);
182
+ }
105
183
 
106
- // The extended Euclidean algorithm says `old_s` is the inverse (possibly negative),
107
- // so we reduce mod p
108
184
  return SafeMath.mod(old_s, p);
109
185
  }
110
186
 
@@ -126,31 +202,23 @@ export class SafeMath {
126
202
  }
127
203
 
128
204
  public static mul(a: u256, b: u256): u256 {
129
- if (a === SafeMath.ZERO || b === SafeMath.ZERO) {
130
- return SafeMath.ZERO;
131
- }
205
+ if (a.isZero() || b.isZero()) return u256.Zero;
132
206
 
133
- const c: u256 = u256.mul(a, b);
134
- const d: u256 = SafeMath.div(c, a);
207
+ const c = u256.mul(a, b);
208
+ const d = SafeMath.div(c, a);
135
209
 
136
- if (u256.ne(d, b)) {
137
- throw new Revert('SafeMath: multiplication overflow');
138
- }
210
+ if (u256.ne(d, b)) throw new Revert('SafeMath: multiplication overflow');
139
211
 
140
212
  return c;
141
213
  }
142
214
 
143
215
  public static mul128(a: u128, b: u128): u128 {
144
- if (a === u128.Zero || b === u128.Zero) {
145
- return u128.Zero;
146
- }
216
+ if (a.isZero() || b.isZero()) return u128.Zero;
147
217
 
148
- const c: u128 = u128.mul(a, b);
149
- const d: u128 = SafeMath.div128(c, a);
218
+ const c = u128.mul(a, b);
219
+ const d = SafeMath.div128(c, a);
150
220
 
151
- if (u128.ne(d, b)) {
152
- throw new Revert('SafeMath: multiplication overflow');
153
- }
221
+ if (u128.ne(d, b)) throw new Revert('SafeMath: multiplication overflow');
154
222
 
155
223
  return c;
156
224
  }
@@ -371,66 +439,12 @@ export class SafeMath {
371
439
  return u256.xor(a, b);
372
440
  }
373
441
 
374
- public static shr(a: u256, shift: i32): u256 {
375
- shift &= 255;
376
- if (shift == 0) return a;
377
-
378
- const w = shift >>> 6; // how many full 64-bit words to drop
379
- const b = shift & 63; // how many bits to shift within a word
380
-
381
- // Extract the words
382
- let lo1 = a.lo1;
383
- let lo2 = a.lo2;
384
- let hi1 = a.hi1;
385
- let hi2 = a.hi2;
386
-
387
- // Shift words down by w words
388
- // For w = 1, move lo2->lo1, hi1->lo2, hi2->hi1, and hi2 = 0
389
- // For w = 2, move hi1->lo1, hi2->lo2, and zeros in hi1, hi2
390
- // For w = 3, move hi2->lo1 and zeros in others
391
- // For w >= 4, everything is zero.
392
- if (w >= 4) {
393
- // Shifting by >= 256 bits zeros out everything
394
- return u256.Zero;
395
- } else if (w == 3) {
396
- lo1 = hi2;
397
- lo2 = 0;
398
- hi1 = 0;
399
- hi2 = 0;
400
- } else if (w == 2) {
401
- lo1 = hi1;
402
- lo2 = hi2;
403
- hi1 = 0;
404
- hi2 = 0;
405
- } else if (w == 1) {
406
- lo1 = lo2;
407
- lo2 = hi1;
408
- hi1 = hi2;
409
- hi2 = 0;
410
- }
411
-
412
- // Now apply the bit shift b
413
- if (b > 0) {
414
- // Bring down bits from the higher word
415
- const carryLo2 = hi1 << (64 - b);
416
- const carryLo1 = lo2 << (64 - b);
417
- const carryHi1 = hi2 << (64 - b);
418
-
419
- lo1 = (lo1 >>> b) | carryLo1;
420
- lo2 = (lo2 >>> b) | carryLo2;
421
- hi1 = (hi1 >>> b) | carryHi1;
422
- hi2 = hi2 >>> b;
423
- }
424
-
425
- return new u256(lo1, lo2, hi1, hi2);
426
- }
427
-
428
442
  /**
429
443
  * Increment a u256 value by 1
430
444
  * @param value The value to increment
431
445
  * @returns The incremented value
432
446
  */
433
- static inc(value: u256): u256 {
447
+ public static inc(value: u256): u256 {
434
448
  if (u256.eq(value, u256.Max)) {
435
449
  throw new Revert('SafeMath: increment overflow');
436
450
  }
@@ -451,6 +465,11 @@ export class SafeMath {
451
465
  return value.preDec();
452
466
  }
453
467
 
468
+ @inline
469
+ public static shr(value: u256, shift: i32): u256 {
470
+ return u256.shr(value, shift);
471
+ }
472
+
454
473
  /**
455
474
  * Approximates the binary logarithm (log2) of a u256 integer.
456
475
  * @param x - The input value for which to calculate log2(x).
@@ -591,6 +610,18 @@ export class SafeMath {
591
610
  return term1 - z2Div + z3Div;
592
611
  }
593
612
 
613
+ // Pre: 0 <= x,y < m, m > 0.
614
+ private static addModNoCarry(x: u256, y: u256, m: u256): u256 {
615
+ const mMinusY = SafeMath.sub(m, y); // safe since y < m
616
+ return u256.ge(x, mMinusY) ? SafeMath.sub(x, mMinusY) : SafeMath.add(x, y);
617
+ }
618
+
619
+ // Pre: 0 <= x < m, m > 0.
620
+ private static doubleModNoCarry(x: u256, m: u256): u256 {
621
+ const mMinusX = SafeMath.sub(m, x); // safe since x < m
622
+ return u256.ge(x, mMinusX) ? SafeMath.sub(x, mMinusX) : SafeMath.add(x, x);
623
+ }
624
+
594
625
  private static bitLength64(value: u64): u32 {
595
626
  if (value == 0) return 0;
596
627