@btc-vision/btc-runtime 1.10.10 → 1.10.12

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 (45) 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 +731 -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 +370 -0
  26. package/docs/core-concepts/storage-system.md +938 -0
  27. package/docs/examples/basic-token.md +745 -0
  28. package/docs/examples/nft-with-reservations.md +1210 -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 +721 -0
  35. package/docs/storage/stored-arrays.md +714 -0
  36. package/docs/storage/stored-maps.md +686 -0
  37. package/docs/storage/stored-primitives.md +608 -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 +403 -0
  42. package/package.json +51 -26
  43. package/runtime/memory/MapOfMap.ts +1 -0
  44. package/runtime/types/SafeMath.ts +121 -1
  45. package/LICENSE.md +0 -21
@@ -0,0 +1,744 @@
1
+ # Calldata
2
+
3
+ The `Calldata` type handles parsing of input parameters passed to contract methods. It provides methods to read various data types in sequence.
4
+
5
+ ## Overview
6
+
7
+ ```typescript
8
+ import { Calldata, Address, BytesWriter } from '@btc-vision/btc-runtime/runtime';
9
+ import { u256 } from '@btc-vision/as-bignum/assembly';
10
+
11
+ public transfer(calldata: Calldata): BytesWriter {
12
+ // Read parameters in order
13
+ const to: Address = calldata.readAddress();
14
+ const amount: u256 = calldata.readU256();
15
+
16
+ // ... process transfer
17
+
18
+ return new BytesWriter(0);
19
+ }
20
+ ```
21
+
22
+ ### Calldata Architecture
23
+
24
+ ```mermaid
25
+ classDiagram
26
+ class Calldata {
27
+ <<extends BytesReader>>
28
+ +readU8() u8
29
+ +readU16(be) u16
30
+ +readU32(be) u32
31
+ +readU64(be) u64
32
+ +readU128(be) u128
33
+ +readU256(be) u256
34
+ +readI8() i8
35
+ +readI16() i16
36
+ +readI32() i32
37
+ +readI64(be) i64
38
+ +readI128(be) i128
39
+ +readAddress() Address
40
+ +readString(length) string
41
+ +readStringWithLength(be) string
42
+ +readBytes(length) Uint8Array
43
+ +readBytesWithLength(be) Uint8Array
44
+ +readBoolean() bool
45
+ +readSelector() Selector
46
+ +readAddressArray(be) Address[]
47
+ +readU256Array(be) u256[]
48
+ +readAddressMapU256(be) AddressMap~u256~
49
+ +getOffset() i32
50
+ +setOffset(offset) void
51
+ +byteLength i32
52
+ }
53
+
54
+ class BytesReader {
55
+ -DataView buffer
56
+ -i32 currentOffset
57
+ +readU8() u8
58
+ +readU32() u32
59
+ +readU256() u256
60
+ }
61
+
62
+ class Contract {
63
+ +transfer(calldata: Calldata) BytesWriter
64
+ +approve(calldata: Calldata) BytesWriter
65
+ +balanceOf(calldata: Calldata) BytesWriter
66
+ }
67
+
68
+ BytesReader <|-- Calldata : extends
69
+ Contract --> Calldata : receives
70
+
71
+ note for Calldata "Sequential parameter reading\nfrom encoded transaction data"
72
+ note for Contract "All public methods\nreceive Calldata"
73
+ ```
74
+
75
+ ## Reading Data
76
+
77
+ ### Primitive Types
78
+
79
+ ```typescript
80
+ // Boolean (1 byte)
81
+ const flag: bool = calldata.readBoolean();
82
+
83
+ // Unsigned integers
84
+ const u8val: u8 = calldata.readU8();
85
+ const u16val: u16 = calldata.readU16();
86
+ const u32val: u32 = calldata.readU32();
87
+ const u64val: u64 = calldata.readU64();
88
+ const u128val: u128 = calldata.readU128();
89
+ const u256val: u256 = calldata.readU256();
90
+
91
+ // Signed integers
92
+ const i8val: i8 = calldata.readI8();
93
+ const i16val: i16 = calldata.readI16();
94
+ const i32val: i32 = calldata.readI32();
95
+ const i64val: i64 = calldata.readI64();
96
+ ```
97
+
98
+ ### Complex Types
99
+
100
+ ```typescript
101
+ // Address (32 bytes)
102
+ const addr: Address = calldata.readAddress();
103
+
104
+ // String with u32 length prefix
105
+ const name: string = calldata.readStringWithLength();
106
+
107
+ // String with known length (stops at null byte)
108
+ const fixedName: string = calldata.readString(32);
109
+
110
+ // Bytes with u32 length prefix
111
+ const data: Uint8Array = calldata.readBytesWithLength();
112
+
113
+ // Bytes with known length
114
+ const fixedData: Uint8Array = calldata.readBytes(64);
115
+
116
+ // Selector (4 bytes, big-endian)
117
+ const selector: Selector = calldata.readSelector();
118
+ ```
119
+
120
+ ### Arrays
121
+
122
+ All array methods expect a u16 length prefix (max 65535 elements):
123
+
124
+ ```typescript
125
+ // Array of addresses
126
+ const addresses: Address[] = calldata.readAddressArray();
127
+
128
+ // Numeric arrays
129
+ const u8Values: u8[] = calldata.readU8Array();
130
+ const u16Values: u16[] = calldata.readU16Array();
131
+ const u32Values: u32[] = calldata.readU32Array();
132
+ const u64Values: u64[] = calldata.readU64Array();
133
+ const u128Values: u128[] = calldata.readU128Array();
134
+ const u256Values: u256[] = calldata.readU256Array();
135
+
136
+ // Array of variable-length buffers
137
+ const buffers: Uint8Array[] = calldata.readArrayOfBuffer();
138
+ ```
139
+
140
+ ### Maps
141
+
142
+ ```typescript
143
+ // Address -> u256 mapping
144
+ const map: AddressMap<u256> = calldata.readAddressMapU256();
145
+
146
+ // Usage
147
+ const keys = map.keys();
148
+ for (let i = 0; i < keys.length; i++) {
149
+ const address = keys[i];
150
+ const value = map.get(address);
151
+ // Process...
152
+ }
153
+ ```
154
+
155
+ ## Read Order
156
+
157
+ **IMPORTANT:** Data must be read in the exact order it was written.
158
+
159
+ ```typescript
160
+ // Correct order
161
+ public myMethod(calldata: Calldata): BytesWriter {
162
+ const address = calldata.readAddress(); // First
163
+ const amount = calldata.readU256(); // Second
164
+ const flag = calldata.readBoolean(); // Third
165
+ // ...
166
+ }
167
+
168
+ // Wrong order will read garbage!
169
+ public myMethod(calldata: Calldata): BytesWriter {
170
+ const amount = calldata.readU256(); // WRONG!
171
+ const address = calldata.readAddress(); // WRONG!
172
+ const flag = calldata.readBoolean();
173
+ }
174
+ ```
175
+
176
+ ### Sequential Read Flow
177
+
178
+ ```mermaid
179
+ ---
180
+ config:
181
+ theme: dark
182
+ ---
183
+ flowchart LR
184
+ A["Calldata Buffer"] --> B["readAddress: 32 bytes"]
185
+ B --> C["readU256: 32 bytes"]
186
+ C --> D["readBoolean: 1 byte"]
187
+ D --> E{"hasMoreData?"}
188
+ E -->|"Yes"| F["Continue"]
189
+ E -->|"No"| G["Complete"]
190
+
191
+ B -.->|"Wrong Order"| H["Garbage Data/Revert"]
192
+ C -.->|"Wrong Order"| H
193
+ ```
194
+
195
+ ## Data Encoding
196
+
197
+ ### Encoding Format
198
+
199
+ ```
200
+ | Field 1 | Field 2 | Field 3 | ... |
201
+ |---------|---------|---------|-----|
202
+ ```
203
+
204
+ Each field is encoded according to its type:
205
+
206
+ | Type | Encoding |
207
+ |------|----------|
208
+ | `bool` | 1 byte (0 or 1) |
209
+ | `u8` | 1 byte |
210
+ | `u16` | 2 bytes (big-endian, default) |
211
+ | `u32` | 4 bytes (big-endian, default) |
212
+ | `u64` | 8 bytes (big-endian, default) |
213
+ | `u128` | 16 bytes (big-endian, default) |
214
+ | `u256` | 32 bytes (big-endian, default) |
215
+ | `Address` | 32 bytes |
216
+ | `Selector` | 4 bytes (big-endian u32) |
217
+ | `string` | 4-byte length (u32 BE) + UTF-8 bytes |
218
+ | `bytes` | 4-byte length (u32 BE) + raw bytes |
219
+ | `arrays` | 2-byte length (u16 BE) + elements |
220
+
221
+ ### String Encoding (with length prefix)
222
+
223
+ ```
224
+ | Length (4 bytes, BE) | UTF-8 Content |
225
+ |----------------------|---------------|
226
+ | 0x00 0x00 0x00 0x0B | "Hello World" |
227
+ ```
228
+
229
+ ### Array Encoding
230
+
231
+ Arrays use a u16 length prefix (max 65535 elements):
232
+
233
+ ```
234
+ | Length (2 bytes, BE) | Element 1 | Element 2 | ... |
235
+ |----------------------|-----------|-----------|-----|
236
+ ```
237
+
238
+ ## Solidity vs OPNet Comparison
239
+
240
+ ### Calldata Decoding Comparison Table
241
+
242
+ | Feature | Solidity | OPNet |
243
+ |---------|----------|-------|
244
+ | **Parameter access** | Automatic (named parameters) | Manual sequential reading |
245
+ | **Decode function** | `abi.decode(data, (T1, T2))` | `calldata.readT1(); calldata.readT2();` |
246
+ | **Type safety** | Compile-time | Runtime |
247
+ | **Read order** | Any order (named) | Must match encoding order |
248
+ | **Error on insufficient data** | Reverts | Reverts |
249
+ | **Dynamic types** | ABI-encoded with offset | Length-prefixed inline |
250
+ | **Memory location** | `calldata`, `memory` keywords | Always sequential buffer |
251
+
252
+ ### Type-by-Type Decoding Comparison
253
+
254
+ | Solidity Decoding | OPNet Decoding |
255
+ |-------------------|----------------|
256
+ | `abi.decode(data, (uint256))` | `calldata.readU256()` |
257
+ | `abi.decode(data, (uint128))` | `calldata.readU128()` |
258
+ | `abi.decode(data, (uint64))` | `calldata.readU64()` |
259
+ | `abi.decode(data, (uint32))` | `calldata.readU32()` |
260
+ | `abi.decode(data, (uint16))` | `calldata.readU16()` |
261
+ | `abi.decode(data, (uint8))` | `calldata.readU8()` |
262
+ | `abi.decode(data, (int256))` | N/A (use u256 with sign handling) |
263
+ | `abi.decode(data, (bool))` | `calldata.readBoolean()` |
264
+ | `abi.decode(data, (address))` | `calldata.readAddress()` |
265
+ | `abi.decode(data, (bytes32))` | `calldata.readBytes()` (length-prefixed) |
266
+ | `abi.decode(data, (string))` | `calldata.readString()` |
267
+ | `abi.decode(data, (bytes))` | `calldata.readBytes()` |
268
+ | `abi.decode(data, (address[]))` | `calldata.readAddressArray()` |
269
+ | `abi.decode(data, (uint256[]))` | `calldata.readU256Array()` |
270
+
271
+ ### Side-by-Side Code Examples
272
+
273
+ #### Simple Function Parameters
274
+
275
+ ```solidity
276
+ // Solidity - Parameters decoded automatically
277
+ function transfer(address to, uint256 amount) public returns (bool) {
278
+ // 'to' and 'amount' are immediately available
279
+ _transfer(msg.sender, to, amount);
280
+ return true;
281
+ }
282
+ ```
283
+
284
+ ```typescript
285
+ // OPNet - Parameters read sequentially
286
+ public transfer(calldata: Calldata): BytesWriter {
287
+ // Must read in exact order they were encoded
288
+ const to: Address = calldata.readAddress();
289
+ const amount: u256 = calldata.readU256();
290
+
291
+ this._transfer(Blockchain.tx.sender, to, amount);
292
+
293
+ const writer = new BytesWriter(1);
294
+ writer.writeBoolean(true);
295
+ return writer;
296
+ }
297
+ ```
298
+
299
+ #### Multiple Parameters
300
+
301
+ ```solidity
302
+ // Solidity
303
+ function transferFrom(
304
+ address from,
305
+ address to,
306
+ uint256 amount
307
+ ) public returns (bool) {
308
+ _spendAllowance(from, msg.sender, amount);
309
+ _transfer(from, to, amount);
310
+ return true;
311
+ }
312
+ ```
313
+
314
+ ```typescript
315
+ // OPNet
316
+ public transferFrom(calldata: Calldata): BytesWriter {
317
+ const from: Address = calldata.readAddress();
318
+ const to: Address = calldata.readAddress();
319
+ const amount: u256 = calldata.readU256();
320
+
321
+ this._spendAllowance(from, Blockchain.tx.sender, amount);
322
+ this._transfer(from, to, amount);
323
+
324
+ const writer = new BytesWriter(1);
325
+ writer.writeBoolean(true);
326
+ return writer;
327
+ }
328
+ ```
329
+
330
+ #### Decoding Complex Types
331
+
332
+ ```solidity
333
+ // Solidity - Decoding from raw bytes
334
+ function decodeTransfer(bytes calldata data) public pure returns (address, uint256) {
335
+ (address to, uint256 amount) = abi.decode(data, (address, uint256));
336
+ return (to, amount);
337
+ }
338
+
339
+ // Or with explicit offset
340
+ function decodeWithOffset(bytes calldata data) public pure {
341
+ address to = abi.decode(data[0:32], (address));
342
+ uint256 amount = abi.decode(data[32:64], (uint256));
343
+ }
344
+ ```
345
+
346
+ ```typescript
347
+ // OPNet - Sequential reading handles offset automatically
348
+ public decodeTransfer(calldata: Calldata): BytesWriter {
349
+ const to: Address = calldata.readAddress(); // Reads bytes 0-31
350
+ const amount: u256 = calldata.readU256(); // Reads bytes 32-63
351
+
352
+ const writer = new BytesWriter(64);
353
+ writer.writeAddress(to);
354
+ writer.writeU256(amount);
355
+ return writer;
356
+ }
357
+ ```
358
+
359
+ #### String and Bytes Handling
360
+
361
+ ```solidity
362
+ // Solidity
363
+ function setName(string calldata name) public {
364
+ require(bytes(name).length > 0, "Empty name");
365
+ _name = name;
366
+ }
367
+
368
+ function processData(bytes calldata data) public {
369
+ require(data.length >= 4, "Too short");
370
+ // Process data...
371
+ }
372
+ ```
373
+
374
+ ```typescript
375
+ // OPNet
376
+ public setName(calldata: Calldata): BytesWriter {
377
+ const name: string = calldata.readString(); // Length-prefixed
378
+ if (name.length == 0) {
379
+ throw new Revert('Empty name');
380
+ }
381
+ this._name.value = name;
382
+ return new BytesWriter(0);
383
+ }
384
+
385
+ public processData(calldata: Calldata): BytesWriter {
386
+ const data: Uint8Array = calldata.readBytes(); // Length-prefixed
387
+ if (data.length < 4) {
388
+ throw new Revert('Too short');
389
+ }
390
+ // Process data...
391
+ return new BytesWriter(0);
392
+ }
393
+ ```
394
+
395
+ #### Array Parameters
396
+
397
+ ```solidity
398
+ // Solidity
399
+ function batchTransfer(
400
+ address[] calldata recipients,
401
+ uint256[] calldata amounts
402
+ ) public {
403
+ require(recipients.length == amounts.length, "Length mismatch");
404
+ for (uint i = 0; i < recipients.length; i++) {
405
+ _transfer(msg.sender, recipients[i], amounts[i]);
406
+ }
407
+ }
408
+ ```
409
+
410
+ ```typescript
411
+ // OPNet
412
+ public batchTransfer(calldata: Calldata): BytesWriter {
413
+ const recipients: Address[] = calldata.readAddressArray();
414
+ const amounts: u256[] = calldata.readU256Array();
415
+
416
+ if (recipients.length != amounts.length) {
417
+ throw new Revert('Length mismatch');
418
+ }
419
+
420
+ for (let i = 0; i < recipients.length; i++) {
421
+ this._transfer(Blockchain.tx.sender, recipients[i], amounts[i]);
422
+ }
423
+
424
+ return new BytesWriter(0);
425
+ }
426
+ ```
427
+
428
+ #### Optional/Variable Parameters
429
+
430
+ ```solidity
431
+ // Solidity - Using bytes for optional data
432
+ function safeTransferFrom(
433
+ address from,
434
+ address to,
435
+ uint256 tokenId,
436
+ bytes calldata data
437
+ ) public {
438
+ _transfer(from, to, tokenId);
439
+ if (data.length > 0) {
440
+ // Call onERC721Received
441
+ }
442
+ }
443
+ ```
444
+
445
+ ```typescript
446
+ // OPNet - Check for remaining data
447
+ public safeTransferFrom(calldata: Calldata): BytesWriter {
448
+ const from: Address = calldata.readAddress();
449
+ const to: Address = calldata.readAddress();
450
+ const tokenId: u256 = calldata.readU256();
451
+
452
+ // Check if optional data is present by comparing offset to total length
453
+ let data: Uint8Array = new Uint8Array(0);
454
+ if (calldata.getOffset() < calldata.byteLength) {
455
+ data = calldata.readBytesWithLength(); // Read length-prefixed bytes
456
+ }
457
+
458
+ this._transfer(from, to, tokenId);
459
+ if (data.length > 0) {
460
+ // Handle callback
461
+ }
462
+
463
+ return new BytesWriter(0);
464
+ }
465
+ ```
466
+
467
+ ### Encoding Format Differences
468
+
469
+ | Aspect | Solidity ABI | OPNet |
470
+ |--------|--------------|-------|
471
+ | **Byte order** | Big-endian | Big-endian (default) |
472
+ | **Address padding** | Left-padded to 32 bytes | 32 bytes (native size) |
473
+ | **Dynamic offset** | Pointer + data section | Inline length prefix |
474
+ | **String encoding** | Offset + length + data | 4-byte u32 length + UTF-8 |
475
+ | **Array encoding** | Offset + length + elements | 2-byte u16 length + elements |
476
+ | **Boolean** | 32 bytes (padded) | 1 byte |
477
+ | **uint8-uint248** | 32 bytes (padded) | Native size |
478
+
479
+ ### Encoding Size Comparison
480
+
481
+ | Type | Solidity ABI Size | OPNet Size |
482
+ |------|-------------------|------------|
483
+ | `bool` | 32 bytes | 1 byte |
484
+ | `uint8` | 32 bytes | 1 byte |
485
+ | `uint16` | 32 bytes | 2 bytes |
486
+ | `uint32` | 32 bytes | 4 bytes |
487
+ | `uint64` | 32 bytes | 8 bytes |
488
+ | `uint128` | 32 bytes | 16 bytes |
489
+ | `uint256` | 32 bytes | 32 bytes |
490
+ | `address` | 32 bytes | 32 bytes |
491
+ | `string "Hello"` | 96 bytes (offset+len+data) | 9 bytes (len+data) |
492
+
493
+ ### Key Differences Summary
494
+
495
+ | Solidity | OPNet |
496
+ |----------|-------|
497
+ | Named parameters in function signature | Single `Calldata` parameter |
498
+ | Automatic ABI decoding | Manual `read*()` methods |
499
+ | Can access parameters in any order | Must read in sequential order |
500
+ | Type info in function signature | Type determined by read method |
501
+ | `calldata` keyword optimization | All calldata is read-only by default |
502
+ | `msg.data` for raw bytes | Calldata object wraps the buffer |
503
+
504
+ ## Common Patterns
505
+
506
+ ### Method Call Flow
507
+
508
+ ```mermaid
509
+ sequenceDiagram
510
+ participant U as 👤 User/Client
511
+ participant BC as Blockchain
512
+ participant C as Contract Method
513
+ participant CD as Calldata
514
+ participant W as BytesWriter
515
+
516
+ U->>BC: Transaction with encoded params
517
+ Note over BC: Selector + Parameters
518
+ BC->>C: Invoke method(calldata)
519
+ C->>CD: readAddress()
520
+ CD-->>C: Address value
521
+ C->>CD: readU256()
522
+ CD-->>C: u256 value
523
+
524
+ C->>C: Execute business logic
525
+ Note over C: Process transfer,<br/>update balances, etc.
526
+
527
+ C->>W: new BytesWriter(size)
528
+ C->>W: Write return values
529
+ W-->>C: Encoded response
530
+ C-->>BC: Return BytesWriter
531
+ BC-->>U: Transaction result
532
+
533
+ Note over CD: All parameters read<br/>sequentially in order
534
+ ```
535
+
536
+ ### Single Value Methods
537
+
538
+ ```typescript
539
+ // balanceOf(address)
540
+ public balanceOf(calldata: Calldata): BytesWriter {
541
+ const account = calldata.readAddress();
542
+ const balance = this.balances.get(account);
543
+
544
+ const writer = new BytesWriter(32);
545
+ writer.writeU256(balance);
546
+ return writer;
547
+ }
548
+ ```
549
+
550
+ ### Multi-Parameter Methods
551
+
552
+ ```typescript
553
+ // transferFrom(from, to, amount)
554
+ public transferFrom(calldata: Calldata): BytesWriter {
555
+ const from = calldata.readAddress();
556
+ const to = calldata.readAddress();
557
+ const amount = calldata.readU256();
558
+
559
+ this._transfer(from, to, amount);
560
+ return new BytesWriter(0);
561
+ }
562
+ ```
563
+
564
+ ### Optional Parameters
565
+
566
+ ```typescript
567
+ // Method with optional data field
568
+ public safeTransfer(calldata: Calldata): BytesWriter {
569
+ const to = calldata.readAddress();
570
+ const tokenId = calldata.readU256();
571
+
572
+ // Check if there's more data by comparing offset to total length
573
+ let data: Uint8Array = new Uint8Array(0);
574
+ if (calldata.getOffset() < calldata.byteLength) {
575
+ data = calldata.readBytesWithLength(); // Read length-prefixed bytes
576
+ }
577
+
578
+ this._safeTransfer(Blockchain.tx.sender, to, tokenId, data);
579
+ return new BytesWriter(0);
580
+ }
581
+ ```
582
+
583
+ ### Batch Operations
584
+
585
+ ```typescript
586
+ // Airdrop to multiple addresses
587
+ public airdrop(calldata: Calldata): BytesWriter {
588
+ const recipients = calldata.readAddressMapU256();
589
+ const addresses = recipients.keys();
590
+
591
+ for (let i = 0; i < addresses.length; i++) {
592
+ const addr = addresses[i];
593
+ const amount = recipients.get(addr);
594
+ this._mint(addr, amount);
595
+ }
596
+
597
+ return new BytesWriter(0);
598
+ }
599
+ ```
600
+
601
+ ## Error Handling
602
+
603
+ ### Insufficient Data
604
+
605
+ ```typescript
606
+ // If calldata doesn't have enough bytes, read will fail
607
+ public myMethod(calldata: Calldata): BytesWriter {
608
+ // If only 32 bytes provided...
609
+ const addr = calldata.readAddress(); // OK (32 bytes)
610
+ const amount = calldata.readU256(); // FAILS! No more data
611
+ }
612
+ ```
613
+
614
+ ### Validation
615
+
616
+ ```typescript
617
+ public myMethod(calldata: Calldata): BytesWriter {
618
+ const to = calldata.readAddress();
619
+ const amount = calldata.readU256();
620
+
621
+ // Validate after reading
622
+ if (to.equals(Address.zero())) {
623
+ throw new Revert('Invalid recipient');
624
+ }
625
+
626
+ if (amount.isZero()) {
627
+ throw new Revert('Amount is zero');
628
+ }
629
+
630
+ // ... proceed
631
+ }
632
+ ```
633
+
634
+ ## Deployment Calldata
635
+
636
+ The `onDeployment` method receives initialization parameters:
637
+
638
+ ```typescript
639
+ public override onDeployment(calldata: Calldata): void {
640
+ // Read deployment parameters
641
+ const name = calldata.readString();
642
+ const symbol = calldata.readString();
643
+ const maxSupply = calldata.readU256();
644
+ const decimals = calldata.readU8();
645
+
646
+ // Initialize contract
647
+ this._name.value = name;
648
+ this._symbol.value = symbol;
649
+ this._maxSupply.value = maxSupply;
650
+ this._decimals.value = decimals;
651
+ }
652
+ ```
653
+
654
+ ### Deployment Parameter Flow
655
+
656
+ ```mermaid
657
+ ---
658
+ config:
659
+ theme: dark
660
+ ---
661
+ flowchart LR
662
+ A["Deploy Transaction"] --> B["Calldata Buffer"]
663
+ B --> C["name: string"]
664
+ C --> D["symbol: string"]
665
+ D --> E["maxSupply: u256"]
666
+ E --> F["decimals: u8"]
667
+ F --> G["onDeployment Method"]
668
+ G --> H["Initialize State"]
669
+ H --> I["Contract Ready"]
670
+ ```
671
+
672
+ ## Best Practices
673
+
674
+ ### 1. Document Parameter Order
675
+
676
+ ```typescript
677
+ /**
678
+ * Transfer tokens to recipient.
679
+ * @param calldata Contains:
680
+ * - to: Address (32 bytes) - Recipient address
681
+ * - amount: u256 (32 bytes) - Amount to transfer
682
+ */
683
+ public transfer(calldata: Calldata): BytesWriter {
684
+ const to = calldata.readAddress();
685
+ const amount = calldata.readU256();
686
+ // ...
687
+ }
688
+ ```
689
+
690
+ ### 2. Validate Early
691
+
692
+ ```typescript
693
+ public mint(calldata: Calldata): BytesWriter {
694
+ // Read all parameters first
695
+ const to = calldata.readAddress();
696
+ const amount = calldata.readU256();
697
+
698
+ // Then validate
699
+ this.onlyDeployer(Blockchain.tx.sender);
700
+
701
+ if (to.equals(Address.zero())) {
702
+ throw new Revert('Cannot mint to zero address');
703
+ }
704
+
705
+ if (amount.isZero()) {
706
+ throw new Revert('Amount must be positive');
707
+ }
708
+
709
+ // Then execute
710
+ this._mint(to, amount);
711
+ return new BytesWriter(0);
712
+ }
713
+ ```
714
+
715
+ ### 3. Handle Arrays Carefully
716
+
717
+ ```typescript
718
+ public batchTransfer(calldata: Calldata): BytesWriter {
719
+ const recipients = calldata.readAddressArray();
720
+ const amounts = calldata.readU256Array();
721
+
722
+ // Validate array lengths match
723
+ if (recipients.length !== amounts.length) {
724
+ throw new Revert('Array length mismatch');
725
+ }
726
+
727
+ // Limit array size to prevent DoS attacks
728
+ if (recipients.length > 100) {
729
+ throw new Revert('Too many recipients');
730
+ }
731
+
732
+ for (let i = 0; i < recipients.length; i++) {
733
+ this._transfer(Blockchain.tx.sender, recipients[i], amounts[i]);
734
+ }
735
+
736
+ return new BytesWriter(0);
737
+ }
738
+ ```
739
+
740
+ ---
741
+
742
+ **Navigation:**
743
+ - Previous: [SafeMath](./safe-math.md)
744
+ - Next: [BytesWriter/Reader](./bytes-writer-reader.md)