@btc-vision/btc-runtime 1.10.11 → 1.11.0-alpha

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 (41) hide show
  1. package/README.md +48 -224
  2. package/SECURITY.md +38 -191
  3. package/docs/README.md +28 -0
  4. package/docs/advanced/contract-upgrades.md +537 -0
  5. package/docs/advanced/plugins.md +90 -25
  6. package/docs/api-reference/blockchain.md +48 -14
  7. package/docs/api-reference/storage.md +2 -111
  8. package/docs/contracts/op-net-base.md +22 -0
  9. package/docs/contracts/upgradeable.md +396 -0
  10. package/docs/core-concepts/blockchain-environment.md +0 -2
  11. package/docs/core-concepts/security.md +8 -111
  12. package/docs/core-concepts/storage-system.md +1 -32
  13. package/docs/examples/nft-with-reservations.md +8 -238
  14. package/docs/storage/memory-maps.md +1 -44
  15. package/docs/storage/stored-arrays.md +1 -65
  16. package/docs/storage/stored-maps.md +1 -73
  17. package/docs/storage/stored-primitives.md +2 -49
  18. package/docs/types/bytes-writer-reader.md +76 -0
  19. package/docs/types/safe-math.md +2 -45
  20. package/package.json +5 -5
  21. package/runtime/buffer/BytesReader.ts +90 -3
  22. package/runtime/buffer/BytesWriter.ts +81 -3
  23. package/runtime/contracts/OP721.ts +40 -4
  24. package/runtime/contracts/OP_NET.ts +83 -11
  25. package/runtime/contracts/Upgradeable.ts +242 -0
  26. package/runtime/env/BlockchainEnvironment.ts +124 -27
  27. package/runtime/env/global.ts +24 -0
  28. package/runtime/events/upgradeable/UpgradeableEvents.ts +41 -0
  29. package/runtime/generic/AddressMap.ts +20 -18
  30. package/runtime/generic/ExtendedAddressMap.ts +147 -0
  31. package/runtime/generic/MapUint8Array.ts +20 -18
  32. package/runtime/index.ts +8 -0
  33. package/runtime/plugins/Plugin.ts +34 -0
  34. package/runtime/plugins/UpgradeablePlugin.ts +279 -0
  35. package/runtime/storage/BaseStoredString.ts +1 -1
  36. package/runtime/storage/arrays/StoredPackedArray.ts +4 -0
  37. package/runtime/types/ExtendedAddress.ts +36 -24
  38. package/runtime/types/ExtendedAddressCache.ts +27 -0
  39. package/runtime/types/SafeMath.ts +109 -18
  40. package/runtime/types/SchnorrSignature.ts +44 -0
  41. package/runtime/utils/lengths.ts +2 -0
