@btc-vision/btc-runtime 1.9.10 → 1.9.12
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
|
@@ -14,7 +14,7 @@ export const ALLOWANCE_DECREASE_TYPE_HASH: u8[] = [
|
|
|
14
14
|
];
|
|
15
15
|
|
|
16
16
|
// onOP721Received(address,address,uint256,bytes)
|
|
17
|
-
export const ON_OP721_RECEIVED_SELECTOR: u32 =
|
|
17
|
+
export const ON_OP721_RECEIVED_SELECTOR: u32 = 0x5349f6de;
|
|
18
18
|
|
|
19
19
|
// onOP1155Received(address,address,uint256,uint256,bytes)
|
|
20
20
|
export const ON_OP1155_RECEIVED_MAGIC: u32 = 0xcedc9fdf;
|
|
@@ -61,10 +61,10 @@ export const OP712_VERSION_HASH: u8[] = [
|
|
|
61
61
|
0x47, 0xad, 0xa4, 0xea, 0xa2, 0x2f, 0x1d, 0x49, 0xc0, 0x1e, 0x52, 0xdd, 0xb7, 0x87, 0x5b, 0x4b,
|
|
62
62
|
];
|
|
63
63
|
|
|
64
|
-
// sha256("
|
|
65
|
-
export const
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
// sha256("OP721Approval(address owner,address spender,uint256 tokenId,uint256 nonce,uint64 deadline)")
|
|
65
|
+
export const OP721_APPROVAL_TYPE_HASH: u8[] = [
|
|
66
|
+
0xb8, 0x6e, 0x99, 0xda, 0xc0, 0x47, 0x4b, 0x4a, 0x9f, 0xc3, 0x32, 0x3a, 0xd6, 0xed, 0x2f, 0x39,
|
|
67
|
+
0x55, 0xe7, 0xb8, 0x6d, 0xc6, 0x8c, 0x62, 0x42, 0x82, 0x1c, 0xbc, 0xac, 0xa2, 0xd8, 0x79, 0xde
|
|
68
68
|
];
|
|
69
69
|
|
|
70
70
|
// sha256("OP721Transfer(address from,address to,uint256 tokenId,uint256 nonce,uint64 deadline)")
|
|
@@ -214,6 +214,37 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
214
214
|
return w;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
@method(
|
|
218
|
+
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
219
|
+
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
220
|
+
)
|
|
221
|
+
@emit('Transferred')
|
|
222
|
+
public transfer(calldata: Calldata): BytesWriter {
|
|
223
|
+
this._transfer(
|
|
224
|
+
Blockchain.tx.sender,
|
|
225
|
+
calldata.readAddress(),
|
|
226
|
+
calldata.readU256(),
|
|
227
|
+
);
|
|
228
|
+
return new BytesWriter(0);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@method(
|
|
232
|
+
{ name: 'from', type: ABIDataTypes.ADDRESS },
|
|
233
|
+
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
234
|
+
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
235
|
+
)
|
|
236
|
+
@emit('Transferred')
|
|
237
|
+
public transferFrom(calldata: Calldata): BytesWriter {
|
|
238
|
+
const from = calldata.readAddress();
|
|
239
|
+
const to = calldata.readAddress();
|
|
240
|
+
const amount = calldata.readU256();
|
|
241
|
+
|
|
242
|
+
this._spendAllowance(from, Blockchain.tx.sender, amount);
|
|
243
|
+
this._transfer(from, to, amount);
|
|
244
|
+
|
|
245
|
+
return new BytesWriter(0);
|
|
246
|
+
}
|
|
247
|
+
|
|
217
248
|
@method(
|
|
218
249
|
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
219
250
|
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
@@ -221,7 +252,7 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
221
252
|
)
|
|
222
253
|
@emit('Transferred')
|
|
223
254
|
public safeTransfer(calldata: Calldata): BytesWriter {
|
|
224
|
-
this.
|
|
255
|
+
this._safeTransfer(
|
|
225
256
|
Blockchain.tx.sender,
|
|
226
257
|
calldata.readAddress(),
|
|
227
258
|
calldata.readU256(),
|
|
@@ -244,7 +275,7 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
244
275
|
const data = calldata.readBytesWithLength();
|
|
245
276
|
|
|
246
277
|
this._spendAllowance(from, Blockchain.tx.sender, amount);
|
|
247
|
-
this.
|
|
278
|
+
this._safeTransfer(from, to, amount, data);
|
|
248
279
|
|
|
249
280
|
return new BytesWriter(0);
|
|
250
281
|
}
|
|
@@ -326,10 +357,9 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
326
357
|
@returns(
|
|
327
358
|
{ name: 'name', type: ABIDataTypes.STRING },
|
|
328
359
|
{ name: 'symbol', type: ABIDataTypes.STRING },
|
|
360
|
+
{ name: 'icon', type: ABIDataTypes.STRING },
|
|
329
361
|
{ name: 'decimals', type: ABIDataTypes.UINT8 },
|
|
330
362
|
{ name: 'totalSupply', type: ABIDataTypes.UINT256 },
|
|
331
|
-
{ name: 'maximumSupply', type: ABIDataTypes.UINT256 },
|
|
332
|
-
{ name: 'icon', type: ABIDataTypes.STRING },
|
|
333
363
|
{ name: 'domainSeparator', type: ABIDataTypes.BYTES32 },
|
|
334
364
|
)
|
|
335
365
|
public metadata(_: Calldata): BytesWriter {
|
|
@@ -354,10 +384,9 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
354
384
|
const w = new BytesWriter(totalSize);
|
|
355
385
|
w.writeStringWithLength(name);
|
|
356
386
|
w.writeStringWithLength(symbol);
|
|
387
|
+
w.writeStringWithLength(icon);
|
|
357
388
|
w.writeU8(this.decimals);
|
|
358
389
|
w.writeU256(this.totalSupply);
|
|
359
|
-
w.writeU256(this.maxSupply);
|
|
360
|
-
w.writeStringWithLength(icon);
|
|
361
390
|
w.writeBytesWithLength(domainSeparator);
|
|
362
391
|
|
|
363
392
|
return w;
|
|
@@ -373,7 +402,7 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
373
402
|
return senderMap.get(spender);
|
|
374
403
|
}
|
|
375
404
|
|
|
376
|
-
protected _transfer(from: Address, to: Address, amount: u256
|
|
405
|
+
protected _transfer(from: Address, to: Address, amount: u256): void {
|
|
377
406
|
if (from === Address.zero() || from === Address.dead()) {
|
|
378
407
|
throw new Revert('Invalid sender');
|
|
379
408
|
}
|
|
@@ -382,10 +411,6 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
382
411
|
throw new Revert('Invalid receiver');
|
|
383
412
|
}
|
|
384
413
|
|
|
385
|
-
if (amount.isZero()) {
|
|
386
|
-
throw new Revert('Amount must be greater than zero');
|
|
387
|
-
}
|
|
388
|
-
|
|
389
414
|
const balance: u256 = this.balanceOfMap.get(from);
|
|
390
415
|
if (balance < amount) {
|
|
391
416
|
throw new Revert('Insufficient balance');
|
|
@@ -397,6 +422,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
397
422
|
this.balanceOfMap.set(to, SafeMath.add(toBal, amount));
|
|
398
423
|
|
|
399
424
|
this.createTransferredEvent(Blockchain.tx.sender, from, to, amount);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
protected _safeTransfer(from: Address, to: Address, amount: u256, data: Uint8Array): void {
|
|
428
|
+
this._transfer(from, to, amount);
|
|
400
429
|
|
|
401
430
|
if (Blockchain.isContract(to)) {
|
|
402
431
|
// In CALLBACK mode, the guard allows depth up to 1
|
|
@@ -24,19 +24,12 @@ import { IOP721 } from './interfaces/IOP721';
|
|
|
24
24
|
import { OP721InitParameters } from './interfaces/OP721InitParameters';
|
|
25
25
|
import { ReentrancyGuard } from './ReentrancyGuard';
|
|
26
26
|
import { StoredMapU256 } from '../storage/maps/StoredMapU256';
|
|
27
|
-
import {
|
|
28
|
-
ApprovedEvent,
|
|
29
|
-
ApprovedForAllEvent,
|
|
30
|
-
MAX_URI_LENGTH,
|
|
31
|
-
TransferredEvent,
|
|
32
|
-
URIEvent,
|
|
33
|
-
} from '../events/predefined';
|
|
27
|
+
import { ApprovedEvent, ApprovedForAllEvent, MAX_URI_LENGTH, TransferredEvent, URIEvent } from '../events/predefined';
|
|
34
28
|
import {
|
|
35
29
|
ON_OP721_RECEIVED_SELECTOR,
|
|
36
30
|
OP712_DOMAIN_TYPE_HASH,
|
|
37
31
|
OP712_VERSION_HASH,
|
|
38
|
-
|
|
39
|
-
OP721_TRANSFER_TYPE_HASH,
|
|
32
|
+
OP721_APPROVAL_TYPE_HASH,
|
|
40
33
|
} from '../constants/Exports';
|
|
41
34
|
|
|
42
35
|
const stringPointer: u16 = Blockchain.nextPointer;
|
|
@@ -52,7 +45,6 @@ const ownerTokensMapPointer: u16 = Blockchain.nextPointer;
|
|
|
52
45
|
const tokenIndexMapPointer: u16 = Blockchain.nextPointer;
|
|
53
46
|
const initializedPointer: u16 = Blockchain.nextPointer;
|
|
54
47
|
const tokenURICounterPointer: u16 = Blockchain.nextPointer;
|
|
55
|
-
const transferNonceMapPointer: u16 = Blockchain.nextPointer;
|
|
56
48
|
const approveNonceMapPointer: u16 = Blockchain.nextPointer;
|
|
57
49
|
|
|
58
50
|
export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
@@ -75,8 +67,6 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
75
67
|
protected readonly balanceOfMap: AddressMemoryMap;
|
|
76
68
|
protected readonly operatorApprovalMap: MapOfMap<u256>;
|
|
77
69
|
|
|
78
|
-
// Separate nonces for different operations
|
|
79
|
-
protected readonly _transferNonceMap: AddressMemoryMap;
|
|
80
70
|
protected readonly _approveNonceMap: AddressMemoryMap;
|
|
81
71
|
|
|
82
72
|
// Token URI storage - stores index to StoredString array
|
|
@@ -112,7 +102,6 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
112
102
|
this.operatorApprovalMap = new MapOfMap<u256>(operatorApprovalMapPointer);
|
|
113
103
|
|
|
114
104
|
// Initialize separate nonce maps
|
|
115
|
-
this._transferNonceMap = new AddressMemoryMap(transferNonceMapPointer);
|
|
116
105
|
this._approveNonceMap = new AddressMemoryMap(approveNonceMapPointer);
|
|
117
106
|
|
|
118
107
|
this.tokenURIIndices = new StoredMapU256(tokenURIMapPointer);
|
|
@@ -308,25 +297,17 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
308
297
|
}
|
|
309
298
|
|
|
310
299
|
@method(
|
|
311
|
-
{ name: 'from', type: ABIDataTypes.ADDRESS },
|
|
312
300
|
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
313
301
|
{ name: 'tokenId', type: ABIDataTypes.UINT256 },
|
|
314
302
|
{ name: 'data', type: ABIDataTypes.BYTES },
|
|
315
303
|
)
|
|
316
304
|
@emit('Transferred')
|
|
317
|
-
public
|
|
318
|
-
const from = calldata.readAddress();
|
|
305
|
+
public safeTransfer(calldata: Calldata): BytesWriter {
|
|
319
306
|
const to = calldata.readAddress();
|
|
320
307
|
const tokenId = calldata.readU256();
|
|
321
308
|
const data = calldata.readBytesWithLength();
|
|
322
309
|
|
|
323
|
-
|
|
324
|
-
this._transfer(from, to, tokenId);
|
|
325
|
-
|
|
326
|
-
// External call happens after all state changes
|
|
327
|
-
if (Blockchain.isContract(to)) {
|
|
328
|
-
this._checkOnOP721Received(from, to, tokenId, data);
|
|
329
|
-
}
|
|
310
|
+
this._transfer(Blockchain.tx.sender, to, tokenId, data);
|
|
330
311
|
|
|
331
312
|
return new BytesWriter(0);
|
|
332
313
|
}
|
|
@@ -335,32 +316,34 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
335
316
|
{ name: 'from', type: ABIDataTypes.ADDRESS },
|
|
336
317
|
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
337
318
|
{ name: 'tokenId', type: ABIDataTypes.UINT256 },
|
|
319
|
+
{ name: 'data', type: ABIDataTypes.BYTES },
|
|
338
320
|
)
|
|
339
321
|
@emit('Transferred')
|
|
340
|
-
public
|
|
322
|
+
public safeTransferFrom(calldata: Calldata): BytesWriter {
|
|
341
323
|
const from = calldata.readAddress();
|
|
342
324
|
const to = calldata.readAddress();
|
|
343
325
|
const tokenId = calldata.readU256();
|
|
326
|
+
const data = calldata.readBytesWithLength();
|
|
344
327
|
|
|
345
|
-
this._transfer(from, to, tokenId);
|
|
328
|
+
this._transfer(from, to, tokenId, data);
|
|
346
329
|
|
|
347
330
|
return new BytesWriter(0);
|
|
348
331
|
}
|
|
349
332
|
|
|
350
333
|
@method(
|
|
351
|
-
{ name: '
|
|
334
|
+
{ name: 'operator', type: ABIDataTypes.ADDRESS },
|
|
352
335
|
{ name: 'tokenId', type: ABIDataTypes.UINT256 },
|
|
353
336
|
)
|
|
354
337
|
@emit('Approved')
|
|
355
338
|
public approve(calldata: Calldata): BytesWriter {
|
|
356
|
-
const
|
|
339
|
+
const operator = calldata.readAddress();
|
|
357
340
|
const tokenId = calldata.readU256();
|
|
358
341
|
|
|
359
342
|
// Validate to address
|
|
360
|
-
if (
|
|
343
|
+
if (operator === Address.zero()) throw new Revert('Cannot approve zero address');
|
|
361
344
|
|
|
362
345
|
const owner = this._ownerOf(tokenId);
|
|
363
|
-
if (
|
|
346
|
+
if (operator === owner) throw new Revert('Approval to current owner');
|
|
364
347
|
|
|
365
348
|
if (
|
|
366
349
|
owner !== Blockchain.tx.sender &&
|
|
@@ -369,13 +352,12 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
369
352
|
throw new Revert('Not authorized to approve');
|
|
370
353
|
}
|
|
371
354
|
|
|
372
|
-
this._approve(
|
|
355
|
+
this._approve(operator, tokenId);
|
|
373
356
|
|
|
374
357
|
return new BytesWriter(0);
|
|
375
358
|
}
|
|
376
359
|
|
|
377
360
|
@method({ name: 'tokenId', type: ABIDataTypes.UINT256 })
|
|
378
|
-
@returns({ name: 'approved', type: ABIDataTypes.ADDRESS })
|
|
379
361
|
public getApproved(calldata: Calldata): BytesWriter {
|
|
380
362
|
const tokenId = calldata.readU256();
|
|
381
363
|
if (!this._exists(tokenId)) throw new Revert('Token does not exist');
|
|
@@ -419,47 +401,50 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
419
401
|
|
|
420
402
|
@method(
|
|
421
403
|
{ name: 'owner', type: ABIDataTypes.ADDRESS },
|
|
422
|
-
{ name: '
|
|
404
|
+
{ name: 'operator', type: ABIDataTypes.ADDRESS },
|
|
423
405
|
{ name: 'tokenId', type: ABIDataTypes.UINT256 },
|
|
424
406
|
{ name: 'deadline', type: ABIDataTypes.UINT64 },
|
|
425
407
|
{ name: 'signature', type: ABIDataTypes.BYTES },
|
|
426
408
|
)
|
|
427
|
-
@emit('
|
|
428
|
-
public
|
|
409
|
+
@emit('Approved')
|
|
410
|
+
public approveBySignature(calldata: Calldata): BytesWriter {
|
|
429
411
|
const owner = calldata.readAddress();
|
|
430
|
-
const
|
|
412
|
+
const operator = calldata.readAddress();
|
|
431
413
|
const tokenId = calldata.readU256();
|
|
432
414
|
const deadline = calldata.readU64();
|
|
433
415
|
const signature = calldata.readBytesWithLength();
|
|
434
416
|
|
|
435
|
-
|
|
436
|
-
this.
|
|
417
|
+
// Verify ownership
|
|
418
|
+
const tokenOwner = this._ownerOf(tokenId);
|
|
419
|
+
if (tokenOwner !== owner) throw new Revert('Not token owner');
|
|
420
|
+
|
|
421
|
+
this._verifyApproveSignature(owner, operator, tokenId, deadline, signature);
|
|
422
|
+
|
|
423
|
+
this._approve(operator, tokenId);
|
|
437
424
|
|
|
438
425
|
return new BytesWriter(0);
|
|
439
426
|
}
|
|
440
427
|
|
|
441
428
|
@method(
|
|
442
429
|
{ name: 'owner', type: ABIDataTypes.ADDRESS },
|
|
443
|
-
{ name: '
|
|
444
|
-
{ name: '
|
|
430
|
+
{ name: 'operator', type: ABIDataTypes.ADDRESS },
|
|
431
|
+
{ name: 'approved', type: ABIDataTypes.BOOL },
|
|
445
432
|
{ name: 'deadline', type: ABIDataTypes.UINT64 },
|
|
446
433
|
{ name: 'signature', type: ABIDataTypes.BYTES },
|
|
447
434
|
)
|
|
448
435
|
@emit('Approved')
|
|
449
|
-
public
|
|
436
|
+
public setApprovalForAllBySignature(calldata: Calldata): BytesWriter {
|
|
450
437
|
const owner = calldata.readAddress();
|
|
451
|
-
const
|
|
452
|
-
const
|
|
438
|
+
const operator = calldata.readAddress();
|
|
439
|
+
const approved = calldata.readBoolean();
|
|
453
440
|
const deadline = calldata.readU64();
|
|
454
441
|
const signature = calldata.readBytesWithLength();
|
|
455
442
|
|
|
456
|
-
|
|
457
|
-
const tokenOwner = this._ownerOf(tokenId);
|
|
458
|
-
if (tokenOwner !== owner) throw new Revert('Not token owner');
|
|
443
|
+
if (owner === operator) throw new Revert('Cannot approve self');
|
|
459
444
|
|
|
460
|
-
this.
|
|
445
|
+
this._verifySetApprovalForAllSignature(owner, operator, approved, deadline, signature);
|
|
461
446
|
|
|
462
|
-
this.
|
|
447
|
+
this._setApprovalForAll(owner, operator, approved);
|
|
463
448
|
|
|
464
449
|
return new BytesWriter(0);
|
|
465
450
|
}
|
|
@@ -500,16 +485,6 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
500
485
|
return w;
|
|
501
486
|
}
|
|
502
487
|
|
|
503
|
-
@method({ name: 'owner', type: ABIDataTypes.ADDRESS })
|
|
504
|
-
@returns({ name: 'nonce', type: ABIDataTypes.UINT256 })
|
|
505
|
-
public getTransferNonce(calldata: Calldata): BytesWriter {
|
|
506
|
-
const owner = calldata.readAddress();
|
|
507
|
-
const nonce = this._transferNonceMap.get(owner);
|
|
508
|
-
const w = new BytesWriter(U256_BYTE_LENGTH);
|
|
509
|
-
w.writeU256(nonce);
|
|
510
|
-
return w;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
488
|
@method({ name: 'owner', type: ABIDataTypes.ADDRESS })
|
|
514
489
|
@returns({ name: 'nonce', type: ABIDataTypes.UINT256 })
|
|
515
490
|
public getApproveNonce(calldata: Calldata): BytesWriter {
|
|
@@ -546,7 +521,6 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
546
521
|
{ name: 'description', type: ABIDataTypes.STRING },
|
|
547
522
|
{ name: 'website', type: ABIDataTypes.STRING },
|
|
548
523
|
{ name: 'totalSupply', type: ABIDataTypes.UINT256 },
|
|
549
|
-
{ name: 'maximumSupply', type: ABIDataTypes.UINT256 },
|
|
550
524
|
{ name: 'domainSeparator', type: ABIDataTypes.BYTES32 },
|
|
551
525
|
)
|
|
552
526
|
public metadata(_: Calldata): BytesWriter {
|
|
@@ -657,7 +631,7 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
657
631
|
this.createTransferEvent(owner, Address.zero(), tokenId);
|
|
658
632
|
}
|
|
659
633
|
|
|
660
|
-
protected _transfer(from: Address, to: Address, tokenId: u256): void {
|
|
634
|
+
protected _transfer(from: Address, to: Address, tokenId: u256, data: Uint8Array): void {
|
|
661
635
|
// Skip self-transfers
|
|
662
636
|
if (from === to) return;
|
|
663
637
|
|
|
@@ -699,6 +673,11 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
699
673
|
// Transfer ownership
|
|
700
674
|
this.ownerOfMap.set(tokenId, this._u256FromAddress(to));
|
|
701
675
|
|
|
676
|
+
// External call happens after all state changes
|
|
677
|
+
if (Blockchain.isContract(to)) {
|
|
678
|
+
this._checkOnOP721Received(from, to, tokenId, data);
|
|
679
|
+
}
|
|
680
|
+
|
|
702
681
|
this.createTransferEvent(from, to, tokenId);
|
|
703
682
|
}
|
|
704
683
|
|
|
@@ -774,10 +753,10 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
774
753
|
): void {
|
|
775
754
|
const calldata = new BytesWriter(
|
|
776
755
|
SELECTOR_BYTE_LENGTH +
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
756
|
+
ADDRESS_BYTE_LENGTH * 2 +
|
|
757
|
+
U256_BYTE_LENGTH +
|
|
758
|
+
U32_BYTE_LENGTH +
|
|
759
|
+
data.length,
|
|
781
760
|
);
|
|
782
761
|
calldata.writeSelector(ON_OP721_RECEIVED_SELECTOR);
|
|
783
762
|
calldata.writeAddress(Blockchain.tx.sender);
|
|
@@ -796,9 +775,9 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
796
775
|
}
|
|
797
776
|
}
|
|
798
777
|
|
|
799
|
-
protected
|
|
778
|
+
protected _verifyApproveSignature(
|
|
800
779
|
owner: Address,
|
|
801
|
-
|
|
780
|
+
spender: Address,
|
|
802
781
|
tokenId: u256,
|
|
803
782
|
deadline: u64,
|
|
804
783
|
signature: Uint8Array,
|
|
@@ -810,38 +789,26 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
810
789
|
throw new Revert('Signature expired');
|
|
811
790
|
}
|
|
812
791
|
|
|
813
|
-
const nonce = this.
|
|
792
|
+
const nonce = this._approveNonceMap.get(owner);
|
|
814
793
|
|
|
815
794
|
const structWriter = new BytesWriter(
|
|
816
795
|
32 + ADDRESS_BYTE_LENGTH * 2 + U256_BYTE_LENGTH * 2 + U64_BYTE_LENGTH,
|
|
817
796
|
);
|
|
818
|
-
structWriter.writeBytesU8Array(
|
|
797
|
+
structWriter.writeBytesU8Array(OP721_APPROVAL_TYPE_HASH);
|
|
819
798
|
structWriter.writeAddress(owner);
|
|
820
|
-
structWriter.writeAddress(
|
|
799
|
+
structWriter.writeAddress(spender);
|
|
821
800
|
structWriter.writeU256(tokenId);
|
|
822
801
|
structWriter.writeU256(nonce);
|
|
823
802
|
structWriter.writeU64(deadline);
|
|
824
803
|
|
|
825
804
|
const structHash = sha256(structWriter.getBuffer());
|
|
826
|
-
|
|
827
|
-
const messageWriter = new BytesWriter(2 + 32 + 32);
|
|
828
|
-
messageWriter.writeU16(0x1901);
|
|
829
|
-
messageWriter.writeBytes(this._buildDomainSeparator());
|
|
830
|
-
messageWriter.writeBytes(structHash);
|
|
831
|
-
|
|
832
|
-
const hash = sha256(messageWriter.getBuffer());
|
|
833
|
-
|
|
834
|
-
if (!Blockchain.verifySchnorrSignature(owner, signature, hash)) {
|
|
835
|
-
throw new Revert('Invalid signature');
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
this._transferNonceMap.set(owner, SafeMath.add(nonce, u256.One));
|
|
805
|
+
this._verifySignature(structHash, owner, signature, nonce);
|
|
839
806
|
}
|
|
840
807
|
|
|
841
|
-
protected
|
|
808
|
+
protected _verifySetApprovalForAllSignature(
|
|
842
809
|
owner: Address,
|
|
843
810
|
spender: Address,
|
|
844
|
-
|
|
811
|
+
approved: boolean,
|
|
845
812
|
deadline: u64,
|
|
846
813
|
signature: Uint8Array,
|
|
847
814
|
): void {
|
|
@@ -857,15 +824,23 @@ export abstract class OP721 extends ReentrancyGuard implements IOP721 {
|
|
|
857
824
|
const structWriter = new BytesWriter(
|
|
858
825
|
32 + ADDRESS_BYTE_LENGTH * 2 + U256_BYTE_LENGTH * 2 + U64_BYTE_LENGTH,
|
|
859
826
|
);
|
|
860
|
-
structWriter.writeBytesU8Array(
|
|
827
|
+
structWriter.writeBytesU8Array(OP721_APPROVAL_TYPE_HASH);
|
|
861
828
|
structWriter.writeAddress(owner);
|
|
862
829
|
structWriter.writeAddress(spender);
|
|
863
|
-
structWriter.
|
|
830
|
+
structWriter.writeBoolean(approved);
|
|
864
831
|
structWriter.writeU256(nonce);
|
|
865
832
|
structWriter.writeU64(deadline);
|
|
866
833
|
|
|
867
834
|
const structHash = sha256(structWriter.getBuffer());
|
|
835
|
+
this._verifySignature(structHash, owner, signature, nonce);
|
|
836
|
+
}
|
|
868
837
|
|
|
838
|
+
protected _verifySignature(
|
|
839
|
+
structHash: Uint8Array,
|
|
840
|
+
owner: Address,
|
|
841
|
+
signature: Uint8Array,
|
|
842
|
+
nonce: u256,
|
|
843
|
+
): void {
|
|
869
844
|
const messageWriter = new BytesWriter(2 + 32 + 32);
|
|
870
845
|
messageWriter.writeU16(0x1901);
|
|
871
846
|
messageWriter.writeBytes(this._buildDomainSeparator());
|
|
@@ -13,7 +13,7 @@ export interface IOP721 {
|
|
|
13
13
|
ownerOf(calldata: Calldata): BytesWriter;
|
|
14
14
|
|
|
15
15
|
// Transfer functions
|
|
16
|
-
|
|
16
|
+
safeTransfer(calldata: Calldata): BytesWriter;
|
|
17
17
|
safeTransferFrom(calldata: Calldata): BytesWriter;
|
|
18
18
|
|
|
19
19
|
// Approval functions
|
|
@@ -21,9 +21,10 @@ export interface IOP721 {
|
|
|
21
21
|
getApproved(calldata: Calldata): BytesWriter;
|
|
22
22
|
setApprovalForAll(calldata: Calldata): BytesWriter;
|
|
23
23
|
isApprovedForAll(calldata: Calldata): BytesWriter;
|
|
24
|
+
approveBySignature(calldata: Calldata): BytesWriter;
|
|
25
|
+
setApprovalForAllBySignature(calldata: Calldata): BytesWriter;
|
|
24
26
|
|
|
25
27
|
// Advanced functions
|
|
26
28
|
burn(calldata: Calldata): BytesWriter;
|
|
27
|
-
transferBySignature(calldata: Calldata): BytesWriter;
|
|
28
29
|
domainSeparator(calldata: Calldata): BytesWriter;
|
|
29
30
|
}
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
U32_BYTE_LENGTH,
|
|
11
11
|
} from '../utils';
|
|
12
12
|
|
|
13
|
+
export const transferSignature = 'transfer(address,uint256)';
|
|
14
|
+
export const transferFromSignature = 'transferFrom(address,address,uint256)';
|
|
13
15
|
export const SafeTransferSignature = 'safeTransfer(address,uint256,bytes)';
|
|
14
16
|
export const SafeTransferFromSignature = 'safeTransferFrom(address,address,uint256,bytes)';
|
|
15
17
|
export const IncreaseAllowanceSignature = 'increaseAllowance(address,uint256)';
|
|
@@ -26,14 +28,22 @@ export class TransferHelper {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
public static get TRANSFER_SELECTOR(): Selector {
|
|
29
|
-
return encodeSelector(
|
|
31
|
+
return encodeSelector(transferSignature);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
public static get TRANSFER_FROM_SELECTOR(): Selector {
|
|
35
|
+
return encodeSelector(transferFromSignature);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public static get SAFE_TRANSFER_SELECTOR(): Selector {
|
|
39
|
+
return encodeSelector(SafeTransferSignature);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public static get SAFE_TRANSFER_FROM_SELECTOR(): Selector {
|
|
33
43
|
return encodeSelector(SafeTransferFromSignature);
|
|
34
44
|
}
|
|
35
45
|
|
|
36
|
-
public static
|
|
46
|
+
public static increaseAllowance(token: Address, spender: Address, amount: u256): void {
|
|
37
47
|
const calldata = new BytesWriter(
|
|
38
48
|
SELECTOR_BYTE_LENGTH + ADDRESS_BYTE_LENGTH + U256_BYTE_LENGTH,
|
|
39
49
|
);
|
|
@@ -44,7 +54,7 @@ export class TransferHelper {
|
|
|
44
54
|
Blockchain.call(token, calldata);
|
|
45
55
|
}
|
|
46
56
|
|
|
47
|
-
public static
|
|
57
|
+
public static decreaseAllowance(token: Address, spender: Address, amount: u256): void {
|
|
48
58
|
const calldata = new BytesWriter(
|
|
49
59
|
SELECTOR_BYTE_LENGTH + ADDRESS_BYTE_LENGTH + U256_BYTE_LENGTH,
|
|
50
60
|
);
|
|
@@ -55,6 +65,42 @@ export class TransferHelper {
|
|
|
55
65
|
Blockchain.call(token, calldata);
|
|
56
66
|
}
|
|
57
67
|
|
|
68
|
+
public static transfer(
|
|
69
|
+
token: Address,
|
|
70
|
+
to: Address,
|
|
71
|
+
amount: u256
|
|
72
|
+
): void {
|
|
73
|
+
const calldata = new BytesWriter(
|
|
74
|
+
SELECTOR_BYTE_LENGTH +
|
|
75
|
+
ADDRESS_BYTE_LENGTH +
|
|
76
|
+
U256_BYTE_LENGTH
|
|
77
|
+
);
|
|
78
|
+
calldata.writeSelector(this.TRANSFER_SELECTOR);
|
|
79
|
+
calldata.writeAddress(to);
|
|
80
|
+
calldata.writeU256(amount);
|
|
81
|
+
|
|
82
|
+
Blockchain.call(token, calldata);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public static transferFrom(
|
|
86
|
+
token: Address,
|
|
87
|
+
from: Address,
|
|
88
|
+
to: Address,
|
|
89
|
+
amount: u256
|
|
90
|
+
): void {
|
|
91
|
+
const calldata = new BytesWriter(
|
|
92
|
+
SELECTOR_BYTE_LENGTH +
|
|
93
|
+
ADDRESS_BYTE_LENGTH * 2 +
|
|
94
|
+
U256_BYTE_LENGTH
|
|
95
|
+
);
|
|
96
|
+
calldata.writeSelector(this.TRANSFER_FROM_SELECTOR);
|
|
97
|
+
calldata.writeAddress(from);
|
|
98
|
+
calldata.writeAddress(to);
|
|
99
|
+
calldata.writeU256(amount);
|
|
100
|
+
|
|
101
|
+
Blockchain.call(token, calldata);
|
|
102
|
+
}
|
|
103
|
+
|
|
58
104
|
public static safeTransfer(
|
|
59
105
|
token: Address,
|
|
60
106
|
to: Address,
|
|
@@ -68,7 +114,7 @@ export class TransferHelper {
|
|
|
68
114
|
U32_BYTE_LENGTH +
|
|
69
115
|
data.length,
|
|
70
116
|
);
|
|
71
|
-
calldata.writeSelector(this.
|
|
117
|
+
calldata.writeSelector(this.SAFE_TRANSFER_SELECTOR);
|
|
72
118
|
calldata.writeAddress(to);
|
|
73
119
|
calldata.writeU256(amount);
|
|
74
120
|
calldata.writeBytesWithLength(data);
|
|
@@ -104,7 +150,7 @@ export class TransferHelper {
|
|
|
104
150
|
U32_BYTE_LENGTH +
|
|
105
151
|
data.length,
|
|
106
152
|
);
|
|
107
|
-
calldata.writeSelector(this.
|
|
153
|
+
calldata.writeSelector(this.SAFE_TRANSFER_FROM_SELECTOR);
|
|
108
154
|
calldata.writeAddress(from);
|
|
109
155
|
calldata.writeAddress(to);
|
|
110
156
|
calldata.writeU256(amount);
|