@btc-vision/btc-runtime 1.3.19 → 1.3.21
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/package.json
CHANGED
|
@@ -12,10 +12,11 @@ import { Revert } from '../types/Revert';
|
|
|
12
12
|
import { SafeMath } from '../types/SafeMath';
|
|
13
13
|
|
|
14
14
|
import { Calldata } from '../types';
|
|
15
|
-
import { BOOLEAN_BYTE_LENGTH, U256_BYTE_LENGTH } from '../utils
|
|
15
|
+
import { ADDRESS_BYTE_LENGTH, BOOLEAN_BYTE_LENGTH, U256_BYTE_LENGTH } from '../utils';
|
|
16
16
|
import { IOP_20 } from './interfaces/IOP_20';
|
|
17
17
|
import { OP20InitParameters } from './interfaces/OP20InitParameters';
|
|
18
18
|
import { OP_NET } from './OP_NET';
|
|
19
|
+
import { sha256 } from '../env/global';
|
|
19
20
|
|
|
20
21
|
const maxSupplyPointer: u16 = Blockchain.nextPointer;
|
|
21
22
|
const decimalsPointer: u16 = Blockchain.nextPointer;
|
|
@@ -124,6 +125,23 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
124
125
|
return response;
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
public approveFrom(callData: Calldata): BytesWriter {
|
|
129
|
+
const response = new BytesWriter(BOOLEAN_BYTE_LENGTH);
|
|
130
|
+
const owner: Address = Blockchain.tx.origin;
|
|
131
|
+
const spender: Address = callData.readAddress();
|
|
132
|
+
const value: u256 = callData.readU256();
|
|
133
|
+
|
|
134
|
+
const signature = callData.readBytesWithLength();
|
|
135
|
+
if (signature.length !== 64) {
|
|
136
|
+
throw new Revert('Invalid signature length');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const resp = this._approveFrom(owner, spender, value, signature);
|
|
140
|
+
response.writeBoolean(resp);
|
|
141
|
+
|
|
142
|
+
return response;
|
|
143
|
+
}
|
|
144
|
+
|
|
127
145
|
public balanceOf(callData: Calldata): BytesWriter {
|
|
128
146
|
const response = new BytesWriter(U256_BYTE_LENGTH);
|
|
129
147
|
const address: Address = callData.readAddress();
|
|
@@ -192,6 +210,8 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
192
210
|
return this.allowance(calldata);
|
|
193
211
|
case encodeSelector('approve'):
|
|
194
212
|
return this.approve(calldata);
|
|
213
|
+
case encodeSelector('approveFrom'):
|
|
214
|
+
return this.approveFrom(calldata);
|
|
195
215
|
case encodeSelector('balanceOf'):
|
|
196
216
|
return this.balanceOf(calldata);
|
|
197
217
|
case encodeSelector('burn'):
|
|
@@ -214,6 +234,34 @@ export abstract class DeployableOP_20 extends OP_NET implements IOP_20 {
|
|
|
214
234
|
return senderMap.get(spender);
|
|
215
235
|
}
|
|
216
236
|
|
|
237
|
+
protected _approveFrom(owner: Address, spender: Address, value: u256, signature: Uint8Array): boolean {
|
|
238
|
+
if (owner === Blockchain.DEAD_ADDRESS) {
|
|
239
|
+
throw new Revert('Address can not be dead address');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (spender === Blockchain.DEAD_ADDRESS) {
|
|
243
|
+
throw new Revert('Spender cannot be dead address');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Regenerate the hash
|
|
247
|
+
const writer = new BytesWriter(ADDRESS_BYTE_LENGTH * 2 + U256_BYTE_LENGTH);
|
|
248
|
+
writer.writeAddress(owner);
|
|
249
|
+
writer.writeAddress(spender);
|
|
250
|
+
writer.writeU256(value);
|
|
251
|
+
|
|
252
|
+
const hash = sha256(writer.getBuffer());
|
|
253
|
+
if (!Blockchain.verifySchnorrSignature(owner, signature, hash)) {
|
|
254
|
+
throw new Revert('ApproveFrom: Invalid signature');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const senderMap = this.allowanceMap.get(owner);
|
|
258
|
+
senderMap.set(spender, value);
|
|
259
|
+
|
|
260
|
+
this.createApproveEvent(owner, spender, value);
|
|
261
|
+
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
|
|
217
265
|
protected _approve(owner: Address, spender: Address, value: u256): boolean {
|
|
218
266
|
if (owner === Blockchain.DEAD_ADDRESS) {
|
|
219
267
|
throw new Revert('Address can not be dead address');
|
|
@@ -391,6 +391,139 @@ export class SafeMath {
|
|
|
391
391
|
return n;
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
+
public static bitLength256(x: u256): u32 {
|
|
395
|
+
// If zero => bitlength is 0
|
|
396
|
+
if (u256.eq(x, u256.Zero)) {
|
|
397
|
+
return 0;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// hi2 != 0 => top 64 bits => bit positions 192..255
|
|
401
|
+
if (x.hi2 != 0) {
|
|
402
|
+
const partial: u32 = SafeMath.bitLength64(x.hi2);
|
|
403
|
+
return 192 + partial;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// hi1 != 0 => next 64 bits => bit positions 128..191
|
|
407
|
+
if (x.hi1 != 0) {
|
|
408
|
+
const partial: u32 = SafeMath.bitLength64(x.hi1);
|
|
409
|
+
return 128 + partial;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// lo2 != 0 => next 64 bits => bit positions 64..127
|
|
413
|
+
if (x.lo2 != 0) {
|
|
414
|
+
const partial: u32 = SafeMath.bitLength64(x.lo2);
|
|
415
|
+
return 64 + partial;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// else in lo1 => bit positions 0..63
|
|
419
|
+
return SafeMath.bitLength64(x.lo1);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
public static approxLog(x: u256): u256 {
|
|
423
|
+
// If x == 0 or x == 1, return 0 (ln(1)=0, ln(0) is undefined but we treat as 0)
|
|
424
|
+
if (x.isZero() || u256.eq(x, u256.One)) {
|
|
425
|
+
return u256.Zero;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// 1) Find bit length
|
|
429
|
+
const bitLen: u32 = SafeMath.bitLength256(x);
|
|
430
|
+
// if bitLen=0 or 1 => that implies x <=1, but we already handled x=0,1 => just safe-check
|
|
431
|
+
if (bitLen <= 1) {
|
|
432
|
+
return u256.Zero;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// 2) ln(x) ~ (bitLen - 1) * ln(2)
|
|
436
|
+
// We'll store ln(2) in a scaled integer. e.g., LN2_SCALED = 693147 => ln(2)*1e6
|
|
437
|
+
const LN2_SCALED: u64 = 693147; // approximate ln(2)*1e6
|
|
438
|
+
const log2Count: u64 = (bitLen - 1) as u64; // integer part of log2(x)
|
|
439
|
+
|
|
440
|
+
// Multiply in pure integer
|
|
441
|
+
return SafeMath.mul(u256.fromU64(log2Count), u256.fromU64(LN2_SCALED));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Return ln(x) * 1e6 for x>1. If x==0 or 1, returns 0.
|
|
446
|
+
* Uses: ln(x) = (k * ln(2)) + ln(1 + r),
|
|
447
|
+
* where k = floor(log2(x)) and r = (x - 2^k)/2^k
|
|
448
|
+
*/
|
|
449
|
+
@unsafe // UNTESTED.
|
|
450
|
+
public static preciseLog(x: u256): u256 {
|
|
451
|
+
if (x.isZero() || u256.eq(x, u256.One)) {
|
|
452
|
+
return u256.Zero;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const bitLen = SafeMath.bitLength256(x);
|
|
456
|
+
if (bitLen <= 1) {
|
|
457
|
+
return u256.Zero;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// integer part of log2(x)
|
|
461
|
+
const k: u32 = bitLen - 1;
|
|
462
|
+
const LN2_SCALED = u256.fromU64(693147); // ln(2)*1e6
|
|
463
|
+
const base: u256 = SafeMath.mul(u256.fromU32(k), LN2_SCALED);
|
|
464
|
+
|
|
465
|
+
// 2^k
|
|
466
|
+
const pow2k = SafeMath.shl(u256.One, <i32>k);
|
|
467
|
+
const xPrime = SafeMath.sub(x, pow2k); // leftover
|
|
468
|
+
|
|
469
|
+
if (xPrime.isZero()) {
|
|
470
|
+
// x was exactly 2^k => no fractional part
|
|
471
|
+
return base;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// rScaled = ((x - 2^k)*1e6)/2^k
|
|
475
|
+
const xPrimeTimes1e6 = SafeMath.mul(xPrime, u256.fromU64(1_000_000));
|
|
476
|
+
const rScaled = SafeMath.div(xPrimeTimes1e6, pow2k); // 0..999999
|
|
477
|
+
|
|
478
|
+
// approximate ln(1 + r)
|
|
479
|
+
const frac: u64 = SafeMath.polyLn1p3(rScaled.toU64());
|
|
480
|
+
|
|
481
|
+
return SafeMath.add(base, u256.fromU64(frac));
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
public static pow10(exponent: u8): u256 {
|
|
485
|
+
let result: u256 = u256.One;
|
|
486
|
+
for (let i: u8 = 0; i < exponent; i++) {
|
|
487
|
+
result = SafeMath.mul(result, u256.fromU32(10));
|
|
488
|
+
}
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* polyLn1p3: 3-term polynomial for ln(1 + z), with z in [0,1).
|
|
494
|
+
* rScaled = z * 1e6
|
|
495
|
+
* returns (ln(1+z)) in scale=1e6
|
|
496
|
+
*/
|
|
497
|
+
// UNTESTED.
|
|
498
|
+
@unsafe
|
|
499
|
+
public static polyLn1p3(rScaled: u64): u64 {
|
|
500
|
+
// term1 = z
|
|
501
|
+
const term1: u64 = rScaled;
|
|
502
|
+
|
|
503
|
+
// term2 => z^2/2
|
|
504
|
+
const z2 = term1 * term1; // up to 1e12
|
|
505
|
+
const z2Div = (z2 / 1_000_000) >>> 1; // divide by scale and by 2
|
|
506
|
+
|
|
507
|
+
// term3 => z^3/3
|
|
508
|
+
const z3 = z2 * term1; // up to 1e18
|
|
509
|
+
const z3Div = z3 / (1_000_000 * 1_000_000) / 3; // => scale
|
|
510
|
+
|
|
511
|
+
// ln(1+z) ~ z - z^2/2 + z^3/3
|
|
512
|
+
return term1 - z2Div + z3Div;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
private static bitLength64(value: u64): u32 {
|
|
516
|
+
if (value == 0) return 0;
|
|
517
|
+
|
|
518
|
+
let count: u32 = 0;
|
|
519
|
+
let temp = value;
|
|
520
|
+
while (temp > 0) {
|
|
521
|
+
temp >>>= 1; // logical shift right
|
|
522
|
+
count++;
|
|
523
|
+
}
|
|
524
|
+
return count;
|
|
525
|
+
}
|
|
526
|
+
|
|
394
527
|
private static shlSegment(
|
|
395
528
|
segments: u64[],
|
|
396
529
|
segmentShift: i32,
|
|
@@ -411,12 +544,4 @@ export class SafeMath {
|
|
|
411
544
|
|
|
412
545
|
return result;
|
|
413
546
|
}
|
|
414
|
-
|
|
415
|
-
public static pow10(exponent: u8): u256 {
|
|
416
|
-
let result: u256 = u256.One;
|
|
417
|
-
for (let i: u8 = 0; i < exponent; i++) {
|
|
418
|
-
result = SafeMath.mul(result, u256.fromU32(10));
|
|
419
|
-
}
|
|
420
|
-
return result;
|
|
421
|
-
}
|
|
422
547
|
}
|