@btc-vision/btc-runtime 1.9.16 → 1.10.0
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 +2 -2
- package/runtime/buffer/BytesReader.ts +1 -1
- package/runtime/constants/Exports.ts +11 -11
- package/runtime/contracts/OP20.ts +312 -12
- package/runtime/contracts/OP721.ts +15 -9
- package/runtime/env/BlockchainEnvironment.ts +202 -5
- package/runtime/env/classes/Transaction.ts +36 -3
- package/runtime/env/consensus/ConsensusRules.ts +228 -0
- package/runtime/env/consensus/MLDSAMetadata.ts +181 -0
- package/runtime/env/consensus/Signatures.ts +7 -0
- package/runtime/env/global.ts +111 -7
- package/runtime/exports/index.ts +2 -1
- package/runtime/index.ts +7 -11
- package/runtime/interfaces/as.ts +5 -0
- package/runtime/shared-libraries/TransferHelper.ts +4 -17
- package/runtime/types/Address.ts +230 -46
- package/runtime/types/ExtendedAddress.ts +426 -0
- package/runtime/nested/PointerManager.ts +0 -55
- package/runtime/nested/codecs/AddressCodec.ts +0 -19
- package/runtime/nested/codecs/BooleanCodec.ts +0 -17
- package/runtime/nested/codecs/Ids.ts +0 -10
- package/runtime/nested/codecs/NumericCodec.ts +0 -58
- package/runtime/nested/codecs/StringCodec.ts +0 -24
- package/runtime/nested/codecs/U256Codec.ts +0 -20
- package/runtime/nested/codecs/VariableBytesCodec.ts +0 -134
- package/runtime/nested/interfaces/ICodec.ts +0 -12
- package/runtime/nested/storage/StorageMap.ts +0 -207
- package/runtime/nested/storage/StorageSet.ts +0 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/btc-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Bitcoin Smart Contract Runtime",
|
|
5
5
|
"main": "btc/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@btc-vision/as-pect-assembly": "^8.2.0",
|
|
26
26
|
"@btc-vision/as-pect-cli": "^8.2.0",
|
|
27
27
|
"@btc-vision/as-pect-transform": "^8.2.0",
|
|
28
|
-
"@types/node": "^24.10.
|
|
28
|
+
"@types/node": "^24.10.1",
|
|
29
29
|
"assemblyscript": "^0.28.9"
|
|
30
30
|
},
|
|
31
31
|
"repository": {
|
|
@@ -238,7 +238,7 @@ export class BytesReader {
|
|
|
238
238
|
public readAddress(): Address {
|
|
239
239
|
this.verifyEnd(this.currentOffset + ADDRESS_BYTE_LENGTH);
|
|
240
240
|
|
|
241
|
-
const addr = new Address();
|
|
241
|
+
const addr = new Address([]);
|
|
242
242
|
for (let i: i32 = 0; i < ADDRESS_BYTE_LENGTH; i++) {
|
|
243
243
|
addr[i] = this.readU8();
|
|
244
244
|
}
|
|
@@ -79,14 +79,14 @@ export const OP721_TRANSFER_TYPE_HASH: u8[] = [
|
|
|
79
79
|
0x64, 0xab, 0xa6, 0xaf, 0x68, 0x51, 0x03, 0xfe, 0xc4, 0xae, 0x12, 0xd7, 0xa6, 0xa9, 0xb2, 0x0f,
|
|
80
80
|
];
|
|
81
81
|
|
|
82
|
-
export const BALANCE_OF_SELECTOR:
|
|
83
|
-
export const ALLOWANCE_SELECTOR:
|
|
84
|
-
export const TOTAL_SUPPLY_SELECTOR:
|
|
85
|
-
export const NAME_SELECTOR:
|
|
86
|
-
export const SYMBOL_SELECTOR:
|
|
87
|
-
export const DECIMALS_SELECTOR:
|
|
88
|
-
export const NONCE_OF_SELECTOR:
|
|
89
|
-
export const DOMAIN_SEPARATOR_SELECTOR:u32 = 0xf1bf80e0; // "domainSeparator()"
|
|
90
|
-
export const METADATA_SELECTOR:
|
|
91
|
-
export const MAXIMUM_SUPPLY_SELECTOR:
|
|
92
|
-
export const ICON_SELECTOR:
|
|
82
|
+
export const BALANCE_OF_SELECTOR: u32 = 0x5b46f8f6; // "balanceOf(address)"
|
|
83
|
+
export const ALLOWANCE_SELECTOR: u32 = 0xd864b7ca; // "allowance(address,address)"
|
|
84
|
+
export const TOTAL_SUPPLY_SELECTOR: u32 = 0xa368022e; // "totalSupply()"
|
|
85
|
+
export const NAME_SELECTOR: u32 = 0x1581f81c; // "name()"
|
|
86
|
+
export const SYMBOL_SELECTOR: u32 = 0x25967ca5; // "symbol()"
|
|
87
|
+
export const DECIMALS_SELECTOR: u32 = 0xbb844440; // "decimals()"
|
|
88
|
+
export const NONCE_OF_SELECTOR: u32 = 0xf6824b65; // "nonceOf(address)"
|
|
89
|
+
export const DOMAIN_SEPARATOR_SELECTOR: u32 = 0xf1bf80e0; // "domainSeparator()"
|
|
90
|
+
export const METADATA_SELECTOR: u32 = 0xfc0d115c; // "metadata()"
|
|
91
|
+
export const MAXIMUM_SUPPLY_SELECTOR: u32 = 0x7d8d5019; // "maximumSupply()"
|
|
92
|
+
export const ICON_SELECTOR: u32 = 0xaaaa50c5; // "icon()"
|
|
@@ -50,25 +50,95 @@ const decimalsPointer: u16 = Blockchain.nextPointer;
|
|
|
50
50
|
const stringPointer: u16 = Blockchain.nextPointer;
|
|
51
51
|
const totalSupplyPointer: u16 = Blockchain.nextPointer;
|
|
52
52
|
const allowanceMapPointer: u16 = Blockchain.nextPointer;
|
|
53
|
-
|
|
54
53
|
const balanceOfMapPointer: u16 = Blockchain.nextPointer;
|
|
55
54
|
|
|
55
|
+
/**
|
|
56
|
+
* OP20 Token Standard Implementation for OPNet.
|
|
57
|
+
*
|
|
58
|
+
* This abstract class implements the OP20 token standard, providing a complete
|
|
59
|
+
* fungible token implementation with advanced features including:
|
|
60
|
+
* - EIP-712 style typed data signatures for gasless approvals
|
|
61
|
+
* - Safe transfer callbacks for receiver contracts
|
|
62
|
+
* - Reentrancy protection for security
|
|
63
|
+
* - Quantum-resistant signature support (Schnorr now, ML-DSA future)
|
|
64
|
+
* - Unlimited approval optimization (u256.Max)
|
|
65
|
+
*
|
|
66
|
+
* @remarks
|
|
67
|
+
* OP20 is OPNet's equivalent of ERC20, adapted for Bitcoin's UTXO model with
|
|
68
|
+
* additional security features. All storage uses persistent pointers for
|
|
69
|
+
* cross-transaction state management. The contract includes built-in protection
|
|
70
|
+
* against common attack vectors including reentrancy and integer overflow.
|
|
71
|
+
*
|
|
72
|
+
* Inheriting contracts must implement deployment verification logic and can
|
|
73
|
+
* extend with additional features like minting permissions, pausability, etc.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* class MyToken extends OP20 {
|
|
78
|
+
* constructor() {
|
|
79
|
+
* super();
|
|
80
|
+
* const params: OP20InitParameters = {
|
|
81
|
+
* name: "My Token",
|
|
82
|
+
* symbol: "MTK",
|
|
83
|
+
* decimals: 18,
|
|
84
|
+
* maxSupply: u256.fromU64(1000000000000000000000000), // 1M tokens
|
|
85
|
+
* icon: "https://example.com/icon.png"
|
|
86
|
+
* };
|
|
87
|
+
* this.instantiate(params);
|
|
88
|
+
* }
|
|
89
|
+
* }
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
56
92
|
export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
93
|
+
/**
|
|
94
|
+
* Total supply of tokens currently in circulation.
|
|
95
|
+
* Intentionally public for inherited classes to implement custom minting/burning logic.
|
|
96
|
+
*/
|
|
97
|
+
public _totalSupply: StoredU256;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Reentrancy protection level for this contract.
|
|
101
|
+
* Set to CALLBACK to allow single-depth callbacks for safeTransfer operations.
|
|
102
|
+
*/
|
|
57
103
|
protected readonly reentrancyLevel: ReentrancyLevel = ReentrancyLevel.CALLBACK;
|
|
58
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Nested mapping of owner -> spender -> allowance amount.
|
|
107
|
+
* Tracks approval amounts for transferFrom operations.
|
|
108
|
+
*/
|
|
59
109
|
protected readonly allowanceMap: MapOfMap<u256>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Mapping of address -> balance.
|
|
113
|
+
* Stores token balances for all holders.
|
|
114
|
+
*/
|
|
60
115
|
protected readonly balanceOfMap: AddressMemoryMap;
|
|
61
116
|
|
|
117
|
+
/** Maximum supply that can ever be minted. */
|
|
62
118
|
protected readonly _maxSupply: StoredU256;
|
|
119
|
+
|
|
120
|
+
/** Number of decimal places for token display. */
|
|
63
121
|
protected readonly _decimals: StoredU256;
|
|
122
|
+
|
|
123
|
+
/** Human-readable token name. */
|
|
64
124
|
protected readonly _name: StoredString;
|
|
125
|
+
|
|
126
|
+
/** Token icon URL for display in wallets/explorers. */
|
|
65
127
|
protected readonly _icon: StoredString;
|
|
128
|
+
|
|
129
|
+
/** Token ticker symbol. */
|
|
66
130
|
protected readonly _symbol: StoredString;
|
|
67
|
-
protected readonly _nonceMap: AddressMemoryMap;
|
|
68
131
|
|
|
69
|
-
/**
|
|
70
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Mapping of address -> nonce for EIP-712 signatures.
|
|
134
|
+
* Prevents signature replay attacks.
|
|
135
|
+
*/
|
|
136
|
+
protected readonly _nonceMap: AddressMemoryMap;
|
|
71
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Initializes the OP20 token with storage pointers.
|
|
140
|
+
* Sets up all persistent storage mappings and variables.
|
|
141
|
+
*/
|
|
72
142
|
public constructor() {
|
|
73
143
|
super();
|
|
74
144
|
|
|
@@ -84,6 +154,21 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
84
154
|
this._icon = new StoredString(stringPointer, 2);
|
|
85
155
|
}
|
|
86
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Initializes token parameters. Can only be called once.
|
|
159
|
+
*
|
|
160
|
+
* @param params - Token initialization parameters
|
|
161
|
+
* @param skipDeployerVerification - If true, skips deployer check (use with caution)
|
|
162
|
+
*
|
|
163
|
+
* @throws {Revert} If already initialized
|
|
164
|
+
* @throws {Revert} If decimals > 32
|
|
165
|
+
* @throws {Revert} If caller is not deployer (unless skipped)
|
|
166
|
+
*
|
|
167
|
+
* @remarks
|
|
168
|
+
* This method sets immutable token parameters and should be called in the
|
|
169
|
+
* constructor of inheriting contracts. The maximum of 32 decimals is enforced
|
|
170
|
+
* to prevent precision issues with u256 arithmetic.
|
|
171
|
+
*/
|
|
87
172
|
public instantiate(
|
|
88
173
|
params: OP20InitParameters,
|
|
89
174
|
skipDeployerVerification: boolean = false,
|
|
@@ -99,6 +184,11 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
99
184
|
this._icon.value = params.icon;
|
|
100
185
|
}
|
|
101
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Returns the token name.
|
|
189
|
+
*
|
|
190
|
+
* @returns Token name as string
|
|
191
|
+
*/
|
|
102
192
|
@method()
|
|
103
193
|
@returns({ name: 'name', type: ABIDataTypes.STRING })
|
|
104
194
|
public name(_: Calldata): BytesWriter {
|
|
@@ -107,6 +197,11 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
107
197
|
return w;
|
|
108
198
|
}
|
|
109
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Returns the token symbol.
|
|
202
|
+
*
|
|
203
|
+
* @returns Token symbol as string
|
|
204
|
+
*/
|
|
110
205
|
@method()
|
|
111
206
|
@returns({ name: 'symbol', type: ABIDataTypes.STRING })
|
|
112
207
|
public symbol(_: Calldata): BytesWriter {
|
|
@@ -115,6 +210,11 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
115
210
|
return w;
|
|
116
211
|
}
|
|
117
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Returns the token icon URL.
|
|
215
|
+
*
|
|
216
|
+
* @returns Icon URL as string
|
|
217
|
+
*/
|
|
118
218
|
@method()
|
|
119
219
|
@returns({ name: 'icon', type: ABIDataTypes.STRING })
|
|
120
220
|
public icon(_: Calldata): BytesWriter {
|
|
@@ -123,6 +223,11 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
123
223
|
return w;
|
|
124
224
|
}
|
|
125
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Returns the number of decimals used for display.
|
|
228
|
+
*
|
|
229
|
+
* @returns Number of decimals (0-32)
|
|
230
|
+
*/
|
|
126
231
|
@method()
|
|
127
232
|
@returns({ name: 'decimals', type: ABIDataTypes.UINT8 })
|
|
128
233
|
public decimals(_: Calldata): BytesWriter {
|
|
@@ -131,6 +236,11 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
131
236
|
return w;
|
|
132
237
|
}
|
|
133
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Returns the total supply of tokens in circulation.
|
|
241
|
+
*
|
|
242
|
+
* @returns Current total supply as u256
|
|
243
|
+
*/
|
|
134
244
|
@method()
|
|
135
245
|
@returns({ name: 'totalSupply', type: ABIDataTypes.UINT256 })
|
|
136
246
|
public totalSupply(_: Calldata): BytesWriter {
|
|
@@ -139,6 +249,11 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
139
249
|
return w;
|
|
140
250
|
}
|
|
141
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Returns the maximum supply that can ever exist.
|
|
254
|
+
*
|
|
255
|
+
* @returns Maximum supply cap as u256
|
|
256
|
+
*/
|
|
142
257
|
@method()
|
|
143
258
|
@returns({ name: 'maximumSupply', type: ABIDataTypes.UINT256 })
|
|
144
259
|
public maximumSupply(_: Calldata): BytesWriter {
|
|
@@ -147,6 +262,15 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
147
262
|
return w;
|
|
148
263
|
}
|
|
149
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Returns the EIP-712 domain separator for signature verification.
|
|
267
|
+
*
|
|
268
|
+
* @returns 32-byte domain separator hash
|
|
269
|
+
*
|
|
270
|
+
* @remarks
|
|
271
|
+
* The domain separator includes chain ID, protocol ID, and contract address
|
|
272
|
+
* to prevent cross-chain and cross-contract signature replay attacks.
|
|
273
|
+
*/
|
|
150
274
|
@method()
|
|
151
275
|
@returns({ name: 'domainSeparator', type: ABIDataTypes.BYTES32 })
|
|
152
276
|
public domainSeparator(_: Calldata): BytesWriter {
|
|
@@ -155,6 +279,12 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
155
279
|
return w;
|
|
156
280
|
}
|
|
157
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Returns the token balance of an address.
|
|
284
|
+
*
|
|
285
|
+
* @param calldata - Contains the address to query
|
|
286
|
+
* @returns Balance as u256
|
|
287
|
+
*/
|
|
158
288
|
@method({ name: 'owner', type: ABIDataTypes.ADDRESS })
|
|
159
289
|
@returns({ name: 'balance', type: ABIDataTypes.UINT256 })
|
|
160
290
|
public balanceOf(calldata: Calldata): BytesWriter {
|
|
@@ -164,6 +294,12 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
164
294
|
return w;
|
|
165
295
|
}
|
|
166
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Returns the current nonce for an address (for signature verification).
|
|
299
|
+
*
|
|
300
|
+
* @param calldata - Contains the address to query
|
|
301
|
+
* @returns Current nonce as u256
|
|
302
|
+
*/
|
|
167
303
|
@method({ name: 'owner', type: ABIDataTypes.ADDRESS })
|
|
168
304
|
@returns({ name: 'nonce', type: ABIDataTypes.UINT256 })
|
|
169
305
|
public nonceOf(calldata: Calldata): BytesWriter {
|
|
@@ -173,6 +309,12 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
173
309
|
return w;
|
|
174
310
|
}
|
|
175
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Returns the amount an address is allowed to spend on behalf of another.
|
|
314
|
+
*
|
|
315
|
+
* @param calldata - Contains owner and spender addresses
|
|
316
|
+
* @returns Remaining allowance as u256
|
|
317
|
+
*/
|
|
176
318
|
@method(
|
|
177
319
|
{ name: 'owner', type: ABIDataTypes.ADDRESS },
|
|
178
320
|
{ name: 'spender', type: ABIDataTypes.ADDRESS },
|
|
@@ -185,6 +327,15 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
185
327
|
return w;
|
|
186
328
|
}
|
|
187
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Transfers tokens from sender to recipient.
|
|
332
|
+
*
|
|
333
|
+
* @param calldata - Contains recipient address and amount
|
|
334
|
+
* @emits Transferred event
|
|
335
|
+
*
|
|
336
|
+
* @throws {Revert} If sender has insufficient balance
|
|
337
|
+
* @throws {Revert} If recipient is zero address
|
|
338
|
+
*/
|
|
188
339
|
@method(
|
|
189
340
|
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
190
341
|
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
@@ -195,6 +346,15 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
195
346
|
return new BytesWriter(0);
|
|
196
347
|
}
|
|
197
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Transfers tokens on behalf of another address using allowance.
|
|
351
|
+
*
|
|
352
|
+
* @param calldata - Contains from address, to address, and amount
|
|
353
|
+
* @emits Transferred event
|
|
354
|
+
*
|
|
355
|
+
* @throws {Revert} If insufficient allowance
|
|
356
|
+
* @throws {Revert} If from has insufficient balance
|
|
357
|
+
*/
|
|
198
358
|
@method(
|
|
199
359
|
{ name: 'from', type: ABIDataTypes.ADDRESS },
|
|
200
360
|
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
@@ -212,6 +372,16 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
212
372
|
return new BytesWriter(0);
|
|
213
373
|
}
|
|
214
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Safely transfers tokens and calls onOP20Received on recipient if it's a contract.
|
|
377
|
+
*
|
|
378
|
+
* @param calldata - Contains recipient, amount, and optional data
|
|
379
|
+
* @emits Transferred event
|
|
380
|
+
*
|
|
381
|
+
* @throws {Revert} If recipient contract rejects the transfer
|
|
382
|
+
* @remarks
|
|
383
|
+
* Prevents tokens from being permanently locked in contracts that can't handle them.
|
|
384
|
+
*/
|
|
215
385
|
@method(
|
|
216
386
|
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
217
387
|
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
@@ -228,6 +398,15 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
228
398
|
return new BytesWriter(0);
|
|
229
399
|
}
|
|
230
400
|
|
|
401
|
+
/**
|
|
402
|
+
* Safely transfers tokens on behalf of another address with callback.
|
|
403
|
+
*
|
|
404
|
+
* @param calldata - Contains from, to, amount, and optional data
|
|
405
|
+
* @emits Transferred event
|
|
406
|
+
*
|
|
407
|
+
* @throws {Revert} If insufficient allowance or balance
|
|
408
|
+
* @throws {Revert} If recipient contract rejects
|
|
409
|
+
*/
|
|
231
410
|
@method(
|
|
232
411
|
{ name: 'from', type: ABIDataTypes.ADDRESS },
|
|
233
412
|
{ name: 'to', type: ABIDataTypes.ADDRESS },
|
|
@@ -247,6 +426,16 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
247
426
|
return new BytesWriter(0);
|
|
248
427
|
}
|
|
249
428
|
|
|
429
|
+
/**
|
|
430
|
+
* Increases the allowance granted to a spender.
|
|
431
|
+
*
|
|
432
|
+
* @param calldata - Contains spender address and amount to increase
|
|
433
|
+
* @emits Approved event
|
|
434
|
+
*
|
|
435
|
+
* @remarks
|
|
436
|
+
* Preferred over setting allowance directly to avoid race conditions.
|
|
437
|
+
* If overflow would occur, sets to u256.Max (unlimited).
|
|
438
|
+
*/
|
|
250
439
|
@method(
|
|
251
440
|
{ name: 'spender', type: ABIDataTypes.ADDRESS },
|
|
252
441
|
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
@@ -261,6 +450,15 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
261
450
|
return new BytesWriter(0);
|
|
262
451
|
}
|
|
263
452
|
|
|
453
|
+
/**
|
|
454
|
+
* Decreases the allowance granted to a spender.
|
|
455
|
+
*
|
|
456
|
+
* @param calldata - Contains spender address and amount to decrease
|
|
457
|
+
* @emits Approved event
|
|
458
|
+
*
|
|
459
|
+
* @remarks
|
|
460
|
+
* If decrease would cause underflow, sets allowance to zero.
|
|
461
|
+
*/
|
|
264
462
|
@method(
|
|
265
463
|
{ name: 'spender', type: ABIDataTypes.ADDRESS },
|
|
266
464
|
{ name: 'amount', type: ABIDataTypes.UINT256 },
|
|
@@ -275,6 +473,18 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
275
473
|
return new BytesWriter(0);
|
|
276
474
|
}
|
|
277
475
|
|
|
476
|
+
/**
|
|
477
|
+
* Increases allowance using an EIP-712 typed signature (gasless approval).
|
|
478
|
+
*
|
|
479
|
+
* @param calldata - Contains owner, spender, amount, deadline, and signature
|
|
480
|
+
* @emits Approved event
|
|
481
|
+
*
|
|
482
|
+
* @throws {Revert} If signature is invalid or expired
|
|
483
|
+
*
|
|
484
|
+
* @remarks
|
|
485
|
+
* Enables gasless approvals where a third party can submit the transaction.
|
|
486
|
+
* Uses Schnorr signatures now, will support ML-DSA after quantum transition.
|
|
487
|
+
*/
|
|
278
488
|
@method(
|
|
279
489
|
{ name: 'owner', type: ABIDataTypes.ADDRESS },
|
|
280
490
|
{ name: 'spender', type: ABIDataTypes.ADDRESS },
|
|
@@ -294,6 +504,14 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
294
504
|
return new BytesWriter(0);
|
|
295
505
|
}
|
|
296
506
|
|
|
507
|
+
/**
|
|
508
|
+
* Decreases allowance using an EIP-712 typed signature.
|
|
509
|
+
*
|
|
510
|
+
* @param calldata - Contains owner, spender, amount, deadline, and signature
|
|
511
|
+
* @emits Approved event
|
|
512
|
+
*
|
|
513
|
+
* @throws {Revert} If signature is invalid or expired
|
|
514
|
+
*/
|
|
297
515
|
@method(
|
|
298
516
|
{ name: 'owner', type: ABIDataTypes.ADDRESS },
|
|
299
517
|
{ name: 'spender', type: ABIDataTypes.ADDRESS },
|
|
@@ -313,6 +531,17 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
313
531
|
return new BytesWriter(0);
|
|
314
532
|
}
|
|
315
533
|
|
|
534
|
+
/**
|
|
535
|
+
* Burns tokens from the sender's balance.
|
|
536
|
+
*
|
|
537
|
+
* @param calldata - Contains amount to burn
|
|
538
|
+
* @emits Burned event
|
|
539
|
+
*
|
|
540
|
+
* @throws {Revert} If sender has insufficient balance
|
|
541
|
+
*
|
|
542
|
+
* @remarks
|
|
543
|
+
* Permanently removes tokens from circulation, decreasing total supply.
|
|
544
|
+
*/
|
|
316
545
|
@method({ name: 'amount', type: ABIDataTypes.UINT256 })
|
|
317
546
|
@emit('Burned')
|
|
318
547
|
public burn(calldata: Calldata): BytesWriter {
|
|
@@ -320,6 +549,14 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
320
549
|
return new BytesWriter(0);
|
|
321
550
|
}
|
|
322
551
|
|
|
552
|
+
/**
|
|
553
|
+
* Returns all token metadata in a single call.
|
|
554
|
+
*
|
|
555
|
+
* @returns Combined metadata including name, symbol, icon, decimals, totalSupply, and domain separator
|
|
556
|
+
*
|
|
557
|
+
* @remarks
|
|
558
|
+
* Optimization for wallets/explorers to fetch all token info in one call.
|
|
559
|
+
*/
|
|
323
560
|
@method()
|
|
324
561
|
@returns(
|
|
325
562
|
{ name: 'name', type: ABIDataTypes.STRING },
|
|
@@ -359,22 +596,34 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
359
596
|
return w;
|
|
360
597
|
}
|
|
361
598
|
|
|
599
|
+
/**
|
|
600
|
+
* Internal: Gets balance of an address.
|
|
601
|
+
* @protected
|
|
602
|
+
*/
|
|
362
603
|
protected _balanceOf(owner: Address): u256 {
|
|
363
604
|
if (!this.balanceOfMap.has(owner)) return u256.Zero;
|
|
364
605
|
return this.balanceOfMap.get(owner);
|
|
365
606
|
}
|
|
366
607
|
|
|
608
|
+
/**
|
|
609
|
+
* Internal: Gets allowance between owner and spender.
|
|
610
|
+
* @protected
|
|
611
|
+
*/
|
|
367
612
|
protected _allowance(owner: Address, spender: Address): u256 {
|
|
368
613
|
const senderMap = this.allowanceMap.get(owner);
|
|
369
614
|
return senderMap.get(spender);
|
|
370
615
|
}
|
|
371
616
|
|
|
617
|
+
/**
|
|
618
|
+
* Internal: Executes token transfer logic.
|
|
619
|
+
* @protected
|
|
620
|
+
*/
|
|
372
621
|
protected _transfer(from: Address, to: Address, amount: u256): void {
|
|
373
|
-
if (from === Address.zero()
|
|
622
|
+
if (from === Address.zero()) {
|
|
374
623
|
throw new Revert('Invalid sender');
|
|
375
624
|
}
|
|
376
625
|
|
|
377
|
-
if (to === Address.zero()
|
|
626
|
+
if (to === Address.zero()) {
|
|
378
627
|
throw new Revert('Invalid receiver');
|
|
379
628
|
}
|
|
380
629
|
|
|
@@ -391,6 +640,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
391
640
|
this.createTransferredEvent(Blockchain.tx.sender, from, to, amount);
|
|
392
641
|
}
|
|
393
642
|
|
|
643
|
+
/**
|
|
644
|
+
* Internal: Safe transfer with receiver callback.
|
|
645
|
+
* @protected
|
|
646
|
+
*/
|
|
394
647
|
protected _safeTransfer(from: Address, to: Address, amount: u256, data: Uint8Array): void {
|
|
395
648
|
this._transfer(from, to, amount);
|
|
396
649
|
|
|
@@ -401,6 +654,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
401
654
|
}
|
|
402
655
|
}
|
|
403
656
|
|
|
657
|
+
/**
|
|
658
|
+
* Internal: Spends allowance for transferFrom.
|
|
659
|
+
* @protected
|
|
660
|
+
*/
|
|
404
661
|
protected _spendAllowance(owner: Address, spender: Address, amount: u256): void {
|
|
405
662
|
if (owner.equals(spender)) return;
|
|
406
663
|
|
|
@@ -417,6 +674,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
417
674
|
this.allowanceMap.set(owner, ownerMap);
|
|
418
675
|
}
|
|
419
676
|
|
|
677
|
+
/**
|
|
678
|
+
* Internal: Calls onOP20Received on receiver contract.
|
|
679
|
+
* @protected
|
|
680
|
+
*/
|
|
420
681
|
protected _callOnOP20Received(
|
|
421
682
|
from: Address,
|
|
422
683
|
to: Address,
|
|
@@ -448,6 +709,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
448
709
|
}
|
|
449
710
|
}
|
|
450
711
|
|
|
712
|
+
/**
|
|
713
|
+
* Internal: Processes signature-based allowance increase.
|
|
714
|
+
* @protected
|
|
715
|
+
*/
|
|
451
716
|
protected _increaseAllowanceBySignature(
|
|
452
717
|
owner: Address,
|
|
453
718
|
spender: Address,
|
|
@@ -466,6 +731,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
466
731
|
this._increaseAllowance(owner, spender, amount);
|
|
467
732
|
}
|
|
468
733
|
|
|
734
|
+
/**
|
|
735
|
+
* Checks if a selector should bypass reentrancy guards.
|
|
736
|
+
* @protected
|
|
737
|
+
*/
|
|
469
738
|
protected isSelectorExcluded(selector: Selector): boolean {
|
|
470
739
|
if (
|
|
471
740
|
selector === BALANCE_OF_SELECTOR ||
|
|
@@ -486,6 +755,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
486
755
|
return super.isSelectorExcluded(selector);
|
|
487
756
|
}
|
|
488
757
|
|
|
758
|
+
/**
|
|
759
|
+
* Internal: Processes signature-based allowance decrease.
|
|
760
|
+
* @protected
|
|
761
|
+
*/
|
|
489
762
|
protected _decreaseAllowanceBySignature(
|
|
490
763
|
owner: Address,
|
|
491
764
|
spender: Address,
|
|
@@ -504,6 +777,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
504
777
|
this._decreaseAllowance(owner, spender, amount);
|
|
505
778
|
}
|
|
506
779
|
|
|
780
|
+
/**
|
|
781
|
+
* Internal: Verifies EIP-712 typed signatures.
|
|
782
|
+
* @protected
|
|
783
|
+
*/
|
|
507
784
|
protected _verifySignature(
|
|
508
785
|
typeHash: u8[],
|
|
509
786
|
owner: Address,
|
|
@@ -547,6 +824,10 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
547
824
|
this._nonceMap.set(owner, SafeMath.add(nonce, u256.One));
|
|
548
825
|
}
|
|
549
826
|
|
|
827
|
+
/**
|
|
828
|
+
* Internal: Builds EIP-712 domain separator.
|
|
829
|
+
* @protected
|
|
830
|
+
*/
|
|
550
831
|
protected _buildDomainSeparator(): Uint8Array {
|
|
551
832
|
const writer = new BytesWriter(32 * 5 + ADDRESS_BYTE_LENGTH);
|
|
552
833
|
writer.writeBytesU8Array(OP712_DOMAIN_TYPE_HASH);
|
|
@@ -559,11 +840,15 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
559
840
|
return sha256(writer.getBuffer());
|
|
560
841
|
}
|
|
561
842
|
|
|
843
|
+
/**
|
|
844
|
+
* Internal: Increases allowance with overflow protection.
|
|
845
|
+
* @protected
|
|
846
|
+
*/
|
|
562
847
|
protected _increaseAllowance(owner: Address, spender: Address, amount: u256): void {
|
|
563
|
-
if (owner === Address.zero()
|
|
848
|
+
if (owner === Address.zero()) {
|
|
564
849
|
throw new Revert('Invalid approver');
|
|
565
850
|
}
|
|
566
|
-
if (spender === Address.zero()
|
|
851
|
+
if (spender === Address.zero()) {
|
|
567
852
|
throw new Revert('Invalid spender');
|
|
568
853
|
}
|
|
569
854
|
|
|
@@ -580,11 +865,15 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
580
865
|
this.createApprovedEvent(owner, spender, newAllowance);
|
|
581
866
|
}
|
|
582
867
|
|
|
868
|
+
/**
|
|
869
|
+
* Internal: Decreases allowance with underflow protection.
|
|
870
|
+
* @protected
|
|
871
|
+
*/
|
|
583
872
|
protected _decreaseAllowance(owner: Address, spender: Address, amount: u256): void {
|
|
584
|
-
if (owner === Address.zero()
|
|
873
|
+
if (owner === Address.zero()) {
|
|
585
874
|
throw new Revert('Invalid approver');
|
|
586
875
|
}
|
|
587
|
-
if (spender === Address.zero()
|
|
876
|
+
if (spender === Address.zero()) {
|
|
588
877
|
throw new Revert('Invalid spender');
|
|
589
878
|
}
|
|
590
879
|
|
|
@@ -602,8 +891,14 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
602
891
|
this.createApprovedEvent(owner, spender, newAllowance);
|
|
603
892
|
}
|
|
604
893
|
|
|
894
|
+
/**
|
|
895
|
+
* Internal: Mints new tokens to an address.
|
|
896
|
+
* @protected
|
|
897
|
+
*
|
|
898
|
+
* @throws {Revert} If exceeds max supply
|
|
899
|
+
*/
|
|
605
900
|
protected _mint(to: Address, amount: u256): void {
|
|
606
|
-
if (to === Address.zero()
|
|
901
|
+
if (to === Address.zero()) {
|
|
607
902
|
throw new Revert('Invalid receiver');
|
|
608
903
|
}
|
|
609
904
|
|
|
@@ -620,8 +915,12 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
620
915
|
this.createMintedEvent(to, amount);
|
|
621
916
|
}
|
|
622
917
|
|
|
918
|
+
/**
|
|
919
|
+
* Internal: Burns tokens from an address.
|
|
920
|
+
* @protected
|
|
921
|
+
*/
|
|
623
922
|
protected _burn(from: Address, amount: u256): void {
|
|
624
|
-
if (from === Address.zero()
|
|
923
|
+
if (from === Address.zero()) {
|
|
625
924
|
throw new Revert('Invalid sender');
|
|
626
925
|
}
|
|
627
926
|
|
|
@@ -635,6 +934,7 @@ export abstract class OP20 extends ReentrancyGuard implements IOP20 {
|
|
|
635
934
|
this.createBurnedEvent(from, amount);
|
|
636
935
|
}
|
|
637
936
|
|
|
937
|
+
/** Event creation helpers */
|
|
638
938
|
protected createBurnedEvent(from: Address, amount: u256): void {
|
|
639
939
|
this.emitEvent(new BurnedEvent(from, amount));
|
|
640
940
|
}
|