@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.
- package/LICENSE +190 -0
- package/README.md +258 -137
- package/SECURITY.md +226 -0
- package/docs/README.md +614 -0
- package/docs/advanced/bitcoin-scripts.md +939 -0
- package/docs/advanced/cross-contract-calls.md +579 -0
- package/docs/advanced/plugins.md +1006 -0
- package/docs/advanced/quantum-resistance.md +660 -0
- package/docs/advanced/signature-verification.md +715 -0
- package/docs/api-reference/blockchain.md +729 -0
- package/docs/api-reference/events.md +642 -0
- package/docs/api-reference/op20.md +902 -0
- package/docs/api-reference/op721.md +819 -0
- package/docs/api-reference/safe-math.md +510 -0
- package/docs/api-reference/storage.md +840 -0
- package/docs/contracts/op-net-base.md +786 -0
- package/docs/contracts/op20-token.md +687 -0
- package/docs/contracts/op20s-signatures.md +614 -0
- package/docs/contracts/op721-nft.md +785 -0
- package/docs/contracts/reentrancy-guard.md +787 -0
- package/docs/core-concepts/blockchain-environment.md +724 -0
- package/docs/core-concepts/decorators.md +466 -0
- package/docs/core-concepts/events.md +652 -0
- package/docs/core-concepts/pointers.md +391 -0
- package/docs/core-concepts/security.md +473 -0
- package/docs/core-concepts/storage-system.md +969 -0
- package/docs/examples/basic-token.md +745 -0
- package/docs/examples/nft-with-reservations.md +1440 -0
- package/docs/examples/oracle-integration.md +1212 -0
- package/docs/examples/stablecoin.md +1180 -0
- package/docs/getting-started/first-contract.md +575 -0
- package/docs/getting-started/installation.md +384 -0
- package/docs/getting-started/project-structure.md +630 -0
- package/docs/storage/memory-maps.md +764 -0
- package/docs/storage/stored-arrays.md +778 -0
- package/docs/storage/stored-maps.md +758 -0
- package/docs/storage/stored-primitives.md +655 -0
- package/docs/types/address.md +773 -0
- package/docs/types/bytes-writer-reader.md +938 -0
- package/docs/types/calldata.md +744 -0
- package/docs/types/safe-math.md +446 -0
- package/package.json +51 -26
- package/runtime/memory/MapOfMap.ts +1 -0
- package/LICENSE.md +0 -21
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# Pointers
|
|
2
|
+
|
|
3
|
+
Pointers are the foundation of OPNet's storage system. Understanding how they work is essential for building efficient and secure smart contracts.
|
|
4
|
+
|
|
5
|
+
## What Are Pointers?
|
|
6
|
+
|
|
7
|
+
A pointer is a `u16` value (0-65535) that identifies a storage slot in your contract. Combined with an optional `u256` sub-pointer, it creates a unique storage key through SHA256 hashing.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Storage Key = SHA256(pointer || subPointer)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Pointer Structure Visualization
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
flowchart LR
|
|
17
|
+
subgraph Construction["32-Byte Storage Key Construction"]
|
|
18
|
+
A["Pointer<br/>(u16, 2 bytes)<br/>0x0003"]
|
|
19
|
+
B["SubPointer<br/>(u256, 30 bytes)<br/>0x00...ABC123"]
|
|
20
|
+
Concat["Concatenation (||)"]
|
|
21
|
+
Hash["SHA256 Hash"]
|
|
22
|
+
Key["Storage Key<br/>(32 bytes)<br/>0x7F3E...9A2D"]
|
|
23
|
+
|
|
24
|
+
A --> Concat
|
|
25
|
+
B --> Concat
|
|
26
|
+
Concat --> Hash
|
|
27
|
+
Hash --> Key
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Pointer Byte Layout
|
|
32
|
+
|
|
33
|
+
```mermaid
|
|
34
|
+
flowchart LR
|
|
35
|
+
subgraph Input["Input to SHA256 (32 bytes total)"]
|
|
36
|
+
P["Pointer<br/>2 bytes<br/>[0-1]"]
|
|
37
|
+
S["SubPointer<br/>30 bytes<br/>[2-31]"]
|
|
38
|
+
P --> S
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
subgraph Process["Hashing Process"]
|
|
42
|
+
Arrow["SHA256 Hash"]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
subgraph Result["Output"]
|
|
46
|
+
Output["Storage Key<br/>32 bytes"]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
S --> Arrow
|
|
50
|
+
Arrow --> Output
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Why Pointers?
|
|
54
|
+
|
|
55
|
+
OPNet's pointer system provides:
|
|
56
|
+
|
|
57
|
+
| Benefit | Description |
|
|
58
|
+
|---------|-------------|
|
|
59
|
+
| **Determinism** | Same inputs always produce same storage keys |
|
|
60
|
+
| **Collision Resistance** | SHA256 ensures unique keys |
|
|
61
|
+
| **Verifiability** | Storage proofs can be validated off-chain |
|
|
62
|
+
| **Explicitness** | Storage layout is explicit and auditable |
|
|
63
|
+
|
|
64
|
+
## Solidity Comparison
|
|
65
|
+
|
|
66
|
+
In Solidity, storage slots are assigned implicitly by the compiler. In OPNet, you explicitly allocate pointers at runtime:
|
|
67
|
+
|
|
68
|
+
```solidity
|
|
69
|
+
// Solidity - Implicit slot assignment
|
|
70
|
+
contract Token {
|
|
71
|
+
uint256 public totalSupply; // slot 0 (assigned by compiler)
|
|
72
|
+
string public name; // slot 1 (assigned by compiler)
|
|
73
|
+
mapping(address => uint256) balances; // slot 2 (assigned by compiler)
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// OPNet - Explicit pointer allocation
|
|
79
|
+
export class Token extends OP_NET {
|
|
80
|
+
private totalSupplyPointer: u16 = Blockchain.nextPointer; // ~0 (allocated at runtime)
|
|
81
|
+
private namePointer: u16 = Blockchain.nextPointer; // ~1 (allocated at runtime)
|
|
82
|
+
private balancesPointer: u16 = Blockchain.nextPointer; // ~2 (allocated at runtime)
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Storage Key Hashing Comparison
|
|
87
|
+
|
|
88
|
+
| Solidity | OPNet |
|
|
89
|
+
|----------|-------|
|
|
90
|
+
| Automatic slot assignment | Explicit pointer allocation |
|
|
91
|
+
| Slot 0, 1, 2, ... | `Blockchain.nextPointer` |
|
|
92
|
+
| `keccak256(key . slot)` | `SHA256(pointer \|\| subPointer)` |
|
|
93
|
+
|
|
94
|
+
## Allocating Pointers
|
|
95
|
+
|
|
96
|
+
### Basic Allocation
|
|
97
|
+
|
|
98
|
+
Use `Blockchain.nextPointer` to get unique pointers:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { Blockchain } from '@btc-vision/btc-runtime/runtime';
|
|
102
|
+
|
|
103
|
+
@final
|
|
104
|
+
export class MyContract extends OP_NET {
|
|
105
|
+
// Each call returns a unique, sequential u16
|
|
106
|
+
private counterPointer: u16 = Blockchain.nextPointer; // e.g., 0
|
|
107
|
+
private ownerPointer: u16 = Blockchain.nextPointer; // e.g., 1
|
|
108
|
+
private balancesPointer: u16 = Blockchain.nextPointer; // e.g., 2
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Pointer Range
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
u16 range: 0 to 65,535
|
|
116
|
+
|
|
117
|
+
Your contract can have up to 65,536 unique pointer slots.
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Important Rules
|
|
121
|
+
|
|
122
|
+
1. **Call `nextPointer` once per storage slot** - Don't reuse pointers
|
|
123
|
+
2. **Allocate at class level** - Pointers should be class properties
|
|
124
|
+
3. **Order matters** - Pointers are assigned sequentially
|
|
125
|
+
4. **Never hardcode** - Always use `Blockchain.nextPointer`
|
|
126
|
+
|
|
127
|
+
## Pointer vs Sub-Pointer
|
|
128
|
+
|
|
129
|
+
### Primary Pointer (u16)
|
|
130
|
+
|
|
131
|
+
The primary pointer identifies the **type** of storage:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
private balancesPointer: u16 = Blockchain.nextPointer; // "balances mapping"
|
|
135
|
+
private allowancesPointer: u16 = Blockchain.nextPointer; // "allowances mapping"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Sub-Pointer (u256)
|
|
139
|
+
|
|
140
|
+
The sub-pointer identifies a **specific entry** within that storage type:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// balances[address] = amount
|
|
144
|
+
// pointer = balancesPointer
|
|
145
|
+
// subPointer = address (converted to u256)
|
|
146
|
+
|
|
147
|
+
const key = SHA256(balancesPointer || addressAsU256);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Visual Example
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
Contract Storage
|
|
154
|
+
|
|
|
155
|
+
+-- Pointer 0 (totalSupply)
|
|
156
|
+
| +-- SubPointer 0 -> u256 value
|
|
157
|
+
|
|
|
158
|
+
+-- Pointer 1 (name)
|
|
159
|
+
| +-- SubPointer 0 -> string value
|
|
160
|
+
|
|
|
161
|
+
+-- Pointer 2 (balances mapping)
|
|
162
|
+
| +-- SubPointer 0xAAA... -> balance of 0xAAA
|
|
163
|
+
| +-- SubPointer 0xBBB... -> balance of 0xBBB
|
|
164
|
+
| +-- SubPointer 0xCCC... -> balance of 0xCCC
|
|
165
|
+
|
|
|
166
|
+
+-- Pointer 3 (allowances nested mapping)
|
|
167
|
+
+-- SubPointer hash(0xAAA, 0xBBB) -> allowance[AAA][BBB]
|
|
168
|
+
+-- SubPointer hash(0xAAA, 0xCCC) -> allowance[AAA][CCC]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Multiple Storage Variables Example
|
|
172
|
+
|
|
173
|
+
```mermaid
|
|
174
|
+
flowchart LR
|
|
175
|
+
subgraph Contract["Token Contract"]
|
|
176
|
+
Root["Contract Root"]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
subgraph SimpleValues["Simple Storage (Single Values)"]
|
|
180
|
+
P0["Pointer 0: totalSupply<br/>StoredU256"]
|
|
181
|
+
P1["Pointer 1: name<br/>StoredString"]
|
|
182
|
+
P2["Pointer 2: symbol<br/>StoredString"]
|
|
183
|
+
|
|
184
|
+
K0["Key: SHA256(0 || 0)<br/>Value: u256"]
|
|
185
|
+
K1["Key: SHA256(1 || 0)<br/>Value: 'MyToken'"]
|
|
186
|
+
K2["Key: SHA256(2 || 0)<br/>Value: 'MTK'"]
|
|
187
|
+
|
|
188
|
+
P0 --> K0
|
|
189
|
+
P1 --> K1
|
|
190
|
+
P2 --> K2
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
subgraph Mappings["Mappings (Multiple Values)"]
|
|
194
|
+
P3["Pointer 3: balances<br/>AddressMemoryMap"]
|
|
195
|
+
P4["Pointer 4: allowances<br/>MapOfMap"]
|
|
196
|
+
|
|
197
|
+
K3A["Key: SHA256(3 || 0xAAA...)<br/>Value: 1000"]
|
|
198
|
+
K3B["Key: SHA256(3 || 0xBBB...)<br/>Value: 500"]
|
|
199
|
+
K3C["Key: SHA256(3 || 0xCCC...)<br/>Value: 250"]
|
|
200
|
+
|
|
201
|
+
K4A["Key: SHA256(4 || hash(owner,spender1))<br/>Value: 100"]
|
|
202
|
+
K4B["Key: SHA256(4 || hash(owner,spender2))<br/>Value: 200"]
|
|
203
|
+
|
|
204
|
+
P3 --> K3A
|
|
205
|
+
P3 --> K3B
|
|
206
|
+
P3 --> K3C
|
|
207
|
+
|
|
208
|
+
P4 --> K4A
|
|
209
|
+
P4 --> K4B
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
Root --> P0
|
|
213
|
+
Root --> P1
|
|
214
|
+
Root --> P2
|
|
215
|
+
Root --> P3
|
|
216
|
+
Root --> P4
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Pointer Patterns
|
|
220
|
+
|
|
221
|
+
### Simple Value
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import { EMPTY_POINTER } from '@btc-vision/btc-runtime/runtime';
|
|
225
|
+
|
|
226
|
+
// Single value storage
|
|
227
|
+
private totalSupplyPointer: u16 = Blockchain.nextPointer;
|
|
228
|
+
private _totalSupply: StoredU256 = new StoredU256(
|
|
229
|
+
this.totalSupplyPointer,
|
|
230
|
+
EMPTY_POINTER
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Storage key: SHA256(totalSupplyPointer || 0)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Mapping
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// mapping(address => uint256)
|
|
240
|
+
private balancesPointer: u16 = Blockchain.nextPointer;
|
|
241
|
+
private balances: AddressMemoryMap = new AddressMemoryMap(this.balancesPointer);
|
|
242
|
+
|
|
243
|
+
// For balances[0xABC]:
|
|
244
|
+
// Storage key: SHA256(balancesPointer || 0xABC)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Nested Mapping
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// mapping(address => mapping(address => uint256))
|
|
251
|
+
private allowancesPointer: u16 = Blockchain.nextPointer;
|
|
252
|
+
|
|
253
|
+
// For allowances[owner][spender]:
|
|
254
|
+
// SubPointer = SHA256(owner || spender)
|
|
255
|
+
// Storage key: SHA256(allowancesPointer || SubPointer)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Array
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
// uint256[] holders
|
|
262
|
+
private holdersPointer: u16 = Blockchain.nextPointer;
|
|
263
|
+
private holders: StoredU256Array = new StoredU256Array(this.holdersPointer);
|
|
264
|
+
|
|
265
|
+
// For holders[i]:
|
|
266
|
+
// Storage key: SHA256(holdersPointer || i)
|
|
267
|
+
|
|
268
|
+
// For holders.length:
|
|
269
|
+
// Storage key: SHA256(holdersPointer || MAX_U256) // Special length slot
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Advanced: Manual Key Calculation
|
|
273
|
+
|
|
274
|
+
For advanced use cases, you can calculate storage keys manually:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { Blockchain, encodePointer } from '@btc-vision/btc-runtime/runtime';
|
|
278
|
+
|
|
279
|
+
// Generate storage key (32-byte hash)
|
|
280
|
+
const pointerHash = encodePointer(pointer, subPointer);
|
|
281
|
+
|
|
282
|
+
// Direct storage access
|
|
283
|
+
const stored = Blockchain.getStorageAt(pointerHash);
|
|
284
|
+
const value = u256.fromUint8ArrayBE(stored);
|
|
285
|
+
|
|
286
|
+
// Write to storage
|
|
287
|
+
Blockchain.setStorageAt(pointerHash, value.toUint8Array(true));
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### encodePointer() Function Flow
|
|
291
|
+
|
|
292
|
+
```mermaid
|
|
293
|
+
flowchart LR
|
|
294
|
+
A["pointer: u16<br/>subPointer: u256"] --> B["32-byte buffer<br/>[0-1] = pointer<br/>[2-31] = subPointer"]
|
|
295
|
+
B --> C["SHA256"]
|
|
296
|
+
C --> D["Storage Key<br/>(32 bytes)"]
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Collision Prevention
|
|
300
|
+
|
|
301
|
+
The SHA256 hashing ensures collision resistance:
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
// Different pointers = different keys
|
|
305
|
+
SHA256(0 || 0xABC) != SHA256(1 || 0xABC)
|
|
306
|
+
|
|
307
|
+
// Different sub-pointers = different keys
|
|
308
|
+
SHA256(0 || 0xABC) != SHA256(0 || 0xDEF)
|
|
309
|
+
|
|
310
|
+
// Even with same total bits
|
|
311
|
+
SHA256(0x0001 || 0x00...00) != SHA256(0x0000 || 0x00...01)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Best Practices
|
|
315
|
+
|
|
316
|
+
### 1. Document Your Pointer Layout
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
/**
|
|
320
|
+
* Storage Layout:
|
|
321
|
+
* Pointer 0: totalSupply (u256)
|
|
322
|
+
* Pointer 1: name (string)
|
|
323
|
+
* Pointer 2: symbol (string)
|
|
324
|
+
* Pointer 3: decimals (u8)
|
|
325
|
+
* Pointer 4: balances (address => u256)
|
|
326
|
+
* Pointer 5: allowances (address => address => u256)
|
|
327
|
+
* Pointer 6: paused (bool)
|
|
328
|
+
*/
|
|
329
|
+
export class MyToken extends OP20 {
|
|
330
|
+
// ... pointers allocated in this order
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### 2. Group Related Pointers
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
// Token metadata pointers
|
|
338
|
+
private namePointer: u16 = Blockchain.nextPointer;
|
|
339
|
+
private symbolPointer: u16 = Blockchain.nextPointer;
|
|
340
|
+
private decimalsPointer: u16 = Blockchain.nextPointer;
|
|
341
|
+
|
|
342
|
+
// Balance pointers
|
|
343
|
+
private balancesPointer: u16 = Blockchain.nextPointer;
|
|
344
|
+
private totalSupplyPointer: u16 = Blockchain.nextPointer;
|
|
345
|
+
|
|
346
|
+
// Approval pointers
|
|
347
|
+
private allowancesPointer: u16 = Blockchain.nextPointer;
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### 3. Never Reuse Pointers
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
// WRONG: Reusing pointer for different data
|
|
354
|
+
private myPointer: u16 = Blockchain.nextPointer;
|
|
355
|
+
private valueA: StoredU256 = new StoredU256(this.myPointer, EMPTY_POINTER);
|
|
356
|
+
private valueB: StoredU256 = new StoredU256(this.myPointer, EMPTY_POINTER); // BUG!
|
|
357
|
+
|
|
358
|
+
// CORRECT: Unique pointer for each
|
|
359
|
+
private pointerA: u16 = Blockchain.nextPointer;
|
|
360
|
+
private pointerB: u16 = Blockchain.nextPointer;
|
|
361
|
+
private valueA: StoredU256 = new StoredU256(this.pointerA, EMPTY_POINTER);
|
|
362
|
+
private valueB: StoredU256 = new StoredU256(this.pointerB, EMPTY_POINTER);
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 4. Understand Inheritance
|
|
366
|
+
|
|
367
|
+
When extending contracts, parent pointers are allocated first:
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
// OP20 allocates pointers 0-6 internally
|
|
371
|
+
export class MyToken extends OP20 {
|
|
372
|
+
// Your pointers start after OP20's
|
|
373
|
+
private customPointer: u16 = Blockchain.nextPointer; // ~7
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Debugging Pointers
|
|
378
|
+
|
|
379
|
+
To debug storage issues:
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
// Log pointer values during development
|
|
383
|
+
console.log(`Balance pointer: ${this.balancesPointer}`);
|
|
384
|
+
console.log(`Expected key: ${encodePointer(this.balancesPointer, addressAsU256)}`);
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
**Navigation:**
|
|
390
|
+
- Previous: [Storage System](./storage-system.md)
|
|
391
|
+
- Next: [Events](./events.md)
|