@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,729 @@
|
|
|
1
|
+
# Blockchain API Reference
|
|
2
|
+
|
|
3
|
+
The `Blockchain` singleton provides access to the runtime environment, storage, and blockchain operations.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { Blockchain } from '@btc-vision/btc-runtime/runtime';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Properties
|
|
12
|
+
|
|
13
|
+
### Block Context
|
|
14
|
+
|
|
15
|
+
| Property | Type | Description |
|
|
16
|
+
|----------|------|-------------|
|
|
17
|
+
| `Blockchain.block` | `Block` | Current block information |
|
|
18
|
+
| `Blockchain.block.number` | `u64` | Block height |
|
|
19
|
+
| `Blockchain.block.numberU256` | `u256` | Block height as u256 |
|
|
20
|
+
| `Blockchain.block.hash` | `Uint8Array` | 32-byte block hash |
|
|
21
|
+
| `Blockchain.block.medianTimestamp` | `u64` | Median timestamp (seconds) |
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
const blockNum = Blockchain.block.number;
|
|
25
|
+
const timestamp = Blockchain.block.medianTimestamp;
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Solidity Comparison:**
|
|
29
|
+
| Solidity | OPNet |
|
|
30
|
+
|----------|-------|
|
|
31
|
+
| `block.number` | `Blockchain.block.number` |
|
|
32
|
+
| `block.timestamp` | `Blockchain.block.medianTimestamp` |
|
|
33
|
+
|
|
34
|
+
### Transaction Context
|
|
35
|
+
|
|
36
|
+
| Property | Type | Description |
|
|
37
|
+
|----------|------|-------------|
|
|
38
|
+
| `Blockchain.tx` | `Transaction` | Current transaction info |
|
|
39
|
+
| `Blockchain.tx.sender` | `Address` | Immediate caller |
|
|
40
|
+
| `Blockchain.tx.origin` | `ExtendedAddress` | Original signer |
|
|
41
|
+
| `Blockchain.tx.txId` | `Uint8Array` | Transaction ID |
|
|
42
|
+
| `Blockchain.tx.hash` | `Uint8Array` | Transaction hash |
|
|
43
|
+
| `Blockchain.tx.inputs` | `TransactionInput[]` | Transaction inputs (UTXOs) |
|
|
44
|
+
| `Blockchain.tx.outputs` | `TransactionOutput[]` | Transaction outputs (UTXOs) |
|
|
45
|
+
| `Blockchain.tx.consensus` | `ConsensusRules` | Consensus rules |
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const caller = Blockchain.tx.sender; // Immediate caller
|
|
49
|
+
const signer = Blockchain.tx.origin; // Original signer
|
|
50
|
+
const unsafeAllowed = Blockchain.tx.consensus.unsafeSignaturesAllowed();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Solidity Comparison:**
|
|
54
|
+
| Solidity | OPNet |
|
|
55
|
+
|----------|-------|
|
|
56
|
+
| `msg.sender` | `Blockchain.tx.sender` |
|
|
57
|
+
| `tx.origin` | `Blockchain.tx.origin` |
|
|
58
|
+
|
|
59
|
+
### Contract Context
|
|
60
|
+
|
|
61
|
+
| Property | Type | Description |
|
|
62
|
+
|----------|------|-------------|
|
|
63
|
+
| `Blockchain.contract` | `OP_NET` | Current contract instance |
|
|
64
|
+
| `Blockchain.contractAddress` | `Address` | This contract's address |
|
|
65
|
+
| `Blockchain.contractDeployer` | `Address` | Deployer's address |
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const self = Blockchain.contractAddress;
|
|
69
|
+
const deployer = Blockchain.contractDeployer;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Solidity Comparison:**
|
|
73
|
+
| Solidity | OPNet |
|
|
74
|
+
|----------|-------|
|
|
75
|
+
| `address(this)` | `Blockchain.contractAddress` |
|
|
76
|
+
|
|
77
|
+
### Network Context
|
|
78
|
+
|
|
79
|
+
| Property | Type | Description |
|
|
80
|
+
|----------|------|-------------|
|
|
81
|
+
| `Blockchain.network` | `Networks` | Network identifier |
|
|
82
|
+
| `Blockchain.chainId` | `Uint8Array` | 32-byte chain ID |
|
|
83
|
+
| `Blockchain.protocolId` | `Uint8Array` | 32-byte protocol ID |
|
|
84
|
+
| `Blockchain.DEAD_ADDRESS` | `ExtendedAddress` | Burn address |
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
if (Blockchain.network === Networks.Mainnet) {
|
|
88
|
+
// Mainnet-specific logic
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Solidity Comparison:**
|
|
93
|
+
| Solidity | OPNet |
|
|
94
|
+
|----------|-------|
|
|
95
|
+
| `block.chainid` | `Blockchain.chainId` |
|
|
96
|
+
|
|
97
|
+
## Storage Architecture
|
|
98
|
+
|
|
99
|
+
### Storage Pointers
|
|
100
|
+
|
|
101
|
+
| Property | Type | Description |
|
|
102
|
+
|----------|------|-------------|
|
|
103
|
+
| `Blockchain.nextPointer` | `u16` | Get next storage pointer |
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
private myPointer: u16 = Blockchain.nextPointer;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The storage system uses a pointer-based architecture where each storage slot is identified by a unique hash:
|
|
110
|
+
|
|
111
|
+
```mermaid
|
|
112
|
+
graph LR
|
|
113
|
+
subgraph "Pointer Allocation"
|
|
114
|
+
A[Contract] -->|Allocate| B[Blockchain.nextPointer]
|
|
115
|
+
B -->|Returns u16<br/>0-65535| C[Pointer ID]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
subgraph "Key Generation"
|
|
119
|
+
C -->|Pointer u16| F[encodePointer]
|
|
120
|
+
D[SubPointer<br/>30 bytes] -->|Address/Key Data| F
|
|
121
|
+
F -->|SHA-256 Hash| G[32-byte Storage Key]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
subgraph "Storage Operations"
|
|
125
|
+
G -->|Read| H[getStorageAt<br/>Returns 32 bytes]
|
|
126
|
+
G -->|Write| I[setStorageAt<br/>Stores value]
|
|
127
|
+
G -->|Check| J[hasStorageAt<br/>Returns boolean]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
H --> K[Persistent Storage]
|
|
131
|
+
I --> K
|
|
132
|
+
J --> K
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Storage Methods
|
|
136
|
+
|
|
137
|
+
### encodePointer
|
|
138
|
+
|
|
139
|
+
Generates a storage key hash from a pointer and subPointer.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
encodePointer(pointer: u16, subPointer: Uint8Array): Uint8Array
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
| Parameter | Type | Description |
|
|
146
|
+
|-----------|------|-------------|
|
|
147
|
+
| `pointer` | `u16` | Storage slot identifier (0-65535) |
|
|
148
|
+
| `subPointer` | `Uint8Array` | Sub-index bytes (typically 30 bytes) |
|
|
149
|
+
| **Returns** | `Uint8Array` | 32-byte storage key hash |
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { encodePointer } from '@btc-vision/btc-runtime/runtime';
|
|
153
|
+
|
|
154
|
+
const pointer: u16 = Blockchain.nextPointer;
|
|
155
|
+
const subPointer = address.toBytes(); // or u256.toUint8Array(true)
|
|
156
|
+
|
|
157
|
+
// Generate storage key
|
|
158
|
+
const pointerHash = encodePointer(pointer, subPointer);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### getStorageAt
|
|
162
|
+
|
|
163
|
+
Reads from persistent storage.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
getStorageAt(pointerHash: Uint8Array): Uint8Array
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Parameter | Type | Description |
|
|
170
|
+
|-----------|------|-------------|
|
|
171
|
+
| `pointerHash` | `Uint8Array` | 32-byte storage key (from encodePointer) |
|
|
172
|
+
| **Returns** | `Uint8Array` | 32-byte value (zeros if unset) |
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { encodePointer } from '@btc-vision/btc-runtime/runtime';
|
|
176
|
+
|
|
177
|
+
// Create storage key
|
|
178
|
+
const pointerHash = encodePointer(pointer, subPointer);
|
|
179
|
+
|
|
180
|
+
// Read from storage
|
|
181
|
+
const stored = Blockchain.getStorageAt(pointerHash);
|
|
182
|
+
const value = u256.fromUint8ArrayBE(stored);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### setStorageAt
|
|
186
|
+
|
|
187
|
+
Writes to persistent storage.
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
setStorageAt(pointerHash: Uint8Array, value: Uint8Array): void
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
| Parameter | Type | Description |
|
|
194
|
+
|-----------|------|-------------|
|
|
195
|
+
| `pointerHash` | `Uint8Array` | 32-byte storage key (from encodePointer) |
|
|
196
|
+
| `value` | `Uint8Array` | Value to store (auto-padded to 32 bytes) |
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { encodePointer } from '@btc-vision/btc-runtime/runtime';
|
|
200
|
+
|
|
201
|
+
// Create storage key
|
|
202
|
+
const pointerHash = encodePointer(pointer, subPointer);
|
|
203
|
+
|
|
204
|
+
// Write to storage
|
|
205
|
+
Blockchain.setStorageAt(pointerHash, value.toUint8Array(true));
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### hasStorageAt
|
|
209
|
+
|
|
210
|
+
Checks if storage slot has non-zero value.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
hasStorageAt(pointerHash: Uint8Array): bool
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
const pointerHash = encodePointer(pointer, subPointer);
|
|
218
|
+
if (Blockchain.hasStorageAt(pointerHash)) {
|
|
219
|
+
// Slot has a value
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Storage Flow
|
|
224
|
+
|
|
225
|
+
The following sequence diagram illustrates the complete flow of storage operations:
|
|
226
|
+
|
|
227
|
+
```mermaid
|
|
228
|
+
sequenceDiagram
|
|
229
|
+
participant C as Contract
|
|
230
|
+
participant B as Blockchain
|
|
231
|
+
participant S as Storage Layer
|
|
232
|
+
|
|
233
|
+
Note over C,S: Storage Pointer Allocation
|
|
234
|
+
C->>B: Blockchain.nextPointer
|
|
235
|
+
B->>C: Returns u16 (e.g., 5)
|
|
236
|
+
|
|
237
|
+
Note over C,S: Write Operation
|
|
238
|
+
C->>C: address.toBytes() -> subPointer
|
|
239
|
+
C->>B: encodePointer(5, subPointer)
|
|
240
|
+
B->>B: SHA-256(pointer + subPointer)
|
|
241
|
+
B->>C: Returns 32-byte hash
|
|
242
|
+
C->>B: setStorageAt(hash, value)
|
|
243
|
+
B->>S: Persist to storage
|
|
244
|
+
|
|
245
|
+
Note over C,S: Read Operation
|
|
246
|
+
C->>B: encodePointer(5, subPointer)
|
|
247
|
+
B->>C: Returns 32-byte hash
|
|
248
|
+
C->>B: getStorageAt(hash)
|
|
249
|
+
S->>B: Retrieve value
|
|
250
|
+
B->>C: Returns 32-byte value
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Storage Pattern Example
|
|
254
|
+
|
|
255
|
+
Complete example showing the correct pattern:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { u256 } from '@btc-vision/as-bignum/assembly';
|
|
259
|
+
import {
|
|
260
|
+
Blockchain,
|
|
261
|
+
encodePointer,
|
|
262
|
+
Address
|
|
263
|
+
} from '@btc-vision/btc-runtime/runtime';
|
|
264
|
+
|
|
265
|
+
// Allocate pointer
|
|
266
|
+
private balancesPointer: u16 = Blockchain.nextPointer;
|
|
267
|
+
|
|
268
|
+
// Write balance
|
|
269
|
+
public setBalance(address: Address, amount: u256): void {
|
|
270
|
+
const pointerHash = encodePointer(this.balancesPointer, address.toBytes());
|
|
271
|
+
Blockchain.setStorageAt(pointerHash, amount.toUint8Array(true));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Read balance
|
|
275
|
+
public getBalance(address: Address): u256 {
|
|
276
|
+
const pointerHash = encodePointer(this.balancesPointer, address.toBytes());
|
|
277
|
+
const stored = Blockchain.getStorageAt(pointerHash);
|
|
278
|
+
return u256.fromUint8ArrayBE(stored);
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Solidity Comparison:**
|
|
283
|
+
| Solidity | OPNet |
|
|
284
|
+
|----------|-------|
|
|
285
|
+
| `mapping(address => uint256) balances` | `AddressMemoryMap` with pointer |
|
|
286
|
+
| `balances[addr] = value` | `Blockchain.setStorageAt(pointerHash, value)` |
|
|
287
|
+
| `balances[addr]` | `Blockchain.getStorageAt(pointerHash)` |
|
|
288
|
+
|
|
289
|
+
### Transient Storage (Experimental)
|
|
290
|
+
|
|
291
|
+
> **Warning:** Transient storage is NOT enabled in production. Only available in testing.
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
getTransientStorageAt(pointerHash: Uint8Array): Uint8Array
|
|
295
|
+
setTransientStorageAt(pointerHash: Uint8Array, value: Uint8Array): void
|
|
296
|
+
hasTransientStorageAt(pointerHash: Uint8Array): bool
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Cross-Contract Calls
|
|
300
|
+
|
|
301
|
+
### call
|
|
302
|
+
|
|
303
|
+
Calls another contract.
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
call(
|
|
307
|
+
destinationContract: Address,
|
|
308
|
+
calldata: BytesWriter,
|
|
309
|
+
stopExecutionOnFailure: boolean = true
|
|
310
|
+
): CallResult
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
| Parameter | Type | Description |
|
|
314
|
+
|-----------|------|-------------|
|
|
315
|
+
| `destinationContract` | `Address` | Target contract |
|
|
316
|
+
| `calldata` | `BytesWriter` | Encoded call data |
|
|
317
|
+
| `stopExecutionOnFailure` | `boolean` | Revert on failure (default: true) |
|
|
318
|
+
| **Returns** | `CallResult` | Success flag and response data |
|
|
319
|
+
|
|
320
|
+
The following diagram shows the two call patterns - standard calls that revert on failure, and try-catch style calls that handle failures gracefully:
|
|
321
|
+
|
|
322
|
+
```mermaid
|
|
323
|
+
flowchart LR
|
|
324
|
+
subgraph StdPattern["stopOnFailure = true"]
|
|
325
|
+
A1["Call"] --> B1{"Success?"}
|
|
326
|
+
B1 -->|"Yes"| C1["Continue"]
|
|
327
|
+
B1 -->|"No"| D1["REVERT TX"]
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
subgraph TryPattern["stopOnFailure = false"]
|
|
331
|
+
A2["Call"] --> B2{"Success?"}
|
|
332
|
+
B2 -->|"Yes"| C2["Continue"]
|
|
333
|
+
B2 -->|"No"| D2["Handle error"]
|
|
334
|
+
end
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Standard call - reverts on failure
|
|
339
|
+
const result = Blockchain.call(tokenAddress, calldata);
|
|
340
|
+
const balance = result.data.readU256();
|
|
341
|
+
|
|
342
|
+
// Try-catch pattern - handles failure gracefully
|
|
343
|
+
const result = Blockchain.call(tokenAddress, calldata, false);
|
|
344
|
+
if (result.success) {
|
|
345
|
+
// Process response
|
|
346
|
+
} else {
|
|
347
|
+
// Handle failure without reverting
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
The complete call flow with both success and failure scenarios:
|
|
352
|
+
|
|
353
|
+
```mermaid
|
|
354
|
+
sequenceDiagram
|
|
355
|
+
participant Caller as Calling Contract
|
|
356
|
+
participant BC as Blockchain
|
|
357
|
+
participant Target as Target Contract
|
|
358
|
+
|
|
359
|
+
Note over Caller,Target: Standard Call (stopExecutionOnFailure=true)
|
|
360
|
+
Caller->>Caller: Encode calldata (BytesWriter)
|
|
361
|
+
Caller->>BC: call(targetAddress, calldata, true)
|
|
362
|
+
BC->>Target: Execute method
|
|
363
|
+
|
|
364
|
+
alt Success Case
|
|
365
|
+
Target->>Target: Process request
|
|
366
|
+
Target->>BC: Return BytesWriter response
|
|
367
|
+
BC->>Caller: CallResult{success: true, data}
|
|
368
|
+
Caller->>Caller: Process response.data
|
|
369
|
+
else Failure Case
|
|
370
|
+
Target->>BC: Throw Revert
|
|
371
|
+
BC->>Caller: Transaction reverts
|
|
372
|
+
Note over Caller: Execution stops
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
Note over Caller,Target: Try-Catch Pattern (stopExecutionOnFailure=false)
|
|
376
|
+
Caller->>BC: call(targetAddress, calldata, false)
|
|
377
|
+
BC->>Target: Execute method
|
|
378
|
+
|
|
379
|
+
alt Success Case
|
|
380
|
+
Target->>BC: Return response
|
|
381
|
+
BC->>Caller: CallResult{success: true, data}
|
|
382
|
+
Caller->>Caller: Handle success
|
|
383
|
+
else Failure Case
|
|
384
|
+
Target->>BC: Throw Revert
|
|
385
|
+
BC->>Caller: CallResult{success: false, data}
|
|
386
|
+
Caller->>Caller: Handle failure gracefully
|
|
387
|
+
Note over Caller: Execution continues
|
|
388
|
+
end
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Solidity Comparison:**
|
|
392
|
+
| Solidity | OPNet |
|
|
393
|
+
|----------|-------|
|
|
394
|
+
| `target.call(data)` | `Blockchain.call(target, calldata, false)` |
|
|
395
|
+
| `target.functionCall(args)` | `Blockchain.call(target, calldata, true)` |
|
|
396
|
+
| `try target.call() { } catch { }` | `Blockchain.call(target, calldata, false)` + check `result.success` |
|
|
397
|
+
|
|
398
|
+
### CallResult
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
class CallResult {
|
|
402
|
+
readonly success: boolean;
|
|
403
|
+
readonly data: BytesReader;
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### deployContractFromExisting
|
|
408
|
+
|
|
409
|
+
Deploys a new contract from a template.
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
deployContractFromExisting(
|
|
413
|
+
existingAddress: Address,
|
|
414
|
+
salt: u256,
|
|
415
|
+
calldata: BytesWriter
|
|
416
|
+
): Address
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
| Parameter | Type | Description |
|
|
420
|
+
|-----------|------|-------------|
|
|
421
|
+
| `existingAddress` | `Address` | Template contract |
|
|
422
|
+
| `salt` | `u256` | Unique salt for address |
|
|
423
|
+
| `calldata` | `BytesWriter` | Constructor parameters |
|
|
424
|
+
| **Returns** | `Address` | New contract address |
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
const salt = u256.fromBytes(Blockchain.sha256(uniqueData));
|
|
428
|
+
const newContract = Blockchain.deployContractFromExisting(
|
|
429
|
+
templateAddress,
|
|
430
|
+
salt,
|
|
431
|
+
constructorData
|
|
432
|
+
);
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## Cryptographic Operations
|
|
436
|
+
|
|
437
|
+
### sha256
|
|
438
|
+
|
|
439
|
+
Computes SHA-256 hash.
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
sha256(buffer: Uint8Array): Uint8Array
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
const hash = Blockchain.sha256(data); // 32 bytes
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### hash256
|
|
450
|
+
|
|
451
|
+
Computes double SHA-256 (Bitcoin standard).
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
454
|
+
hash256(buffer: Uint8Array): Uint8Array
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
const txHash = Blockchain.hash256(txData); // 32 bytes
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Signature Verification
|
|
462
|
+
|
|
463
|
+
### verifySignature
|
|
464
|
+
|
|
465
|
+
Verifies signature based on current consensus rules.
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
verifySignature(
|
|
469
|
+
address: ExtendedAddress,
|
|
470
|
+
signature: Uint8Array,
|
|
471
|
+
hash: Uint8Array,
|
|
472
|
+
forceMLDSA: boolean = false
|
|
473
|
+
): boolean
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
| Parameter | Type | Description |
|
|
477
|
+
|-----------|------|-------------|
|
|
478
|
+
| `address` | `ExtendedAddress` | Signer's address |
|
|
479
|
+
| `signature` | `Uint8Array` | Signature bytes (64 for Schnorr, 2420+ for ML-DSA) |
|
|
480
|
+
| `hash` | `Uint8Array` | 32-byte message hash |
|
|
481
|
+
| `forceMLDSA` | `boolean` | Force ML-DSA verification |
|
|
482
|
+
| **Returns** | `boolean` | True if valid |
|
|
483
|
+
|
|
484
|
+
The signature verification selects the appropriate algorithm based on consensus rules:
|
|
485
|
+
|
|
486
|
+
```mermaid
|
|
487
|
+
flowchart LR
|
|
488
|
+
subgraph "verifySignature Flow"
|
|
489
|
+
Start([Verify Signature]) --> GetInput[Receive address,<br/>signature, hash]
|
|
490
|
+
GetInput --> CheckConsensus{unsafeSignaturesAllowed()<br/>AND !forceMLDSA?}
|
|
491
|
+
CheckConsensus -->|Yes| Schnorr[Schnorr Path]
|
|
492
|
+
CheckConsensus -->|No| MLDSA[ML-DSA Path]
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
subgraph "Schnorr Verification"
|
|
496
|
+
Schnorr --> ValidateSig{signature.length<br/>== 64?}
|
|
497
|
+
ValidateSig -->|Yes| SchnorrVerify[Verify Schnorr]
|
|
498
|
+
ValidateSig -->|No| SchnorrFail([Revert])
|
|
499
|
+
SchnorrVerify --> SchnorrResult{Valid?}
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
subgraph "ML-DSA Verification"
|
|
503
|
+
MLDSA --> MLDSAVerify[Verify ML-DSA-44<br/>Level2]
|
|
504
|
+
MLDSAVerify --> MLDSAResult{Valid?}
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
MLDSAResult -->|Yes| Success([Return true])
|
|
508
|
+
MLDSAResult -->|No| Fail([Return false])
|
|
509
|
+
SchnorrResult -->|Yes| Success
|
|
510
|
+
SchnorrResult -->|No| Fail
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
const isValid = Blockchain.verifySignature(
|
|
515
|
+
signerAddress,
|
|
516
|
+
signatureBytes,
|
|
517
|
+
messageHash
|
|
518
|
+
);
|
|
519
|
+
if (!isValid) {
|
|
520
|
+
throw new Revert('Invalid signature');
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
The complete EIP-712 style signature verification flow:
|
|
525
|
+
|
|
526
|
+
```mermaid
|
|
527
|
+
sequenceDiagram
|
|
528
|
+
participant C as Contract
|
|
529
|
+
participant BC as Blockchain
|
|
530
|
+
participant Cons as Consensus Layer
|
|
531
|
+
participant Crypto as Crypto Module
|
|
532
|
+
|
|
533
|
+
Note over C,Crypto: EIP-712 Style Signature Verification
|
|
534
|
+
C->>C: Build domain separator
|
|
535
|
+
C->>C: Hash struct data
|
|
536
|
+
C->>C: Combine: 0x1901 + domain + structHash
|
|
537
|
+
C->>C: messageHash = SHA-256(combined)
|
|
538
|
+
|
|
539
|
+
C->>BC: verifySignature(address, signature, messageHash, forceMLDSA?)
|
|
540
|
+
|
|
541
|
+
BC->>Cons: Check consensus flags
|
|
542
|
+
Cons->>BC: unsafeSignaturesAllowed()
|
|
543
|
+
|
|
544
|
+
alt unsafeSignaturesAllowed() AND !forceMLDSA
|
|
545
|
+
BC->>BC: Validate signature.length == 64
|
|
546
|
+
BC->>Crypto: verifySchnorr(tweakedPublicKey, sig, hash)
|
|
547
|
+
Crypto->>BC: Valid/Invalid
|
|
548
|
+
else ML-DSA required (consensus or forced)
|
|
549
|
+
BC->>BC: Use ML-DSA Level2 (ML-DSA-44)
|
|
550
|
+
BC->>Crypto: verifyMLDSA(Level2, mldsaPublicKey, sig, hash)
|
|
551
|
+
Crypto->>BC: Valid/Invalid
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
BC->>C: Return boolean
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
### verifyMLDSASignature
|
|
558
|
+
|
|
559
|
+
Verifies ML-DSA (quantum-resistant) signature.
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
verifyMLDSASignature(
|
|
563
|
+
level: MLDSASecurityLevel,
|
|
564
|
+
publicKey: Uint8Array,
|
|
565
|
+
signature: Uint8Array,
|
|
566
|
+
hash: Uint8Array
|
|
567
|
+
): boolean
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
| Parameter | Type | Description |
|
|
571
|
+
|-----------|------|-------------|
|
|
572
|
+
| `level` | `MLDSASecurityLevel` | Security level (Level2, Level3, Level5) |
|
|
573
|
+
| `publicKey` | `Uint8Array` | ML-DSA public key |
|
|
574
|
+
| `signature` | `Uint8Array` | ML-DSA signature |
|
|
575
|
+
| `hash` | `Uint8Array` | 32-byte message hash |
|
|
576
|
+
| **Returns** | `boolean` | True if valid |
|
|
577
|
+
|
|
578
|
+
```typescript
|
|
579
|
+
import { MLDSASecurityLevel } from '@btc-vision/btc-runtime/runtime';
|
|
580
|
+
|
|
581
|
+
const isValid = Blockchain.verifyMLDSASignature(
|
|
582
|
+
MLDSASecurityLevel.Level2, // ML-DSA-44
|
|
583
|
+
address.mldsaPublicKey, // 1312 bytes
|
|
584
|
+
signature, // 2420 bytes
|
|
585
|
+
messageHash // 32 bytes
|
|
586
|
+
);
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### verifySchnorrSignature (Deprecated)
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
verifySchnorrSignature(
|
|
593
|
+
publicKey: ExtendedAddress,
|
|
594
|
+
signature: Uint8Array,
|
|
595
|
+
hash: Uint8Array
|
|
596
|
+
): boolean
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
> **Note:** Use `verifySignature()` instead for automatic consensus migration.
|
|
600
|
+
|
|
601
|
+
## Utility Methods
|
|
602
|
+
|
|
603
|
+
### validateBitcoinAddress
|
|
604
|
+
|
|
605
|
+
Validates a Bitcoin address string.
|
|
606
|
+
|
|
607
|
+
```typescript
|
|
608
|
+
validateBitcoinAddress(address: string): bool
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
```typescript
|
|
612
|
+
if (!Blockchain.validateBitcoinAddress(userAddress)) {
|
|
613
|
+
throw new Revert('Invalid Bitcoin address');
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### isContract
|
|
618
|
+
|
|
619
|
+
Checks if an address is a contract.
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
isContract(address: Address): boolean
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
if (Blockchain.isContract(targetAddress)) {
|
|
627
|
+
// Is a contract, not EOA
|
|
628
|
+
}
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
**Solidity Comparison:**
|
|
632
|
+
| Solidity | OPNet |
|
|
633
|
+
|----------|-------|
|
|
634
|
+
| `address.code.length > 0` | `Blockchain.isContract(address)` |
|
|
635
|
+
|
|
636
|
+
### getAccountType
|
|
637
|
+
|
|
638
|
+
Gets account type code.
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
getAccountType(address: Address): u32
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
| Return Value | Meaning |
|
|
645
|
+
|--------------|---------|
|
|
646
|
+
| `0` | EOA or uninitialized |
|
|
647
|
+
| `>0` | Contract (type code) |
|
|
648
|
+
|
|
649
|
+
### getBlockHash
|
|
650
|
+
|
|
651
|
+
Retrieves historical block hash.
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
getBlockHash(blockNumber: u64): Uint8Array
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
const hash = Blockchain.getBlockHash(Blockchain.block.number - 10);
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
> **Warning:** Only ~256 recent blocks available. Older blocks return zeros.
|
|
662
|
+
|
|
663
|
+
**Solidity Comparison:**
|
|
664
|
+
| Solidity | OPNet |
|
|
665
|
+
|----------|-------|
|
|
666
|
+
| `blockhash(blockNumber)` | `Blockchain.getBlockHash(blockNumber)` |
|
|
667
|
+
|
|
668
|
+
## Event Methods
|
|
669
|
+
|
|
670
|
+
### emit
|
|
671
|
+
|
|
672
|
+
Emits an event.
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
emit(event: NetEvent): void
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
Blockchain.emit(new TransferEvent(from, to, amount));
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
**Solidity Comparison:**
|
|
683
|
+
| Solidity | OPNet |
|
|
684
|
+
|----------|-------|
|
|
685
|
+
| `emit Transfer(from, to, amount)` | `Blockchain.emit(new TransferEvent(from, to, amount))` |
|
|
686
|
+
|
|
687
|
+
### log
|
|
688
|
+
|
|
689
|
+
Logs debug message (testing only).
|
|
690
|
+
|
|
691
|
+
```typescript
|
|
692
|
+
log(data: string): void
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
> **Warning:** Only available in unit testing framework.
|
|
696
|
+
|
|
697
|
+
```typescript
|
|
698
|
+
Blockchain.log('Debug: operation started');
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
## Plugin Methods
|
|
702
|
+
|
|
703
|
+
### registerPlugin
|
|
704
|
+
|
|
705
|
+
Registers a plugin.
|
|
706
|
+
|
|
707
|
+
```typescript
|
|
708
|
+
registerPlugin(plugin: Plugin): void
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
```typescript
|
|
712
|
+
Blockchain.registerPlugin(new MyPlugin());
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
## Lifecycle Hooks
|
|
716
|
+
|
|
717
|
+
These are called by the runtime:
|
|
718
|
+
|
|
719
|
+
| Method | When Called |
|
|
720
|
+
|--------|-------------|
|
|
721
|
+
| `onDeployment(calldata)` | Contract deployment |
|
|
722
|
+
| `onExecutionStarted(selector, calldata)` | Before method execution |
|
|
723
|
+
| `onExecutionCompleted(selector, calldata)` | After successful execution |
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
**Navigation:**
|
|
728
|
+
- Previous: [Oracle Integration](../examples/oracle-integration.md)
|
|
729
|
+
- Next: [OP20 API](./op20.md)
|