@btc-vision/btc-runtime 1.10.10 → 1.10.11

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 (44) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +258 -137
  3. package/SECURITY.md +226 -0
  4. package/docs/README.md +614 -0
  5. package/docs/advanced/bitcoin-scripts.md +939 -0
  6. package/docs/advanced/cross-contract-calls.md +579 -0
  7. package/docs/advanced/plugins.md +1006 -0
  8. package/docs/advanced/quantum-resistance.md +660 -0
  9. package/docs/advanced/signature-verification.md +715 -0
  10. package/docs/api-reference/blockchain.md +729 -0
  11. package/docs/api-reference/events.md +642 -0
  12. package/docs/api-reference/op20.md +902 -0
  13. package/docs/api-reference/op721.md +819 -0
  14. package/docs/api-reference/safe-math.md +510 -0
  15. package/docs/api-reference/storage.md +840 -0
  16. package/docs/contracts/op-net-base.md +786 -0
  17. package/docs/contracts/op20-token.md +687 -0
  18. package/docs/contracts/op20s-signatures.md +614 -0
  19. package/docs/contracts/op721-nft.md +785 -0
  20. package/docs/contracts/reentrancy-guard.md +787 -0
  21. package/docs/core-concepts/blockchain-environment.md +724 -0
  22. package/docs/core-concepts/decorators.md +466 -0
  23. package/docs/core-concepts/events.md +652 -0
  24. package/docs/core-concepts/pointers.md +391 -0
  25. package/docs/core-concepts/security.md +473 -0
  26. package/docs/core-concepts/storage-system.md +969 -0
  27. package/docs/examples/basic-token.md +745 -0
  28. package/docs/examples/nft-with-reservations.md +1440 -0
  29. package/docs/examples/oracle-integration.md +1212 -0
  30. package/docs/examples/stablecoin.md +1180 -0
  31. package/docs/getting-started/first-contract.md +575 -0
  32. package/docs/getting-started/installation.md +384 -0
  33. package/docs/getting-started/project-structure.md +630 -0
  34. package/docs/storage/memory-maps.md +764 -0
  35. package/docs/storage/stored-arrays.md +778 -0
  36. package/docs/storage/stored-maps.md +758 -0
  37. package/docs/storage/stored-primitives.md +655 -0
  38. package/docs/types/address.md +773 -0
  39. package/docs/types/bytes-writer-reader.md +938 -0
  40. package/docs/types/calldata.md +744 -0
  41. package/docs/types/safe-math.md +446 -0
  42. package/package.json +51 -26
  43. package/runtime/memory/MapOfMap.ts +1 -0
  44. package/LICENSE.md +0 -21
