@btc-vision/btc-runtime 1.10.8 → 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 +52 -27
  43. package/runtime/memory/MapOfMap.ts +1 -0
  44. package/LICENSE.md +0 -21
@@ -0,0 +1,745 @@
1
+ # Basic Token Example
2
+
3
+ A complete, production-ready OP20 token implementation with minting, burning, and administrative controls.
4
+
5
+ ## Overview
6
+
7
+ This example demonstrates:
8
+ - OP20 token initialization
9
+ - Decorators (`@method`, `@returns`, `@emit`)
10
+ - Custom minting function
11
+ - Burn functionality
12
+ - Access control
13
+ - Event emission
14
+
15
+ ## Token Lifecycle
16
+
17
+ The token follows a standard lifecycle from deployment through minting, transfers, and burning:
18
+
19
+ ```mermaid
20
+ ---
21
+ config:
22
+ theme: dark
23
+ ---
24
+ graph LR
25
+ subgraph "👤 User Interactions"
26
+ A["Deploy Contract"]
27
+ B["Call mint"]
28
+ C["Call transfer"]
29
+ D["Call burn"]
30
+ end
31
+
32
+ subgraph "Bitcoin Layer"
33
+ E[Deploy TX]
34
+ F[Mint TX]
35
+ G[Transfer TX]
36
+ H[Burn TX]
37
+ end
38
+
39
+ subgraph "Contract Execution"
40
+ I[Initialize Token]
41
+ J[Mint Tokens]
42
+ K[Transfer Tokens]
43
+ L[Burn Tokens]
44
+ end
45
+
46
+ subgraph "Storage Operations"
47
+ M[Store Metadata]
48
+ N[Update Balances]
49
+ O[Update Total Supply]
50
+ P[Reduce Supply]
51
+ end
52
+
53
+ A --> E
54
+ E --> I
55
+ I --> M
56
+
57
+ B --> F
58
+ F --> J
59
+ J --> N
60
+ J --> O
61
+
62
+ C --> G
63
+ G --> K
64
+ K --> N
65
+
66
+ D --> H
67
+ H --> L
68
+ L --> N
69
+ L --> P
70
+ ```
71
+
72
+ ## Complete Implementation
73
+
74
+ ```typescript
75
+ import { u256 } from '@btc-vision/as-bignum/assembly';
76
+ import {
77
+ OP20,
78
+ OP20InitParameters,
79
+ Blockchain,
80
+ Address,
81
+ Calldata,
82
+ BytesWriter,
83
+ SafeMath,
84
+ Revert,
85
+ MintEvent,
86
+ BurnEvent,
87
+ ABIDataTypes,
88
+ } from '@btc-vision/btc-runtime/runtime';
89
+
90
+ @final
91
+ export class BasicToken extends OP20 {
92
+ public constructor() {
93
+ super();
94
+ }
95
+
96
+ /**
97
+ * Initialize the token on deployment.
98
+ * This is equivalent to Solidity's constructor.
99
+ */
100
+ public override onDeployment(calldata: Calldata): void {
101
+ // Read initialization parameters
102
+ const maxSupply = calldata.readU256();
103
+ const decimals = calldata.readU8();
104
+ const name = calldata.readString();
105
+ const symbol = calldata.readString();
106
+ const initialMintTo = calldata.readAddress();
107
+ const initialMintAmount = calldata.readU256();
108
+
109
+ // Validate decimals
110
+ if (decimals > 32) {
111
+ throw new Revert('Decimals cannot exceed 32');
112
+ }
113
+
114
+ // Validate initial mint doesn't exceed max supply
115
+ if (initialMintAmount > maxSupply) {
116
+ throw new Revert('Initial mint exceeds max supply');
117
+ }
118
+
119
+ // Initialize OP20
120
+ this.instantiate(new OP20InitParameters(maxSupply, decimals, name, symbol));
121
+
122
+ // Mint initial supply if specified
123
+ if (!initialMintAmount.isZero() && !initialMintTo.equals(Address.zero())) {
124
+ this._mint(initialMintTo, initialMintAmount);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Mint new tokens to an address.
130
+ * Only callable by the contract deployer.
131
+ */
132
+ @method(
133
+ { name: 'to', type: ABIDataTypes.ADDRESS },
134
+ { name: 'amount', type: ABIDataTypes.UINT256 },
135
+ )
136
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
137
+ @emit('Minted')
138
+ public mint(calldata: Calldata): BytesWriter {
139
+ // Access control
140
+ this.onlyDeployer(Blockchain.tx.sender);
141
+
142
+ // Read parameters
143
+ const to = calldata.readAddress();
144
+ const amount = calldata.readU256();
145
+
146
+ // Validate
147
+ if (to.equals(Address.zero())) {
148
+ throw new Revert('Cannot mint to zero address');
149
+ }
150
+
151
+ if (amount.isZero()) {
152
+ throw new Revert('Mint amount must be positive');
153
+ }
154
+
155
+ // Check max supply
156
+ const currentSupply = this.totalSupply();
157
+ const newSupply = SafeMath.add(currentSupply, amount);
158
+ if (newSupply > this.maxSupply()) {
159
+ throw new Revert('Mint would exceed max supply');
160
+ }
161
+
162
+ // Mint tokens
163
+ this._mint(to, amount);
164
+
165
+ // Emit event
166
+ this.emitEvent(new MintEvent(to, amount));
167
+
168
+ return new BytesWriter(0);
169
+ }
170
+
171
+ /**
172
+ * Burn tokens from the caller's balance.
173
+ */
174
+ @method({ name: 'amount', type: ABIDataTypes.UINT256 })
175
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
176
+ @emit('Burned')
177
+ public burn(calldata: Calldata): BytesWriter {
178
+ const amount = calldata.readU256();
179
+
180
+ // Validate
181
+ if (amount.isZero()) {
182
+ throw new Revert('Burn amount must be positive');
183
+ }
184
+
185
+ const sender = Blockchain.tx.sender;
186
+ const balance = this.balanceOf(sender);
187
+
188
+ if (balance < amount) {
189
+ throw new Revert('Burn amount exceeds balance');
190
+ }
191
+
192
+ // Burn tokens
193
+ this._burn(sender, amount);
194
+
195
+ // Emit event
196
+ this.emitEvent(new BurnEvent(sender, amount));
197
+
198
+ return new BytesWriter(0);
199
+ }
200
+
201
+ /**
202
+ * Burn tokens from another account using allowance.
203
+ */
204
+ @method(
205
+ { name: 'from', type: ABIDataTypes.ADDRESS },
206
+ { name: 'amount', type: ABIDataTypes.UINT256 },
207
+ )
208
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
209
+ @emit('Burned')
210
+ public burnFrom(calldata: Calldata): BytesWriter {
211
+ const from = calldata.readAddress();
212
+ const amount = calldata.readU256();
213
+ const sender = Blockchain.tx.sender;
214
+
215
+ // Check allowance
216
+ const currentAllowance = this.allowance(from, sender);
217
+ if (currentAllowance < amount) {
218
+ throw new Revert('Burn amount exceeds allowance');
219
+ }
220
+
221
+ // Check balance
222
+ const balance = this.balanceOf(from);
223
+ if (balance < amount) {
224
+ throw new Revert('Burn amount exceeds balance');
225
+ }
226
+
227
+ // Update allowance (unless unlimited)
228
+ if (!currentAllowance.equals(u256.Max)) {
229
+ this._approve(from, sender, SafeMath.sub(currentAllowance, amount));
230
+ }
231
+
232
+ // Burn tokens
233
+ this._burn(from, amount);
234
+
235
+ // Emit event
236
+ this.emitEvent(new BurnEvent(from, amount));
237
+
238
+ return new BytesWriter(0);
239
+ }
240
+
241
+ /**
242
+ * Get token metadata in a single call.
243
+ */
244
+ @method()
245
+ @returns(
246
+ { name: 'name', type: ABIDataTypes.STRING },
247
+ { name: 'symbol', type: ABIDataTypes.STRING },
248
+ { name: 'decimals', type: ABIDataTypes.UINT8 },
249
+ { name: 'totalSupply', type: ABIDataTypes.UINT256 },
250
+ { name: 'maxSupply', type: ABIDataTypes.UINT256 },
251
+ )
252
+ public tokenInfo(_: Calldata): BytesWriter {
253
+ const name = this._name.value;
254
+ const symbol = this._symbol.value;
255
+
256
+ const writer = new BytesWriter(256);
257
+ writer.writeString(name);
258
+ writer.writeString(symbol);
259
+ writer.writeU8(this._decimals.value);
260
+ writer.writeU256(this.totalSupply());
261
+ writer.writeU256(this.maxSupply());
262
+ return writer;
263
+ }
264
+ }
265
+ ```
266
+
267
+ ## Token Supply States
268
+
269
+ The token supply transitions through different states based on mint and burn operations:
270
+
271
+ ```mermaid
272
+ stateDiagram-v2
273
+ [*] --> Initialized: Deploy Contract
274
+ Initialized --> HasSupply: Initial Mint TX
275
+ HasSupply --> SupplyIncreased: mint() TX
276
+ SupplyIncreased --> HasSupply
277
+ HasSupply --> SupplyDecreased: burn() TX
278
+ SupplyDecreased --> HasSupply
279
+
280
+ note right of HasSupply
281
+ Storage: Current Supply <= Max Supply
282
+ Enforced on every mint operation
283
+ end note
284
+
285
+ note right of SupplyIncreased
286
+ Only deployer can mint
287
+ Max supply check performed
288
+ end note
289
+
290
+ note right of SupplyDecreased
291
+ Any holder can burn
292
+ Reduces total supply in storage
293
+ end note
294
+ ```
295
+
296
+ ## Mint Operation Flow
297
+
298
+ The mint operation includes multiple validation checks before updating storage:
299
+
300
+ ```mermaid
301
+ sequenceDiagram
302
+ participant User as 👤 User/Deployer
303
+ participant BTC as Bitcoin Network
304
+ participant Contract as Contract Execution
305
+ participant Storage as Storage Layer
306
+ participant Events as Event System
307
+
308
+ User->>BTC: Submit mint TX
309
+ BTC->>Contract: Execute mint(to, amount)
310
+ Contract->>Contract: onlyDeployer check
311
+ alt Not deployer
312
+ Contract-->>BTC: Revert: Not deployer
313
+ BTC-->>User: TX Failed
314
+ end
315
+
316
+ Contract->>Contract: Validate to != zero address
317
+ alt Invalid address
318
+ Contract-->>BTC: Revert: Zero address
319
+ BTC-->>User: TX Failed
320
+ end
321
+
322
+ Contract->>Contract: Validate amount > 0
323
+ alt Invalid amount
324
+ Contract-->>BTC: Revert: Amount must be positive
325
+ BTC-->>User: TX Failed
326
+ end
327
+
328
+ Contract->>Storage: Read current supply
329
+ Storage-->>Contract: currentSupply
330
+ Contract->>Contract: newSupply = current + amount
331
+ Contract->>Contract: Check newSupply <= maxSupply
332
+ alt Exceeds max supply
333
+ Contract-->>BTC: Revert: Exceeds max supply
334
+ BTC-->>User: TX Failed
335
+ end
336
+
337
+ Contract->>Contract: _mint(to, amount)
338
+ Contract->>Storage: Write balance updates
339
+ Contract->>Storage: Write totalSupply update
340
+ Storage-->>Contract: Success
341
+
342
+ Contract->>Events: Emit MintEvent(to, amount)
343
+ Events-->>BTC: Event logged
344
+ Contract-->>BTC: Success (BytesWriter)
345
+ BTC-->>User: TX Confirmed
346
+
347
+ Note over Contract,Storage: SafeMath used for all arithmetic
348
+ ```
349
+
350
+ ## Decorator Breakdown
351
+
352
+ ### Mint Method
353
+
354
+ The `@method` decorator defines the ABI parameters, `@returns` defines the return type, and `@emit` declares the event:
355
+
356
+ ```typescript
357
+ @method(
358
+ { name: 'to', type: ABIDataTypes.ADDRESS }, // First parameter
359
+ { name: 'amount', type: ABIDataTypes.UINT256 }, // Second parameter
360
+ )
361
+ @returns({ name: 'success', type: ABIDataTypes.BOOL }) // Return type
362
+ @emit('Minted') // Emits Minted event
363
+ public mint(calldata: Calldata): BytesWriter {
364
+ const to = calldata.readAddress(); // Read first param
365
+ const amount = calldata.readU256(); // Read second param
366
+ // ...
367
+ }
368
+ ```
369
+
370
+ **Solidity Comparison:**
371
+
372
+ ```solidity
373
+ // Solidity
374
+ function mint(address to, uint256 amount) external onlyOwner {
375
+ // ...
376
+ emit Minted(to, amount);
377
+ }
378
+
379
+ // OPNet
380
+ @method(
381
+ { name: 'to', type: ABIDataTypes.ADDRESS },
382
+ { name: 'amount', type: ABIDataTypes.UINT256 },
383
+ )
384
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
385
+ @emit('Minted')
386
+ public mint(calldata: Calldata): BytesWriter {
387
+ // ...
388
+ }
389
+ ```
390
+
391
+ ### Burn Method
392
+
393
+ Single parameter methods use a simplified decorator syntax:
394
+
395
+ ```typescript
396
+ @method({ name: 'amount', type: ABIDataTypes.UINT256 }) // Single parameter
397
+ @returns({ name: 'success', type: ABIDataTypes.BOOL }) // Return type
398
+ @emit('Burned')
399
+ public burn(calldata: Calldata): BytesWriter {
400
+ const amount = calldata.readU256();
401
+ // ...
402
+ }
403
+ ```
404
+
405
+ ### Getter with Multiple Returns
406
+
407
+ View functions use `@returns` to define output types:
408
+
409
+ ```typescript
410
+ @method() // No input parameters
411
+ @returns(
412
+ { name: 'name', type: ABIDataTypes.STRING },
413
+ { name: 'symbol', type: ABIDataTypes.STRING },
414
+ { name: 'decimals', type: ABIDataTypes.UINT8 },
415
+ { name: 'totalSupply', type: ABIDataTypes.UINT256 },
416
+ { name: 'maxSupply', type: ABIDataTypes.UINT256 },
417
+ )
418
+ public tokenInfo(_: Calldata): BytesWriter {
419
+ // ...
420
+ }
421
+ ```
422
+
423
+ ## Usage
424
+
425
+ ### Deployment
426
+
427
+ ```typescript
428
+ // Prepare deployment calldata
429
+ const writer = new BytesWriter(256);
430
+
431
+ // Parameters
432
+ writer.writeU256(u256.fromString('1000000000000000000000000')); // 1M max supply
433
+ writer.writeU8(18); // 18 decimals
434
+ writer.writeString('My Basic Token'); // name
435
+ writer.writeString('MBT'); // symbol
436
+ writer.writeAddress(deployerAddress); // initial mint to
437
+ writer.writeU256(u256.fromString('500000000000000000000000')); // 500k initial mint
438
+
439
+ const deployCalldata = writer.getBuffer();
440
+ ```
441
+
442
+ ### Minting
443
+
444
+ ```typescript
445
+ import { encodeSelector } from '@btc-vision/btc-runtime/runtime';
446
+
447
+ // Define selector (or use pre-computed u32)
448
+ const MINT_SELECTOR: u32 = 0x40c10f19; // mint(address,uint256)
449
+
450
+ // Prepare mint calldata
451
+ const writer = new BytesWriter(64);
452
+ writer.writeSelector(MINT_SELECTOR);
453
+ writer.writeAddress(recipientAddress);
454
+ writer.writeU256(u256.fromString('1000000000000000000000')); // 1000 tokens
455
+
456
+ const mintCalldata = writer.getBuffer();
457
+ ```
458
+
459
+ ### Burning
460
+
461
+ ```typescript
462
+ // Define selector (or use pre-computed u32)
463
+ const BURN_SELECTOR: u32 = 0x42966c68; // burn(uint256)
464
+
465
+ // Prepare burn calldata
466
+ const writer = new BytesWriter(36);
467
+ writer.writeSelector(BURN_SELECTOR);
468
+ writer.writeU256(u256.fromString('500000000000000000000')); // 500 tokens
469
+
470
+ const burnCalldata = writer.getBuffer();
471
+ ```
472
+
473
+ ## Key Concepts Demonstrated
474
+
475
+ ### 1. Decorators
476
+
477
+ Always use decorators for public methods to define the ABI:
478
+
479
+ ```typescript
480
+ // With decorators - proper ABI generation
481
+ @method({ name: 'to', type: ABIDataTypes.ADDRESS })
482
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
483
+ @emit('Transfer')
484
+ public transfer(calldata: Calldata): BytesWriter
485
+
486
+ // Without decorators - no ABI, hard for callers to use
487
+ public transfer(calldata: Calldata): BytesWriter
488
+ ```
489
+
490
+ ### 2. Access Control
491
+
492
+ ```typescript
493
+ public mint(calldata: Calldata): BytesWriter {
494
+ // Only deployer can call
495
+ this.onlyDeployer(Blockchain.tx.sender);
496
+ // ...
497
+ }
498
+ ```
499
+
500
+ **Solidity Comparison:**
501
+
502
+ ```solidity
503
+ // Solidity uses modifiers
504
+ modifier onlyOwner() {
505
+ require(msg.sender == owner, "Not owner");
506
+ _;
507
+ }
508
+
509
+ function mint(address to, uint256 amount) external onlyOwner { }
510
+
511
+ // OPNet uses inline checks
512
+ public mint(calldata: Calldata): BytesWriter {
513
+ this.onlyDeployer(Blockchain.tx.sender); // Throws if not deployer
514
+ // ...
515
+ }
516
+ ```
517
+
518
+ ### 3. Input Validation
519
+
520
+ ```typescript
521
+ // Zero address check
522
+ if (to.equals(Address.zero())) {
523
+ throw new Revert('Cannot mint to zero address');
524
+ }
525
+
526
+ // Zero amount check
527
+ if (amount.isZero()) {
528
+ throw new Revert('Mint amount must be positive');
529
+ }
530
+
531
+ // Supply cap check
532
+ if (newSupply > this.maxSupply()) {
533
+ throw new Revert('Mint would exceed max supply');
534
+ }
535
+ ```
536
+
537
+ ### 4. Event Emission
538
+
539
+ ```typescript
540
+ // Mint event
541
+ this.emitEvent(new MintEvent(to, amount));
542
+
543
+ // Burn event
544
+ this.emitEvent(new BurnEvent(from, amount));
545
+ ```
546
+
547
+ ### 5. Method Routing
548
+
549
+ Method routing is handled **AUTOMATICALLY** via `@method` decorators. You do NOT need to override the `execute` method:
550
+
551
+ ```typescript
552
+ // CORRECT: Use @method decorator - routing is automatic
553
+ @method(
554
+ { name: 'to', type: ABIDataTypes.ADDRESS },
555
+ { name: 'amount', type: ABIDataTypes.UINT256 },
556
+ )
557
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
558
+ @emit('Minted')
559
+ public mint(calldata: Calldata): BytesWriter {
560
+ // Implementation - runtime routes calls automatically
561
+ return new BytesWriter(0);
562
+ }
563
+
564
+ // DO NOT manually override execute() - decorators handle this
565
+ ```
566
+
567
+ ## Solidity Equivalent
568
+
569
+ For developers familiar with Solidity, here is the equivalent ERC20 implementation using OpenZeppelin:
570
+
571
+ ```solidity
572
+ // SPDX-License-Identifier: MIT
573
+ pragma solidity ^0.8.20;
574
+
575
+ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
576
+ import "@openzeppelin/contracts/access/Ownable.sol";
577
+
578
+ contract BasicToken is ERC20, Ownable {
579
+ uint256 public maxSupply;
580
+
581
+ event Minted(address indexed to, uint256 amount);
582
+ event Burned(address indexed from, uint256 amount);
583
+
584
+ constructor(
585
+ string memory name,
586
+ string memory symbol,
587
+ uint256 _maxSupply,
588
+ address initialMintTo,
589
+ uint256 initialMintAmount
590
+ ) ERC20(name, symbol) Ownable(msg.sender) {
591
+ maxSupply = _maxSupply;
592
+ if (initialMintAmount > 0 && initialMintTo != address(0)) {
593
+ require(initialMintAmount <= _maxSupply, "Initial mint exceeds max supply");
594
+ _mint(initialMintTo, initialMintAmount);
595
+ }
596
+ }
597
+
598
+ function mint(address to, uint256 amount) external onlyOwner {
599
+ require(to != address(0), "Cannot mint to zero address");
600
+ require(amount > 0, "Mint amount must be positive");
601
+ require(totalSupply() + amount <= maxSupply, "Mint would exceed max supply");
602
+ _mint(to, amount);
603
+ emit Minted(to, amount);
604
+ }
605
+
606
+ function burn(uint256 amount) external {
607
+ require(amount > 0, "Burn amount must be positive");
608
+ _burn(msg.sender, amount);
609
+ emit Burned(msg.sender, amount);
610
+ }
611
+
612
+ function burnFrom(address from, uint256 amount) external {
613
+ _spendAllowance(from, msg.sender, amount);
614
+ _burn(from, amount);
615
+ emit Burned(from, amount);
616
+ }
617
+
618
+ function tokenInfo() external view returns (
619
+ string memory name_,
620
+ string memory symbol_,
621
+ uint8 decimals_,
622
+ uint256 totalSupply_,
623
+ uint256 maxSupply_
624
+ ) {
625
+ return (name(), symbol(), decimals(), totalSupply(), maxSupply);
626
+ }
627
+ }
628
+ ```
629
+
630
+ ## Solidity vs OPNet Comparison
631
+
632
+ ### Key Differences Table
633
+
634
+ | Aspect | Solidity (ERC20) | OPNet (OP20) |
635
+ |--------|------------------|--------------|
636
+ | **Inheritance** | `contract MyToken is ERC20, Ownable` | `class MyToken extends OP20` |
637
+ | **Constructor** | `constructor() ERC20("Name", "SYM")` | `onDeployment()` + `this.instantiate(new OP20InitParameters(...))` |
638
+ | **Mint** | `_mint(to, amount)` | `this._mint(to, amount)` |
639
+ | **Burn** | `_burn(from, amount)` | `this._burn(from, amount)` |
640
+ | **Access Control** | `modifier onlyOwner()` | `this.onlyDeployer(Blockchain.tx.sender)` |
641
+ | **Events** | `event Minted(...); emit Minted(...)` | `@emit('Minted')` + `this.emitEvent(new MintEvent(...))` |
642
+ | **Function Declaration** | `function mint(address to, uint256 amount) external` | `@method({ name: 'to', type: ABIDataTypes.ADDRESS }, ...)` |
643
+ | **Return Values** | `returns (uint256)` | `@returns({ name: 'value', type: ABIDataTypes.UINT256 })` |
644
+ | **Msg.sender** | `msg.sender` | `Blockchain.tx.sender` |
645
+ | **Revert** | `require(condition, "message")` or `revert("message")` | `throw new Revert('message')` |
646
+ | **Safe Math** | Built-in (Solidity 0.8+) | `SafeMath.add()`, `SafeMath.sub()`, etc. |
647
+ | **Method Routing** | Automatic via function selectors | Automatic via `@method` decorators |
648
+
649
+ ### Structural Differences
650
+
651
+ **Solidity:**
652
+ ```solidity
653
+ // Function with modifier
654
+ function mint(address to, uint256 amount) external onlyOwner {
655
+ require(to != address(0), "Cannot mint to zero address");
656
+ _mint(to, amount);
657
+ emit Minted(to, amount);
658
+ }
659
+ ```
660
+
661
+ **OPNet:**
662
+ ```typescript
663
+ // Method with decorators
664
+ @method(
665
+ { name: 'to', type: ABIDataTypes.ADDRESS },
666
+ { name: 'amount', type: ABIDataTypes.UINT256 },
667
+ )
668
+ @returns({ name: 'success', type: ABIDataTypes.BOOL })
669
+ @emit('Minted')
670
+ public mint(calldata: Calldata): BytesWriter {
671
+ this.onlyDeployer(Blockchain.tx.sender);
672
+ const to = calldata.readAddress();
673
+ const amount = calldata.readU256();
674
+
675
+ if (to.equals(Address.zero())) {
676
+ throw new Revert('Cannot mint to zero address');
677
+ }
678
+
679
+ this._mint(to, amount);
680
+ this.emitEvent(new MintEvent(to, amount));
681
+ return new BytesWriter(0);
682
+ }
683
+ ```
684
+
685
+ ### Advantages of OPNet Approach
686
+
687
+ | Feature | Benefit |
688
+ |---------|---------|
689
+ | **TypeScript/AssemblyScript** | Familiar syntax for web developers, strong typing |
690
+ | **Explicit ABI via Decorators** | Self-documenting code, automatic ABI generation |
691
+ | **u256 Native Support** | First-class 256-bit integer support via `@btc-vision/as-bignum` |
692
+ | **Bitcoin Native** | Direct integration with Bitcoin's security model |
693
+ | **Unified Storage Pointers** | Consistent storage access pattern with `Blockchain.nextPointer` |
694
+ | **Predictable Execution** | Bitcoin transaction model provides predictable execution |
695
+ | **Automatic Method Routing** | `@method` decorators handle selector generation and routing |
696
+
697
+ ### Initialization Pattern Comparison
698
+
699
+ **Solidity (constructor runs once at deployment):**
700
+ ```solidity
701
+ constructor(string memory name, string memory symbol) ERC20(name, symbol) {
702
+ // Initialize state
703
+ }
704
+ ```
705
+
706
+ **OPNet (onDeployment called during contract deployment):**
707
+ ```typescript
708
+ public override onDeployment(calldata: Calldata): void {
709
+ const name = calldata.readString();
710
+ const symbol = calldata.readString();
711
+ this.instantiate(new OP20InitParameters(maxSupply, decimals, name, symbol));
712
+ }
713
+ ```
714
+
715
+ ### Event Emission Comparison
716
+
717
+ **Solidity:**
718
+ ```solidity
719
+ event Minted(address indexed to, uint256 amount);
720
+ // Later in code:
721
+ emit Minted(to, amount);
722
+ ```
723
+
724
+ **OPNet:**
725
+ ```typescript
726
+ // Event class definition
727
+ class MintEvent extends NetEvent {
728
+ constructor(public to: Address, public amount: u256) {
729
+ super('Minted');
730
+ }
731
+ protected override encodeData(writer: BytesWriter): void {
732
+ writer.writeAddress(this.to);
733
+ writer.writeU256(this.amount);
734
+ }
735
+ }
736
+
737
+ // Later in code:
738
+ this.emitEvent(new MintEvent(to, amount));
739
+ ```
740
+
741
+ ---
742
+
743
+ **Navigation:**
744
+ - Previous: [Plugins](../advanced/plugins.md)
745
+ - Next: [NFT with Reservations](./nft-with-reservations.md)