@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,473 @@
1
+ # Security
2
+
3
+ Security is paramount in smart contract development. This guide covers OPNet's security mechanisms and best practices for writing secure contracts.
4
+
5
+ ## Security Mechanisms
6
+
7
+ OPNet provides several built-in security features:
8
+
9
+ | Feature | Description |
10
+ |---------|-------------|
11
+ | **SafeMath** | Overflow/underflow protection |
12
+ | **ReentrancyGuard** | Reentrancy attack prevention |
13
+ | **Access Control** | Role-based authorization |
14
+ | **Input Validation** | Calldata parsing with bounds checks |
15
+ | **Storage Safety** | SHA256-hashed storage keys |
16
+
17
+ ## SafeMath
18
+
19
+ ### The Problem
20
+
21
+ Integer overflow/underflow can cause critical bugs:
22
+
23
+ ```typescript
24
+ // DANGEROUS: Native arithmetic can overflow silently
25
+ const a: u256 = u256.Max;
26
+ const b: u256 = u256.One;
27
+ const result = a + b; // Wraps to 0!
28
+ ```
29
+
30
+ ### The Solution
31
+
32
+ Always use SafeMath for arithmetic:
33
+
34
+ ```typescript
35
+ import { SafeMath } from '@btc-vision/btc-runtime/runtime';
36
+ import { u256 } from '@btc-vision/as-bignum/assembly';
37
+
38
+ const a = u256.fromU64(100);
39
+ const b = u256.fromU64(50);
40
+
41
+ // Safe operations
42
+ const sum = SafeMath.add(a, b); // Reverts on overflow
43
+ const diff = SafeMath.sub(a, b); // Reverts on underflow
44
+ const product = SafeMath.mul(a, b); // Reverts on overflow
45
+ const quotient = SafeMath.div(a, b); // Reverts on division by zero
46
+ const remainder = SafeMath.mod(a, b); // Reverts on division by zero
47
+ ```
48
+
49
+ ### Solidity Comparison
50
+
51
+ In Solidity 0.8+, arithmetic operations revert on overflow/underflow by default. OPNet achieves the same behavior through SafeMath:
52
+
53
+ ```solidity
54
+ // Solidity 0.8+ - automatic overflow protection
55
+ uint256 result = a + b; // Reverts on overflow
56
+ ```
57
+
58
+ ```typescript
59
+ // OPNet - explicit SafeMath usage
60
+ const result = SafeMath.add(a, b); // Reverts on overflow
61
+ ```
62
+
63
+ ### SafeMath Operations
64
+
65
+ | Operation | Method | Behavior |
66
+ |-----------|--------|----------|
67
+ | Addition | `SafeMath.add(a, b)` | Reverts on overflow |
68
+ | Subtraction | `SafeMath.sub(a, b)` | Reverts on underflow |
69
+ | Multiplication | `SafeMath.mul(a, b)` | Reverts on overflow |
70
+ | Division | `SafeMath.div(a, b)` | Reverts on zero divisor |
71
+ | Modulo | `SafeMath.mod(a, b)` | Reverts on zero divisor |
72
+ | Power | `SafeMath.pow(base, exp)` | Reverts on overflow |
73
+ | Square Root | `SafeMath.sqrt(a)` | Newton-Raphson method |
74
+
75
+ See [SafeMath API](../api-reference/safe-math.md) for complete reference.
76
+
77
+ ## Reentrancy Protection
78
+
79
+ ### The Problem
80
+
81
+ Reentrancy attacks occur when a contract calls back into itself before completing:
82
+
83
+ ```
84
+ 1. User calls withdraw()
85
+ 2. Contract sends funds to User
86
+ 3. User's receive function calls withdraw() again
87
+ 4. Contract sends funds again (before updating balance)
88
+ 5. Repeat until drained
89
+ ```
90
+
91
+ ### Reentrancy Attack Sequence
92
+
93
+ ```mermaid
94
+ sequenceDiagram
95
+ participant Attacker
96
+ participant VulnerableContract
97
+ participant AttackerContract
98
+
99
+ Attacker->>VulnerableContract: withdraw()
100
+ activate VulnerableContract
101
+
102
+ Note over VulnerableContract: balance = 100<br/>Check balance
103
+
104
+ VulnerableContract->>AttackerContract: Transfer 100 tokens
105
+ activate AttackerContract
106
+
107
+ Note over AttackerContract: Receive callback triggered
108
+
109
+ AttackerContract->>VulnerableContract: withdraw() [RE-ENTER!]
110
+ activate VulnerableContract
111
+
112
+ Note over VulnerableContract: balance still = 100<br/>Check balance [BUG!]
113
+
114
+ VulnerableContract->>AttackerContract: Transfer 100 tokens AGAIN
115
+ deactivate VulnerableContract
116
+
117
+ AttackerContract-->>VulnerableContract: Return
118
+ deactivate AttackerContract
119
+
120
+ Note over VulnerableContract: balance = 0<br/>(Too late!)
121
+
122
+ VulnerableContract-->>Attacker: Complete
123
+ deactivate VulnerableContract
124
+
125
+ Note over Attacker: Stole 200 tokens!<br/>Expected: 100
126
+ ```
127
+
128
+ ### The Solution: ReentrancyGuard
129
+
130
+ ```typescript
131
+ import { ReentrancyGuard, ReentrancyLevel } from '@btc-vision/btc-runtime/runtime';
132
+
133
+ @final
134
+ export class MyContract extends ReentrancyGuard {
135
+ // Override the reentrancy level (STANDARD is the default)
136
+ protected override readonly reentrancyLevel: ReentrancyLevel = ReentrancyLevel.STANDARD;
137
+
138
+ public constructor() {
139
+ super();
140
+ }
141
+
142
+ @method()
143
+ public withdraw(calldata: Calldata): BytesWriter {
144
+ // ReentrancyGuard automatically protects this method
145
+ const amount = this.balances.get(Blockchain.tx.sender);
146
+
147
+ // Even if external call tries to re-enter, it will fail
148
+ this.balances.set(Blockchain.tx.sender, u256.Zero);
149
+ // ... transfer funds ...
150
+
151
+ return new BytesWriter(0);
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### ReentrancyGuard Mechanism Flow
157
+
158
+ ```mermaid
159
+ ---
160
+ config:
161
+ theme: dark
162
+ ---
163
+ flowchart LR
164
+ Start["Method Called"] --> Check{"Guard Active?"}
165
+ Check -->|Yes| Revert["REVERT"]
166
+ Check -->|No| SetGuard["Set Guard Flag"]
167
+ SetGuard --> Execute["Execute Logic"]
168
+ Execute --> External{"External Call?"}
169
+ External -->|Yes| Call["Call External"]
170
+ Call --> Detect{"Re-enter?"}
171
+ Detect -->|Yes| Block["REVERT: Blocked"]
172
+ Detect -->|No| Clear["Clear Guard"]
173
+ External -->|No| Clear
174
+ Clear --> Success["Transaction Success"]
175
+ ```
176
+
177
+ ### Guard Modes
178
+
179
+ | Mode | Description | Use Case |
180
+ |------|-------------|----------|
181
+ | `ReentrancyLevel.STANDARD` | Uses boolean lock, strict mutual exclusion | Default for most contracts |
182
+ | `ReentrancyLevel.CALLBACK` | Uses depth counter, still blocks reentrancy | Depth tracking use cases |
183
+
184
+ ```typescript
185
+ // STANDARD: No re-entry allowed, uses boolean lock (default)
186
+ protected override readonly reentrancyLevel: ReentrancyLevel = ReentrancyLevel.STANDARD;
187
+
188
+ // CALLBACK: No re-entry allowed, uses depth counter for tracking
189
+ protected override readonly reentrancyLevel: ReentrancyLevel = ReentrancyLevel.CALLBACK;
190
+ ```
191
+
192
+ ### Guard Mode Decision Tree
193
+
194
+ ```mermaid
195
+ ---
196
+ config:
197
+ theme: dark
198
+ ---
199
+ flowchart LR
200
+ Start{"External Calls?"}
201
+ Start -->|No| None["No Guard Needed"]
202
+ Start -->|Yes| Tracking{"Need Depth Tracking?"}
203
+ Tracking -->|No| Standard["STANDARD Mode"]
204
+ Tracking -->|Yes| CallbackMode["CALLBACK Mode"]
205
+ ```
206
+
207
+ Note: Both modes block reentrancy. STANDARD uses a boolean lock; CALLBACK uses a depth counter.
208
+
209
+ See [ReentrancyGuard](../contracts/reentrancy-guard.md) for detailed usage.
210
+
211
+ ## Access Control
212
+
213
+ ### onlyDeployer Pattern
214
+
215
+ ```typescript
216
+ @final
217
+ export class MyContract extends OP_NET {
218
+ public constructor() {
219
+ super();
220
+ }
221
+
222
+ @method()
223
+ public adminFunction(calldata: Calldata): BytesWriter {
224
+ // Only deployer can call
225
+ this.onlyDeployer(Blockchain.tx.sender);
226
+
227
+ // Admin logic...
228
+ return new BytesWriter(0);
229
+ }
230
+ }
231
+ ```
232
+
233
+ ### Solidity Comparison
234
+
235
+ ```solidity
236
+ // Solidity
237
+ modifier onlyOwner() {
238
+ require(msg.sender == owner, "Not owner");
239
+ _;
240
+ }
241
+ ```
242
+
243
+ ```typescript
244
+ // OPNet
245
+ protected onlyOwner(): void {
246
+ if (!Blockchain.tx.sender.equals(this.owner.value)) {
247
+ throw new Revert('Not owner');
248
+ }
249
+ }
250
+ ```
251
+
252
+ ### Custom Roles
253
+
254
+ ```typescript
255
+ @final
256
+ export class MyContract extends OP_NET {
257
+ private readonly adminPointer: u16 = Blockchain.nextPointer;
258
+ private readonly admin: StoredAddress = new StoredAddress(this.adminPointer, Address.zero());
259
+
260
+ private readonly mintersPointer: u16 = Blockchain.nextPointer;
261
+ private readonly minters: AddressMemoryMap;
262
+
263
+ public constructor() {
264
+ super();
265
+ this.minters = new AddressMemoryMap(this.mintersPointer);
266
+ }
267
+
268
+ protected onlyAdmin(): void {
269
+ if (!Blockchain.tx.sender.equals(this.admin.value)) {
270
+ throw new Revert('Not admin');
271
+ }
272
+ }
273
+
274
+ protected onlyMinter(): void {
275
+ if (this.minters.get(Blockchain.tx.sender).isZero()) {
276
+ throw new Revert('Not minter');
277
+ }
278
+ }
279
+
280
+ @method()
281
+ public mint(calldata: Calldata): BytesWriter {
282
+ this.onlyMinter();
283
+ // ...
284
+ return new BytesWriter(0);
285
+ }
286
+
287
+ @method()
288
+ public setMinter(calldata: Calldata): BytesWriter {
289
+ this.onlyAdmin();
290
+ const minter = calldata.readAddress();
291
+ this.minters.set(minter, u256.One);
292
+ return new BytesWriter(0);
293
+ }
294
+ }
295
+ ```
296
+
297
+ ## Input Validation
298
+
299
+ ### Validate All Inputs
300
+
301
+ ```typescript
302
+ @method()
303
+ public transfer(calldata: Calldata): BytesWriter {
304
+ const to = calldata.readAddress();
305
+ const amount = calldata.readU256();
306
+
307
+ // Validate recipient
308
+ if (to.equals(Address.zero())) {
309
+ throw new Revert('Cannot transfer to zero address');
310
+ }
311
+
312
+ // Validate amount
313
+ if (amount.isZero()) {
314
+ throw new Revert('Amount must be greater than zero');
315
+ }
316
+
317
+ // Validate balance
318
+ const balance = this.balances.get(Blockchain.tx.sender);
319
+ if (balance < amount) {
320
+ throw new Revert('Insufficient balance');
321
+ }
322
+
323
+ // ... proceed with transfer
324
+ }
325
+ ```
326
+
327
+ ### Common Validations
328
+
329
+ ```typescript
330
+ // Zero address check
331
+ if (address.equals(Address.zero())) {
332
+ throw new Revert('Invalid address');
333
+ }
334
+
335
+ // Self-transfer check
336
+ if (from.equals(to)) {
337
+ throw new Revert('Cannot transfer to self');
338
+ }
339
+
340
+ // Amount checks
341
+ if (amount.isZero()) {
342
+ throw new Revert('Amount is zero');
343
+ }
344
+ if (amount > maxAmount) {
345
+ throw new Revert('Amount exceeds maximum');
346
+ }
347
+
348
+ // Array bounds
349
+ if (index >= array.length) {
350
+ throw new Revert('Index out of bounds');
351
+ }
352
+ ```
353
+
354
+ ## Common Vulnerabilities
355
+
356
+ ### 1. Integer Overflow/Underflow
357
+
358
+ ```typescript
359
+ // VULNERABLE
360
+ const newBalance = balance + amount; // Can overflow!
361
+
362
+ // SAFE
363
+ const newBalance = SafeMath.add(balance, amount);
364
+ ```
365
+
366
+ ### 2. Reentrancy
367
+
368
+ ```typescript
369
+ // VULNERABLE
370
+ @method()
371
+ public withdraw(): void {
372
+ const amount = balances.get(sender);
373
+ externalCall(sender, amount); // Can re-enter!
374
+ balances.set(sender, u256.Zero);
375
+ }
376
+
377
+ // SAFE (Checks-Effects-Interactions pattern)
378
+ @method()
379
+ public withdraw(): void {
380
+ const amount = balances.get(sender);
381
+ balances.set(sender, u256.Zero); // Update state first
382
+ externalCall(sender, amount); // Then make external call
383
+ }
384
+ ```
385
+
386
+ ### 3. Access Control Bypass
387
+
388
+ ```typescript
389
+ // VULNERABLE
390
+ @method()
391
+ public mint(calldata: Calldata): void {
392
+ // No access control!
393
+ this._mint(calldata.readAddress(), calldata.readU256());
394
+ }
395
+
396
+ // SAFE
397
+ @method()
398
+ public mint(calldata: Calldata): void {
399
+ this.onlyDeployer(Blockchain.tx.sender);
400
+ this._mint(calldata.readAddress(), calldata.readU256());
401
+ }
402
+ ```
403
+
404
+ ### 4. tx.origin Authentication
405
+
406
+ ```typescript
407
+ // VULNERABLE (phishing attack possible)
408
+ @method()
409
+ public withdraw(): void {
410
+ if (Blockchain.tx.origin.equals(owner)) { // WRONG!
411
+ // ...
412
+ }
413
+ }
414
+
415
+ // SAFE
416
+ @method()
417
+ public withdraw(): void {
418
+ if (Blockchain.tx.sender.equals(owner)) { // Correct
419
+ // ...
420
+ }
421
+ }
422
+ ```
423
+
424
+ ### 5. Floating Point
425
+
426
+ ```typescript
427
+ // VULNERABLE (non-deterministic)
428
+ const price: f64 = 1.5; // NEVER use floats!
429
+
430
+ // SAFE (fixed-point)
431
+ const PRECISION: u256 = u256.fromU64(1_000_000);
432
+ const price: u256 = SafeMath.mul(u256.fromU64(15), SafeMath.div(PRECISION, u256.fromU64(10)));
433
+ ```
434
+
435
+ ## Security Checklist
436
+
437
+ Before deploying, verify:
438
+
439
+ - [ ] All arithmetic uses SafeMath
440
+ - [ ] ReentrancyGuard on sensitive functions
441
+ - [ ] Access control on admin functions
442
+ - [ ] Input validation on all public methods
443
+ - [ ] No floating-point arithmetic
444
+ - [ ] No tx.origin for authentication
445
+ - [ ] Events emitted for state changes
446
+ - [ ] Tests cover edge cases
447
+ - [ ] No hardcoded secrets
448
+
449
+ ## Audit Information
450
+
451
+ btc-runtime has been audited by [Verichains](https://verichains.io). The audit covered:
452
+
453
+ - Contract standards (OP20, OP721)
454
+ - Storage system security
455
+ - Cryptographic implementations
456
+ - SafeMath operations
457
+ - ReentrancyGuard mechanisms
458
+
459
+ See [SECURITY.md](../../SECURITY.md) for full audit details.
460
+
461
+ ## Reporting Vulnerabilities
462
+
463
+ If you discover a security issue:
464
+
465
+ 1. **DO NOT** open a public GitHub issue
466
+ 2. Report via [GitHub Security Advisories](https://github.com/btc-vision/btc-runtime/security/advisories)
467
+ 3. Allow time for fix before disclosure
468
+
469
+ ---
470
+
471
+ **Navigation:**
472
+ - Previous: [Events](./events.md)
473
+ - Next: [OP_NET Base Contract](../contracts/op-net-base.md)