@@ -0,0 +1,466 @@
1
+ # Decorators
2
+
3
+ Decorators are essential for OPNet smart contracts. They define the ABI (Application Binary Interface) that allows external callers to interact with your contract methods.
4
+
5
+ ## Overview
6
+
7
+ OPNet uses three main decorators:
8
+
9
+ | Decorator | Purpose |
10
+ |-----------|---------|
11
+ | `@method()` | Defines input parameters for a contract method |
12
+ | `@returns()` | Defines return values for a contract method |
13
+ | `@emit()` | Specifies which event a method emits |
14
+
15
+ ```typescript
16
+ import { OP_NET, Calldata, BytesWriter, ABIDataTypes } from '@btc-vision/btc-runtime/runtime';
17
+
18
+ @final
19
+ class MyContract extends OP_NET {
20
+ public constructor() {
21
+ super();
22
+ }
23
+
24
+ @method({ name: 'recipient', type: ABIDataTypes.ADDRESS })
25
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
26
+ @emit('Transferred')
27
+ public transfer(calldata: Calldata): BytesWriter {
28
+ const recipient = calldata.readAddress();
29
+ // ... implementation
30
+ const writer = new BytesWriter(1);
31
+ writer.writeBoolean(true);
32
+ return writer;
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### Decorator Flow and ABI Generation
38
+
39
+ ```mermaid
40
+ ---
41
+ config:
42
+ theme: dark
43
+ ---
44
+ flowchart LR
45
+ Start["Contract Source Code"] --> Parse["Compiler"]
46
+ Parse --> Extract["Extract Decorators"]
47
+ Extract --> Build["Build ABI Entry"]
48
+ Build --> Gen["Generate Selector<br/>SHA256 -> u32"]
49
+ Gen --> Output["abi.json"]
50
+ ```
51
+
52
+ ## Solidity Comparison
53
+
54
+ OPNet decorators serve the same purpose as Solidity's function signatures but are more explicit:
55
+
56
+ | Solidity | OPNet |
57
+ |----------|-------|
58
+ | `function name() public view returns (string)` | `@method() @returns({ name: 'name', type: ABIDataTypes.STRING })` |
59
+ | `function balanceOf(address owner) public view returns (uint256)` | `@method({ name: 'owner', type: ABIDataTypes.ADDRESS }) @returns({ name: 'balance', type: ABIDataTypes.UINT256 })` |
60
+ | `function transfer(address to, uint256 amount) public` | `@method({ name: 'to', type: ABIDataTypes.ADDRESS }, { name: 'amount', type: ABIDataTypes.UINT256 })` |
61
+ | `event Transfer(address from, address to, uint256 amount)` | `@emit('Transferred')` |
62
+
63
+ ## ABIDataTypes
64
+
65
+ The `ABIDataTypes` enum defines all supported parameter and return types:
66
+
67
+ ### Numeric Types
68
+
69
+ | Type | Description | Size |
70
+ |------|-------------|------|
71
+ | `ABIDataTypes.UINT8` | Unsigned 8-bit integer | 1 byte |
72
+ | `ABIDataTypes.UINT16` | Unsigned 16-bit integer | 2 bytes |
73
+ | `ABIDataTypes.UINT32` | Unsigned 32-bit integer | 4 bytes |
74
+ | `ABIDataTypes.UINT64` | Unsigned 64-bit integer | 8 bytes |
75
+ | `ABIDataTypes.UINT128` | Unsigned 128-bit integer | 16 bytes |
76
+ | `ABIDataTypes.UINT256` | Unsigned 256-bit integer | 32 bytes |
77
+
78
+ ### Address and Bytes Types
79
+
80
+ | Type | Description | Size |
81
+ |------|-------------|------|
82
+ | `ABIDataTypes.ADDRESS` | OPNet address | 32 bytes |
83
+ | `ABIDataTypes.BYTES` | Variable-length bytes | Variable |
84
+ | `ABIDataTypes.BYTES32` | Fixed 32-byte value | 32 bytes |
85
+
86
+ ### Other Types
87
+
88
+ | Type | Description | Size |
89
+ |------|-------------|------|
90
+ | `ABIDataTypes.BOOL` | Boolean value | 1 byte |
91
+ | `ABIDataTypes.STRING` | UTF-8 string | Variable |
92
+
93
+ ### Array Types
94
+
95
+ | Type | Description |
96
+ |------|-------------|
97
+ | `ABIDataTypes.ADDRESS_ARRAY` | Array of addresses |
98
+ | `ABIDataTypes.BYTES_ARRAY` | Array of byte arrays |
99
+ | `ABIDataTypes.UINT256_ARRAY` | Array of u256 values |
100
+
101
+ ## @method Decorator
102
+
103
+ The `@method` decorator defines input parameters for a contract method.
104
+
105
+ ### No Parameters
106
+
107
+ ```typescript
108
+ @method()
109
+ @returns({ name: 'supply', type: ABIDataTypes.UINT256 })
110
+ public totalSupply(_: Calldata): BytesWriter {
111
+ const writer = new BytesWriter(32);
112
+ writer.writeU256(this._totalSupply.value);
113
+ return writer;
114
+ }
115
+ ```
116
+
117
+ ### Single Parameter
118
+
119
+ ```typescript
120
+ @method({ name: 'owner', type: ABIDataTypes.ADDRESS })
121
+ @returns({ name: 'balance', type: ABIDataTypes.UINT256 })
122
+ public balanceOf(calldata: Calldata): BytesWriter {
123
+ const owner = calldata.readAddress();
124
+ const balance = this._balances.get(owner);
125
+
126
+ const writer = new BytesWriter(32);
127
+ writer.writeU256(balance);
128
+ return writer;
129
+ }
130
+ ```
131
+
132
+ ### Multiple Parameters
133
+
134
+ ```typescript
135
+ @method(
136
+ { name: 'to', type: ABIDataTypes.ADDRESS },
137
+ { name: 'amount', type: ABIDataTypes.UINT256 },
138
+ )
139
+ @emit('Transferred')
140
+ public transfer(calldata: Calldata): BytesWriter {
141
+ const to = calldata.readAddress();
142
+ const amount = calldata.readU256();
143
+
144
+ this._transfer(Blockchain.tx.sender, to, amount);
145
+
146
+ return new BytesWriter(0);
147
+ }
148
+ ```
149
+
150
+ ### Complex Parameters
151
+
152
+ ```typescript
153
+ @method(
154
+ { name: 'owner', type: ABIDataTypes.ADDRESS },
155
+ { name: 'spender', type: ABIDataTypes.ADDRESS },
156
+ { name: 'value', type: ABIDataTypes.UINT256 },
157
+ { name: 'deadline', type: ABIDataTypes.UINT64 },
158
+ { name: 'signature', type: ABIDataTypes.BYTES },
159
+ )
160
+ @emit('Approved')
161
+ public permit(calldata: Calldata): BytesWriter {
162
+ const owner = calldata.readAddress();
163
+ const spender = calldata.readAddress();
164
+ const value = calldata.readU256();
165
+ const deadline = calldata.readU64();
166
+ const signature = calldata.readBytesWithLength();
167
+
168
+ // ... implementation
169
+ return new BytesWriter(0);
170
+ }
171
+ ```
172
+
173
+ ### Named Method Override
174
+
175
+ When your method name differs from the ABI name:
176
+
177
+ ```typescript
178
+ @method('name') // ABI will use 'name' as the method name
179
+ @returns({ name: 'name', type: ABIDataTypes.STRING })
180
+ public fn_name(_: Calldata): BytesWriter {
181
+ // Method is called 'fn_name' in code but 'name' in ABI
182
+ const writer = new BytesWriter(this._name.value.length + 4);
183
+ writer.writeString(this._name.value);
184
+ return writer;
185
+ }
186
+ ```
187
+
188
+ ## @returns Decorator
189
+
190
+ The `@returns` decorator defines return values for a contract method.
191
+
192
+ ### Single Return Value
193
+
194
+ ```typescript
195
+ @method()
196
+ @returns({ name: 'decimals', type: ABIDataTypes.UINT8 })
197
+ public decimals(_: Calldata): BytesWriter {
198
+ const writer = new BytesWriter(1);
199
+ writer.writeU8(this._decimals.value);
200
+ return writer;
201
+ }
202
+ ```
203
+
204
+ ### Multiple Return Values
205
+
206
+ ```typescript
207
+ @method()
208
+ @returns(
209
+ { name: 'name', type: ABIDataTypes.STRING },
210
+ { name: 'symbol', type: ABIDataTypes.STRING },
211
+ { name: 'decimals', type: ABIDataTypes.UINT8 },
212
+ { name: 'totalSupply', type: ABIDataTypes.UINT256 },
213
+ )
214
+ public metadata(_: Calldata): BytesWriter {
215
+ const writer = new BytesWriter(256);
216
+ writer.writeString(this._name.value);
217
+ writer.writeString(this._symbol.value);
218
+ writer.writeU8(this._decimals.value);
219
+ writer.writeU256(this._totalSupply.value);
220
+ return writer;
221
+ }
222
+ ```
223
+
224
+ ### No Return Value
225
+
226
+ Methods that only mutate state:
227
+
228
+ ```typescript
229
+ @method(
230
+ { name: 'to', type: ABIDataTypes.ADDRESS },
231
+ { name: 'amount', type: ABIDataTypes.UINT256 },
232
+ )
233
+ @emit('Transferred')
234
+ public transfer(calldata: Calldata): BytesWriter {
235
+ const to = calldata.readAddress();
236
+ const amount = calldata.readU256();
237
+
238
+ this._transfer(Blockchain.tx.sender, to, amount);
239
+
240
+ return new BytesWriter(0); // Empty return
241
+ }
242
+ ```
243
+
244
+ ## @emit Decorator
245
+
246
+ The `@emit` decorator specifies which event a method emits. This is used for ABI generation but doesn't automatically emit the event - you must call `this.emitEvent()` in your implementation.
247
+
248
+ ```typescript
249
+ @method(
250
+ { name: 'to', type: ABIDataTypes.ADDRESS },
251
+ { name: 'amount', type: ABIDataTypes.UINT256 },
252
+ )
253
+ @emit('Transferred') // Indicates this method emits Transferred event
254
+ public transfer(calldata: Calldata): BytesWriter {
255
+ const to = calldata.readAddress();
256
+ const amount = calldata.readU256();
257
+ const from = Blockchain.tx.sender;
258
+
259
+ this._transfer(from, to, amount);
260
+
261
+ // You must still emit the event manually
262
+ this.emitEvent(new TransferredEvent(from, from, to, amount));
263
+
264
+ return new BytesWriter(0);
265
+ }
266
+ ```
267
+
268
+ ### How Decorators Work Together
269
+
270
+ ```mermaid
271
+ ---
272
+ config:
273
+ theme: dark
274
+ ---
275
+ flowchart LR
276
+ Code["Method with Decorators"] --> Extract["Extract Metadata"]
277
+ Extract --> GenSig["Generate Signature"]
278
+ GenSig --> Selector["Selector: 0xABCD1234"]
279
+ Selector --> ABI["ABI Entry"]
280
+ ABI --> Call["External Call"]
281
+ Call --> Match{"Match?"}
282
+ Match -->|Yes| Execute["Execute Method"]
283
+ Match -->|No| Next["Next Method"]
284
+ Execute --> Return["Return Result"]
285
+ ```
286
+
287
+ ## Complete Examples
288
+
289
+ ### Simple Getter
290
+
291
+ ```typescript
292
+ @method()
293
+ @returns({ name: 'owner', type: ABIDataTypes.ADDRESS })
294
+ public owner(_: Calldata): BytesWriter {
295
+ const writer = new BytesWriter(32);
296
+ writer.writeAddress(this._owner.value);
297
+ return writer;
298
+ }
299
+ ```
300
+
301
+ ### Getter with Parameter
302
+
303
+ ```typescript
304
+ @method({ name: 'tokenId', type: ABIDataTypes.UINT256 })
305
+ @returns({ name: 'owner', type: ABIDataTypes.ADDRESS })
306
+ public ownerOf(calldata: Calldata): BytesWriter {
307
+ const tokenId = calldata.readU256();
308
+ const owner = this._owners.get(tokenId);
309
+
310
+ if (owner.isZero()) {
311
+ throw new Revert('Token does not exist');
312
+ }
313
+
314
+ const writer = new BytesWriter(32);
315
+ writer.writeAddress(owner);
316
+ return writer;
317
+ }
318
+ ```
319
+
320
+ ### State-Mutating Method
321
+
322
+ ```typescript
323
+ @method(
324
+ { name: 'spender', type: ABIDataTypes.ADDRESS },
325
+ { name: 'amount', type: ABIDataTypes.UINT256 },
326
+ )
327
+ @emit('Approved')
328
+ public approve(calldata: Calldata): BytesWriter {
329
+ const spender = calldata.readAddress();
330
+ const amount = calldata.readU256();
331
+ const owner = Blockchain.tx.sender;
332
+
333
+ this._approve(owner, spender, amount);
334
+ this.emitEvent(new ApprovedEvent(owner, spender, amount));
335
+
336
+ return new BytesWriter(0);
337
+ }
338
+ ```
339
+
340
+ ### Method with Bytes Input
341
+
342
+ ```typescript
343
+ @method(ABIDataTypes.BYTES) // Shorthand for { name: 'data', type: ABIDataTypes.BYTES }
344
+ @returns({ name: 'valid', type: ABIDataTypes.BOOL })
345
+ public verifySignature(calldata: Calldata): BytesWriter {
346
+ const signature = calldata.readBytesWithLength();
347
+
348
+ const message = new BytesWriter(32);
349
+ message.writeString('Sign this message');
350
+ const messageHash = sha256(message.getBuffer());
351
+
352
+ const isValid = Blockchain.verifySignature(
353
+ Blockchain.tx.origin,
354
+ signature,
355
+ messageHash,
356
+ true
357
+ );
358
+
359
+ const writer = new BytesWriter(1);
360
+ writer.writeBoolean(isValid);
361
+ return writer;
362
+ }
363
+ ```
364
+
365
+ ### Full Token Transfer
366
+
367
+ ```typescript
368
+ @method(
369
+ { name: 'from', type: ABIDataTypes.ADDRESS },
370
+ { name: 'to', type: ABIDataTypes.ADDRESS },
371
+ { name: 'amount', type: ABIDataTypes.UINT256 },
372
+ )
373
+ @emit('Transferred')
374
+ public transferFrom(calldata: Calldata): BytesWriter {
375
+ const from = calldata.readAddress();
376
+ const to = calldata.readAddress();
377
+ const amount = calldata.readU256();
378
+ const spender = Blockchain.tx.sender;
379
+
380
+ // Check and update allowance
381
+ const currentAllowance = this._allowances.get(from).get(spender);
382
+ if (currentAllowance < amount) {
383
+ throw new Revert('Insufficient allowance');
384
+ }
385
+
386
+ // Deduct from allowance (unless unlimited)
387
+ if (currentAllowance != u256.Max) {
388
+ this._allowances.get(from).set(spender, SafeMath.sub(currentAllowance, amount));
389
+ }
390
+
391
+ // Transfer
392
+ this._transfer(from, to, amount);
393
+ this.emitEvent(new TransferredEvent(spender, from, to, amount));
394
+
395
+ return new BytesWriter(0);
396
+ }
397
+ ```
398
+
399
+ ## Best Practices
400
+
401
+ ### 1. Always Use Decorators for Public Methods
402
+
403
+ ```typescript
404
+ // Good - properly decorated
405
+ @method({ name: 'amount', type: ABIDataTypes.UINT256 })
406
+ @emit('Burned')
407
+ public burn(calldata: Calldata): BytesWriter {
408
+ // ...
409
+ return new BytesWriter(0);
410
+ }
411
+
412
+ // Bad - no decorators
413
+ public burn(calldata: Calldata): BytesWriter {
414
+ // Callers won't know the ABI
415
+ return new BytesWriter(0);
416
+ }
417
+ ```
418
+
419
+ ### 2. Match Read Order with Parameter Order
420
+
421
+ ```typescript
422
+ @method(
423
+ { name: 'to', type: ABIDataTypes.ADDRESS },
424
+ { name: 'amount', type: ABIDataTypes.UINT256 },
425
+ )
426
+ public transfer(calldata: Calldata): BytesWriter {
427
+ // Read in same order as @method parameters
428
+ const to = calldata.readAddress(); // First
429
+ const amount = calldata.readU256(); // Second
430
+ // ...
431
+ }
432
+ ```
433
+
434
+ ### 3. Use Descriptive Names
435
+
436
+ ```typescript
437
+ // Good - clear names
438
+ @method({ name: 'recipient', type: ABIDataTypes.ADDRESS })
439
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
440
+
441
+ // Less clear
442
+ @method({ name: 'a', type: ABIDataTypes.ADDRESS })
443
+ @returns({ name: 'r', type: ABIDataTypes.BOOL })
444
+ ```
445
+
446
+ ### 4. Group Related Returns
447
+
448
+ ```typescript
449
+ @method()
450
+ @returns(
451
+ { name: 'name', type: ABIDataTypes.STRING },
452
+ { name: 'symbol', type: ABIDataTypes.STRING },
453
+ { name: 'decimals', type: ABIDataTypes.UINT8 },
454
+ { name: 'totalSupply', type: ABIDataTypes.UINT256 },
455
+ { name: 'domainSeparator', type: ABIDataTypes.BYTES32 },
456
+ )
457
+ public metadata(_: Calldata): BytesWriter {
458
+ // Single call returns all token metadata
459
+ }
460
+ ```
461
+
462
+ ---
463
+
464
+ **Navigation:**
465
+ - Previous: [Events](./events.md)
466
+ - Next: [Security](./security.md)