@@ -0,0 +1,396 @@
1
+ # Upgradeable
2
+
3
+ The `Upgradeable` base class provides a secure upgrade mechanism with configurable timelock protection. Contracts extending `Upgradeable` can replace their bytecode while giving users time to assess pending changes.
4
+
5
+ > **Alternative**: If you're already extending another base class (like `OP20` or `OP721`), use the [`UpgradeablePlugin`](../advanced/contract-upgrades.md#using-the-upgradeableplugin) instead. Just call `this.registerPlugin(new UpgradeablePlugin(144))` in your constructor - no other code changes needed!
6
+
7
+ ## Overview
8
+
9
+ ```typescript
10
+ import {
11
+ Upgradeable,
12
+ Calldata,
13
+ BytesWriter,
14
+ encodeSelector,
15
+ Selector,
16
+ ADDRESS_BYTE_LENGTH,
17
+ } from '@btc-vision/btc-runtime/runtime';
18
+
19
+ @final
20
+ export class MyContract extends Upgradeable {
21
+ // Set delay: 144 blocks = ~24 hours
22
+ protected readonly upgradeDelay: u64 = 144;
23
+
24
+ public override execute(method: Selector, calldata: Calldata): BytesWriter {
25
+ switch (method) {
26
+ case encodeSelector('submitUpgrade'):
27
+ return this.submitUpgrade(calldata.readAddress());
28
+ case encodeSelector('applyUpgrade'): {
29
+ const sourceAddress = calldata.readAddress();
30
+ const remainingLength = calldata.byteLength - ADDRESS_BYTE_LENGTH;
31
+ const updateCalldata = new BytesWriter(remainingLength);
32
+ if (remainingLength > 0) {
33
+ updateCalldata.writeBytes(calldata.readBytes(remainingLength));
34
+ }
35
+ return this.applyUpgrade(sourceAddress, updateCalldata);
36
+ }
37
+ case encodeSelector('cancelUpgrade'):
38
+ return this.cancelUpgrade();
39
+ default:
40
+ return super.execute(method, calldata);
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ ## Class Reference
47
+
48
+ ### Properties
49
+
50
+ | Property | Type | Description |
51
+ |----------|------|-------------|
52
+ | `upgradeDelay` | `u64` | Blocks to wait before upgrade can be applied (default: 144 = ~24h) |
53
+ | `pendingUpgradeAddress` | `Address` | Source address of pending upgrade (zero if none) |
54
+ | `pendingUpgradeBlock` | `u64` | Block when upgrade was submitted (0 if none) |
55
+ | `upgradeEffectiveBlock` | `u64` | Block when upgrade can be applied (0 if none) |
56
+ | `hasPendingUpgrade` | `bool` | Whether an upgrade is pending |
57
+ | `canApplyUpgrade` | `bool` | Whether the delay has elapsed |
58
+
59
+ ### Methods
60
+
61
+ #### submitUpgrade
62
+
63
+ Submits an upgrade for timelock. Only callable by deployer.
64
+
65
+ ```typescript
66
+ protected submitUpgrade(sourceAddress: Address): BytesWriter
67
+ ```
68
+
69
+ **Parameters:**
70
+ - `sourceAddress`: The address of the contract containing the new bytecode
71
+
72
+ **Reverts if:**
73
+ - Caller is not the deployer
74
+ - Source is not a deployed contract
75
+ - An upgrade is already pending
76
+
77
+ **Emits:** `UpgradeSubmitted(sourceAddress, submitBlock, effectiveBlock)`
78
+
79
+ #### applyUpgrade
80
+
81
+ Applies a pending upgrade after the delay has passed. Only callable by deployer.
82
+
83
+ ```typescript
84
+ protected applyUpgrade(sourceAddress: Address, calldata: BytesWriter): BytesWriter
85
+ ```
86
+
87
+ **Parameters:**
88
+ - `sourceAddress`: The source contract address (must match pending)
89
+ - `calldata`: Data passed to the `onUpdate` hook of the new contract
90
+
91
+ **Reverts if:**
92
+ - Caller is not the deployer
93
+ - No upgrade is pending
94
+ - Delay has not elapsed
95
+ - Address does not match pending upgrade
96
+
97
+ **Emits:** `UpgradeApplied(sourceAddress, appliedAtBlock)`
98
+
99
+ #### cancelUpgrade
100
+
101
+ Cancels a pending upgrade. Only callable by deployer.
102
+
103
+ ```typescript
104
+ protected cancelUpgrade(): BytesWriter
105
+ ```
106
+
107
+ **Reverts if:**
108
+ - Caller is not the deployer
109
+ - No upgrade is pending
110
+
111
+ **Emits:** `UpgradeCancelled(sourceAddress, cancelledAtBlock)`
112
+
113
+ ## Events
114
+
115
+ ### UpgradeSubmittedEvent
116
+
117
+ Emitted when an upgrade is submitted.
118
+
119
+ ```typescript
120
+ class UpgradeSubmittedEvent extends NetEvent {
121
+ constructor(
122
+ sourceAddress: Address, // Contract with new bytecode
123
+ submitBlock: u64, // Block when submitted
124
+ effectiveBlock: u64 // Block when can be applied
125
+ )
126
+ }
127
+ ```
128
+
129
+ ### UpgradeAppliedEvent
130
+
131
+ Emitted when an upgrade is applied.
132
+
133
+ ```typescript
134
+ class UpgradeAppliedEvent extends NetEvent {
135
+ constructor(
136
+ sourceAddress: Address, // Contract with new bytecode
137
+ appliedAtBlock: u64 // Block when applied
138
+ )
139
+ }
140
+ ```
141
+
142
+ ### UpgradeCancelledEvent
143
+
144
+ Emitted when a pending upgrade is cancelled.
145
+
146
+ ```typescript
147
+ class UpgradeCancelledEvent extends NetEvent {
148
+ constructor(
149
+ sourceAddress: Address, // Cancelled source contract
150
+ cancelledAtBlock: u64 // Block when cancelled
151
+ )
152
+ }
153
+ ```
154
+
155
+ ## Usage Patterns
156
+
157
+ ### Basic Upgradeable Contract
158
+
159
+ ```typescript
160
+ @final
161
+ export class SimpleUpgradeable extends Upgradeable {
162
+ protected readonly upgradeDelay: u64 = 144; // ~1 day
163
+
164
+ public override execute(method: Selector, calldata: Calldata): BytesWriter {
165
+ switch (method) {
166
+ case encodeSelector('submitUpgrade'):
167
+ return this.submitUpgrade(calldata.readAddress());
168
+ case encodeSelector('applyUpgrade'): {
169
+ const sourceAddress = calldata.readAddress();
170
+ const remainingLength = calldata.byteLength - ADDRESS_BYTE_LENGTH;
171
+ const updateCalldata = new BytesWriter(remainingLength);
172
+ if (remainingLength > 0) {
173
+ updateCalldata.writeBytes(calldata.readBytes(remainingLength));
174
+ }
175
+ return this.applyUpgrade(sourceAddress, updateCalldata);
176
+ }
177
+ case encodeSelector('cancelUpgrade'):
178
+ return this.cancelUpgrade();
179
+ default:
180
+ return super.execute(method, calldata);
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ ### With Upgrade Status Views
187
+
188
+ ```typescript
189
+ @final
190
+ export class UpgradeableWithViews extends Upgradeable {
191
+ protected readonly upgradeDelay: u64 = 1008; // ~1 week
192
+
193
+ public override execute(method: Selector, calldata: Calldata): BytesWriter {
194
+ switch (method) {
195
+ // Upgrade actions
196
+ case encodeSelector('submitUpgrade'):
197
+ return this.submitUpgrade(calldata.readAddress());
198
+ case encodeSelector('applyUpgrade'): {
199
+ const sourceAddress = calldata.readAddress();
200
+ const remainingLength = calldata.byteLength - ADDRESS_BYTE_LENGTH;
201
+ const updateCalldata = new BytesWriter(remainingLength);
202
+ if (remainingLength > 0) {
203
+ updateCalldata.writeBytes(calldata.readBytes(remainingLength));
204
+ }
205
+ return this.applyUpgrade(sourceAddress, updateCalldata);
206
+ }
207
+ case encodeSelector('cancelUpgrade'):
208
+ return this.cancelUpgrade();
209
+
210
+ // View methods
211
+ case encodeSelector('getPendingUpgrade'):
212
+ return this.getPendingUpgrade();
213
+ case encodeSelector('getUpgradeStatus'):
214
+ return this.getUpgradeStatus();
215
+
216
+ default:
217
+ return super.execute(method, calldata);
218
+ }
219
+ }
220
+
221
+ private getPendingUpgrade(): BytesWriter {
222
+ const response = new BytesWriter(32);
223
+ response.writeAddress(this.pendingUpgradeAddress);
224
+ return response;
225
+ }
226
+
227
+ private getUpgradeStatus(): BytesWriter {
228
+ const response = new BytesWriter(17);
229
+ response.writeBoolean(this.hasPendingUpgrade);
230
+ response.writeU64(this.pendingUpgradeBlock);
231
+ response.writeU64(this.upgradeEffectiveBlock);
232
+ return response;
233
+ }
234
+ }
235
+ ```
236
+
237
+ ### Emergency Upgrades (Not Recommended)
238
+
239
+ For contracts that need faster upgrades (use with caution):
240
+
241
+ ```typescript
242
+ @final
243
+ export class QuickUpgradeable extends Upgradeable {
244
+ // Only 6 blocks (~1 hour) - use only for emergencies
245
+ protected readonly upgradeDelay: u64 = 6;
246
+
247
+ // ... rest of implementation
248
+ }
249
+ ```
250
+
251
+ ## Security Considerations
252
+
253
+ ### 1. Delay Selection
254
+
255
+ Choose an appropriate delay based on your contract's risk profile:
256
+
257
+ | Contract Type | Recommended Delay |
258
+ |---------------|-------------------|
259
+ | Test/Development | 1-6 blocks |
260
+ | Standard DeFi | 144 blocks (~24 hours) |
261
+ | High-value vaults | 1008 blocks (~1 week) |
262
+ | Governance contracts | 4320 blocks (~1 month) |
263
+
264
+ ### 2. Source Validation
265
+
266
+ The `submitUpgrade` function validates that the source is a deployed contract. This prevents:
267
+ - Submitting non-existent addresses
268
+ - Last-minute malicious deployments
269
+
270
+ ### 3. Address Match Verification
271
+
272
+ The `applyUpgrade` function requires the address to match the pending upgrade. This prevents:
273
+ - Front-running attacks
274
+ - Address substitution attacks
275
+
276
+ ### 4. Storage Compatibility
277
+
278
+ When upgrading, ensure storage layout compatibility:
279
+
280
+ ```typescript
281
+ // V1 - Original
282
+ class ContractV1 extends Upgradeable {
283
+ private ptr1: u16 = Blockchain.nextPointer; // Pointer 1
284
+ private ptr2: u16 = Blockchain.nextPointer; // Pointer 2
285
+ }
286
+
287
+ // V2 - Add new pointers at the END
288
+ class ContractV2 extends Upgradeable {
289
+ private ptr1: u16 = Blockchain.nextPointer; // Pointer 1 (same)
290
+ private ptr2: u16 = Blockchain.nextPointer; // Pointer 2 (same)
291
+ private ptr3: u16 = Blockchain.nextPointer; // Pointer 3 (NEW)
292
+ }
293
+ ```
294
+
295
+ ## Upgrade Workflow
296
+
297
+ ```
298
+ 1. Deploy new bytecode contract
299
+ └─> Returns: newContractAddress
300
+
301
+ 2. Submit upgrade
302
+ └─> submitUpgrade(newContractAddress)
303
+ └─> Emits: UpgradeSubmitted
304
+
305
+ 3. Wait for delay
306
+ └─> Users can monitor and exit
307
+
308
+ 4. Apply upgrade
309
+ └─> applyUpgrade(newContractAddress)
310
+ └─> Emits: UpgradeApplied
311
+ └─> VM calls onUpdate() on new bytecode
312
+ └─> New bytecode active next block
313
+
314
+ 5. (Optional) Discard source contract
315
+ └─> Source contract can be abandoned
316
+ ```
317
+
318
+ ### The onUpdate Hook
319
+
320
+ Override `onUpdate` in your new contract version to perform migrations:
321
+
322
+ ```typescript
323
+ @final
324
+ export class MyContractV2 extends Upgradeable {
325
+ protected readonly upgradeDelay: u64 = 144;
326
+
327
+ // New storage added in V2
328
+ private newFeaturePointer: u16 = Blockchain.nextPointer;
329
+ private _newFeature: StoredU256;
330
+
331
+ public constructor() {
332
+ super();
333
+ this._newFeature = new StoredU256(this.newFeaturePointer, EMPTY_POINTER);
334
+ }
335
+
336
+ public override onUpdate(calldata: Calldata): void {
337
+ super.onUpdate(calldata);
338
+ // Initialize new storage
339
+ this._newFeature.value = u256.fromU64(100);
340
+ }
341
+
342
+ // ... execute() and other methods
343
+ }
344
+ ```
345
+
346
+ See [The onUpdate Lifecycle Hook](../advanced/contract-upgrades.md#the-onupdate-lifecycle-hook) for more details.
347
+
348
+ ## Combining with Other Base Classes
349
+
350
+ ### Upgradeable + ReentrancyGuard
351
+
352
+ ```typescript
353
+ // Create a combined base class
354
+ class UpgradeableWithReentrancy extends Upgradeable {
355
+ protected readonly reentrancyLevel: ReentrancyLevel = ReentrancyLevel.STANDARD;
356
+ private _locked: StoredBoolean;
357
+
358
+ protected constructor() {
359
+ super();
360
+ this._locked = new StoredBoolean(Blockchain.nextPointer, false);
361
+ }
362
+
363
+ protected nonReentrant(): void {
364
+ if (this._locked.value) {
365
+ throw new Revert('ReentrancyGuard: LOCKED');
366
+ }
367
+ this._locked.value = true;
368
+ }
369
+
370
+ protected releaseGuard(): void {
371
+ this._locked.value = false;
372
+ }
373
+ }
374
+
375
+ @final
376
+ export class SecureUpgradeableVault extends UpgradeableWithReentrancy {
377
+ // Implementation with both upgrade and reentrancy protection
378
+ }
379
+ ```
380
+
381
+ ## Solidity Comparison
382
+
383
+ | Feature | OpenZeppelin UUPS | OPNet Upgradeable |
384
+ |---------|-------------------|-------------------|
385
+ | Upgrade mechanism | delegatecall | Native bytecode replacement |
386
+ | Storage location | Implementation contract | Same contract |
387
+ | Proxy overhead | Yes | No |
388
+ | Timelock | Separate contract (optional) | Built-in |
389
+ | Events | Custom | Built-in |
390
+ | Cancel upgrade | Custom implementation | Built-in |
391
+
392
+ ---
393
+
394
+ **Navigation:**
395
+ - Previous: [ReentrancyGuard](./reentrancy-guard.md)
396
+ - Next: [Address Type](../types/address.md)
@@ -587,7 +587,6 @@ classDiagram
587
587
  +getBlockHash(blockNumber) Uint8Array
588
588
  +emit(event) void
589
589
  +log(data) void
590
- +registerPlugin(plugin) void
591
590
  }
592
591
 
593
592
  class Block {
@@ -715,7 +714,6 @@ export class MyContract extends OP_NET {
715
714
  | `Blockchain.getBlockHash()` | `Uint8Array` | Historical block hash |
716
715
  | `Blockchain.emit()` | `void` | Emit event |
717
716
  | `Blockchain.log()` | `void` | Debug logging (testing only) |
718
- | `Blockchain.registerPlugin()` | `void` | Register a plugin |
719
717
 
720
718
  ---
721
719
 
@@ -76,137 +76,34 @@ See [SafeMath API](../api-reference/safe-math.md) for complete reference.
76
76
 
77
77
  ## Reentrancy Protection
78
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
79
+ Reentrancy attacks occur when a contract calls back into itself before completing, allowing attackers to drain funds by repeatedly calling withdraw before the balance is updated.
108
80
 
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
81
+ **Solution:** Extend `ReentrancyGuard` to automatically protect all methods:
129
82
 
130
83
  ```typescript
131
84
  import { ReentrancyGuard, ReentrancyLevel } from '@btc-vision/btc-runtime/runtime';
132
85
 
133
86
  @final
134
87
  export class MyContract extends ReentrancyGuard {
135
- // Override the reentrancy level (STANDARD is the default)
136
88
  protected override readonly reentrancyLevel: ReentrancyLevel = ReentrancyLevel.STANDARD;
137
89
 
138
- public constructor() {
139
- super();
140
- }
141
-
142
90
  @method()
143
91
  public withdraw(calldata: Calldata): BytesWriter {
144
- // ReentrancyGuard automatically protects this method
92
+ // Protected automatically - re-entry attempts will revert
145
93
  const amount = this.balances.get(Blockchain.tx.sender);
146
-
147
- // Even if external call tries to re-enter, it will fail
148
94
  this.balances.set(Blockchain.tx.sender, u256.Zero);
149
95
  // ... transfer funds ...
150
-
151
96
  return new BytesWriter(0);
152
97
  }
153
98
  }
154
99
  ```
155
100
 
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.
101
+ | Mode | Description |
102
+ |------|-------------|
103
+ | `ReentrancyLevel.STANDARD` | Boolean lock (default) |
104
+ | `ReentrancyLevel.CALLBACK` | Depth counter for tracking |
208
105
 
209
- See [ReentrancyGuard](../contracts/reentrancy-guard.md) for detailed usage.
106
+ Both modes block reentrancy. See [ReentrancyGuard](../contracts/reentrancy-guard.md) for detailed explanation, attack diagrams, and advanced usage.
210
107
 
211
108
  ## Access Control
212
109
 
@@ -195,38 +195,7 @@ flowchart LR
195
195
  end
196
196
  ```
197
197
 
198
- ## CRITICAL: Map Implementation Warning
199
-
200
- > **DO NOT USE AssemblyScript's Built-in Map**
201
- >
202
- > When creating custom map implementations or extending map functionality, you **MUST** use the Map class from `@btc-vision/btc-runtime/runtime`, NOT the built-in AssemblyScript Map.
203
- >
204
- > **Why the AssemblyScript Map is broken for blockchain:**
205
- > - NOT optimized for blockchain storage patterns
206
- > - Does NOT handle Uint8Array buffers as keys correctly
207
- > - Does NOT work properly with Address key comparisons
208
- > - Will cause silent data corruption or key collisions
209
- >
210
- > **CORRECT:**
211
- > ```typescript
212
- > import { Map } from '@btc-vision/btc-runtime/runtime';
213
- >
214
- > export class MyCustomMap<V> extends Map<Address, V> {
215
- > // Your implementation
216
- > }
217
- > ```
218
- >
219
- > **WRONG:**
220
- > ```typescript
221
- > // DO NOT DO THIS - will break!
222
- > const map = new Map<Uint8Array, u256>(); // AssemblyScript Map
223
- > ```
224
- >
225
- > The btc-runtime Map is specifically designed to:
226
- > - Handle Address and Uint8Array key comparisons correctly
227
- > - Optimize for blockchain storage access patterns
228
- > - Support proper serialization for persistent storage
229
- > - Prevent key collisions with custom equality logic
198
+ > **Important:** Do NOT use AssemblyScript's built-in Map for blockchain storage. See [CRITICAL: Map Implementation Warning](../storage/stored-maps.md#critical-map-implementation-warning) for details.
230
199
 
231
200
  ## Pointer Allocation
232
201