@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
@@ -906,249 +906,19 @@ public reserve(calldata: Calldata): BytesWriter { }
906
906
  public getSaleInfo(_calldata: Calldata): BytesWriter { }
907
907
  ```
908
908
 
909
- ## Solidity Equivalent
910
-
911
- For developers familiar with Solidity, here is an equivalent ERC721 implementation with reservations and reveal mechanics:
912
-
913
- ```solidity
914
- // SPDX-License-Identifier: MIT
915
- pragma solidity ^0.8.20;
916
-
917
- import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
918
- import "@openzeppelin/contracts/access/Ownable.sol";
919
- import "@openzeppelin/contracts/utils/Strings.sol";
920
-
921
- contract NFTWithReservations is ERC721, Ownable {
922
- using Strings for uint256;
923
-
924
- enum SalePhase { INACTIVE, WHITELIST, PUBLIC }
925
-
926
- // Configuration
927
- uint256 public maxSupply;
928
- uint256 public price;
929
- uint256 public maxPerWallet;
930
- string private baseURI_;
931
- string private hiddenURI;
932
- bool public revealed;
933
- SalePhase public salePhase;
934
- uint256 private nextTokenId = 1;
935
-
936
- // Reservation system
937
- uint256 public reservationEnd;
938
- mapping(address => uint256) public reservations;
939
-
940
- // Whitelist
941
- mapping(address => bool) public whitelist;
942
- mapping(address => uint256) public mintedCount;
943
-
944
- event Reserved(address indexed user, uint256 quantity);
945
- event ReservationClaimed(address indexed user, uint256 quantity);
946
- event ReservationCancelled(address indexed user, uint256 quantity);
947
-
948
- constructor(
949
- string memory name,
950
- string memory symbol,
951
- uint256 _maxSupply,
952
- uint256 _price,
953
- uint256 _maxPerWallet,
954
- string memory _hiddenURI
955
- ) ERC721(name, symbol) Ownable(msg.sender) {
956
- maxSupply = _maxSupply;
957
- price = _price;
958
- maxPerWallet = _maxPerWallet;
959
- hiddenURI = _hiddenURI;
960
- }
961
-
962
- // ============ RESERVATION SYSTEM ============
963
-
964
- function reserve(uint256 quantity) external payable {
965
- require(block.timestamp < reservationEnd, "Reservation period ended");
966
- require(reservations[msg.sender] + quantity <= maxPerWallet, "Exceeds max per wallet");
967
- require(msg.value >= price * quantity, "Insufficient payment");
968
-
969
- reservations[msg.sender] += quantity;
970
- emit Reserved(msg.sender, quantity);
971
- }
972
-
973
- function claimReserved() external {
974
- require(block.timestamp >= reservationEnd, "Reservation period not ended");
975
- uint256 quantity = reservations[msg.sender];
976
- require(quantity > 0, "No reservations");
977
-
978
- reservations[msg.sender] = 0;
979
-
980
- for (uint256 i = 0; i < quantity; i++) {
981
- _safeMint(msg.sender, nextTokenId++);
982
- }
983
-
984
- emit ReservationClaimed(msg.sender, quantity);
985
- }
986
-
987
- function cancelReservation() external {
988
- require(block.timestamp < reservationEnd, "Reservation period ended");
989
- uint256 quantity = reservations[msg.sender];
990
- require(quantity > 0, "No reservations");
991
-
992
- reservations[msg.sender] = 0;
993
-
994
- // Refund
995
- uint256 refundAmount = price * quantity;
996
- (bool success, ) = msg.sender.call{value: refundAmount}("");
997
- require(success, "Refund failed");
998
-
999
- emit ReservationCancelled(msg.sender, quantity);
1000
- }
1001
-
1002
- // ============ MINTING ============
1003
-
1004
- function whitelistMint(uint256 quantity) external payable {
1005
- require(salePhase == SalePhase.WHITELIST, "Whitelist sale not active");
1006
- require(whitelist[msg.sender], "Not whitelisted");
1007
- require(msg.value >= price * quantity, "Insufficient payment");
1008
-
1009
- _mintInternal(msg.sender, quantity);
1010
- }
1011
-
1012
- function publicMint(uint256 quantity) external payable {
1013
- require(salePhase == SalePhase.PUBLIC, "Public sale not active");
1014
- require(msg.value >= price * quantity, "Insufficient payment");
1015
-
1016
- _mintInternal(msg.sender, quantity);
1017
- }
1018
-
1019
- function _mintInternal(address to, uint256 quantity) internal {
1020
- require(nextTokenId + quantity - 1 <= maxSupply, "Exceeds max supply");
1021
- require(mintedCount[to] + quantity <= maxPerWallet, "Exceeds max per wallet");
1022
-
1023
- mintedCount[to] += quantity;
1024
-
1025
- for (uint256 i = 0; i < quantity; i++) {
1026
- _safeMint(to, nextTokenId++);
1027
- }
1028
- }
1029
-
1030
- // ============ REVEAL ============
1031
-
1032
- function tokenURI(uint256 tokenId) public view override returns (string memory) {
1033
- require(_ownerOf(tokenId) != address(0), "Token does not exist");
1034
-
1035
- if (!revealed) {
1036
- return hiddenURI;
1037
- }
1038
-
1039
- return string(abi.encodePacked(baseURI_, tokenId.toString(), ".json"));
1040
- }
1041
-
1042
- // ============ ADMIN FUNCTIONS ============
1043
-
1044
- function startReservation(uint256 duration) external onlyOwner {
1045
- reservationEnd = block.timestamp + duration;
1046
- }
1047
-
1048
- function setSalePhase(SalePhase phase) external onlyOwner {
1049
- salePhase = phase;
1050
- }
1051
-
1052
- function setWhitelist(address[] calldata addresses, bool status) external onlyOwner {
1053
- for (uint256 i = 0; i < addresses.length; i++) {
1054
- whitelist[addresses[i]] = status;
1055
- }
1056
- }
1057
-
1058
- function reveal(string calldata _baseURI) external onlyOwner {
1059
- baseURI_ = _baseURI;
1060
- revealed = true;
1061
- }
1062
-
1063
- function setPrice(uint256 _price) external onlyOwner {
1064
- price = _price;
1065
- }
1066
-
1067
- function withdraw() external onlyOwner {
1068
- (bool success, ) = owner().call{value: address(this).balance}("");
1069
- require(success, "Withdrawal failed");
1070
- }
1071
-
1072
- // ============ VIEW FUNCTIONS ============
1073
-
1074
- function totalSupply() public view returns (uint256) {
1075
- return nextTokenId - 1;
1076
- }
1077
-
1078
- function getSaleInfo() external view returns (
1079
- SalePhase phase,
1080
- uint256 currentPrice,
1081
- uint256 maxSupply_,
1082
- uint256 totalSupply_,
1083
- bool isRevealed
1084
- ) {
1085
- return (salePhase, price, maxSupply, totalSupply(), revealed);
1086
- }
1087
- }
1088
- ```
1089
-
1090
- ## Solidity vs OPNet Comparison
1091
-
1092
- ### Key Differences Table
909
+ ## Solidity Comparison
1093
910
 
1094
911
  | Aspect | Solidity (ERC721) | OPNet (OP721) |
1095
912
  |--------|-------------------|---------------|
1096
- | **Inheritance** | `contract NFT is ERC721, Ownable` | `class NFT extends OP721` |
1097
- | **Constructor** | `constructor() ERC721("Name", "SYM")` | `onDeployment()` + `this.instantiate(...)` |
1098
- | **Enum Definition** | `enum SalePhase { INACTIVE, WHITELIST }` | `const PHASE_INACTIVE: u8 = 0` |
1099
- | **Mint** | `_safeMint(to, tokenId)` | `this._mint(to, tokenId)` |
1100
- | **Token Counter** | `uint256 private nextTokenId` | `StoredU256` with pointer |
1101
- | **Timestamp** | `block.timestamp` | `Blockchain.block.medianTime` |
1102
- | **Whitelist Storage** | `mapping(address => bool)` | `AddressMemoryMap` |
1103
- | **Payment Handling** | `msg.value`, `payable` | Bitcoin UTXO model |
1104
- | **String Concat** | `string(abi.encodePacked(...))` | `baseURI + tokenId.toString() + '.json'` |
1105
-
1106
- ### Reservation Pattern Comparison
1107
-
1108
- **Solidity:**
1109
- ```solidity
1110
- mapping(address => uint256) public reservations;
1111
- uint256 public reservationEnd;
1112
-
1113
- function reserve(uint256 quantity) external payable {
1114
- require(block.timestamp < reservationEnd, "Reservation period ended");
1115
- require(reservations[msg.sender] + quantity <= maxPerWallet, "Exceeds max per wallet");
1116
- require(msg.value >= price * quantity, "Insufficient payment");
1117
-
1118
- reservations[msg.sender] += quantity;
1119
- }
1120
- ```
1121
-
1122
- **OPNet:**
1123
- ```typescript
1124
- private _reservedBy: AddressMemoryMap;
1125
- private _reservationEnd: StoredU256;
913
+ | Inheritance | `contract NFT is ERC721, Ownable` | `class NFT extends OP721` |
914
+ | Constructor | `constructor() ERC721("Name", "SYM")` | `onDeployment()` + `this.instantiate(...)` |
915
+ | Mint | `_safeMint(to, tokenId)` | `this._mint(to, tokenId)` |
916
+ | Timestamp | `block.timestamp` | `Blockchain.block.medianTime` |
917
+ | Whitelist Storage | `mapping(address => bool)` | `AddressMemoryMap` |
1126
918
 
1127
- @method({ name: 'quantity', type: ABIDataTypes.UINT256 })
1128
- @returns({ name: 'success', type: ABIDataTypes.BOOL })
1129
- @emit('Reserved')
1130
- public reserve(calldata: Calldata): BytesWriter {
1131
- const quantity = calldata.readU256();
1132
- const sender = Blockchain.tx.sender;
1133
-
1134
- const now = u256.fromU64(Blockchain.block.medianTime);
1135
- if (now >= this._reservationEnd.value) {
1136
- throw new Revert('Reservation period ended');
1137
- }
1138
-
1139
- const currentReserved = this._reservedBy.get(sender);
1140
- const newTotal = SafeMath.add(currentReserved, quantity);
1141
-
1142
- if (newTotal > this._maxPerWallet.value) {
1143
- throw new Revert('Exceeds max per wallet');
1144
- }
1145
-
1146
- this._reservedBy.set(sender, newTotal);
1147
- return new BytesWriter(0);
1148
- }
1149
- ```
919
+ For detailed OP721 API documentation, see [OP721 Contract](../contracts/op721-nft.md).
1150
920
 
1151
- ### Whitelist Verification Comparison
921
+ ### Whitelist Implementation Comparison
1152
922
 
1153
923
  **Solidity (Using Merkle Proofs):**
1154
924
  ```solidity
@@ -202,50 +202,7 @@ flowchart LR
202
202
  | `transfer(to, amount)` | `balances[msg.sender] -= amount; balances[to] += amount;` | `this.balances.set(sender, SafeMath.sub(...)); this.balances.set(to, SafeMath.add(...));` |
203
203
  | `approve(spender, amount)` | `allowances[msg.sender][spender] = amount;` | Use `MapOfMap<u256>` for nested mapping |
204
204
 
205
- ### Full Comparison Example
206
-
207
- ```solidity
208
- // Solidity
209
- contract Token {
210
- mapping(address => uint256) public balances;
211
-
212
- function transfer(address to, uint256 amount) external {
213
- require(balances[msg.sender] >= amount, "Insufficient");
214
- balances[msg.sender] -= amount;
215
- balances[to] += amount;
216
- }
217
- }
218
- ```
219
-
220
- ```typescript
221
- // OPNet
222
- @final
223
- export class Token extends OP_NET {
224
- private balancesPointer: u16 = Blockchain.nextPointer;
225
- private balances: AddressMemoryMap;
226
-
227
- constructor() {
228
- super();
229
- this.balances = new AddressMemoryMap(this.balancesPointer);
230
- }
231
-
232
- public transfer(calldata: Calldata): BytesWriter {
233
- const to = calldata.readAddress();
234
- const amount = calldata.readU256();
235
- const sender = Blockchain.tx.sender;
236
-
237
- const senderBalance = this.balances.get(sender);
238
- if (senderBalance < amount) {
239
- throw new Revert('Insufficient balance');
240
- }
241
-
242
- this.balances.set(sender, SafeMath.sub(senderBalance, amount));
243
- this.balances.set(to, SafeMath.add(this.balances.get(to), amount));
244
-
245
- return new BytesWriter(0);
246
- }
247
- }
248
- ```
205
+ For a complete token implementation using AddressMemoryMap, see [Basic Token Example](../examples/basic-token.md).
249
206
 
250
207
  ## Side-by-Side Code Examples
251
208
 
@@ -238,71 +238,7 @@ if (this.holders.getLength() === 0) {
238
238
  | Get last element | `arr[arr.length - 1]` | `arr.get(arr.getLength() - 1)` |
239
239
  | Initialize with values | `arr = [1, 2, 3];` | Multiple `arr.push()` calls in `onDeployment`, then `arr.save()` |
240
240
 
241
- ### Full Example Comparison
242
-
243
- ```solidity
244
- // Solidity
245
- contract Registry {
246
- address[] public members;
247
-
248
- function addMember(address member) external {
249
- members.push(member);
250
- }
251
-
252
- function removeMember(uint256 index) external {
253
- members[index] = members[members.length - 1];
254
- members.pop();
255
- }
256
-
257
- function getMemberCount() external view returns (uint256) {
258
- return members.length;
259
- }
260
- }
261
- ```
262
-
263
- ```typescript
264
- // OPNet
265
- @final
266
- export class Registry extends OP_NET {
267
- private membersPointer: u16 = Blockchain.nextPointer;
268
- private members: StoredAddressArray;
269
-
270
- constructor() {
271
- super();
272
- this.members = new StoredAddressArray(this.membersPointer, EMPTY_POINTER);
273
- }
274
-
275
- public addMember(calldata: Calldata): BytesWriter {
276
- const member = calldata.readAddress();
277
- this.members.push(member);
278
- this.members.save();
279
- return new BytesWriter(0);
280
- }
281
-
282
- public removeMember(calldata: Calldata): BytesWriter {
283
- const index = calldata.readU32();
284
- const length = this.members.getLength();
285
-
286
- if (index >= length) {
287
- throw new Revert('Index out of bounds');
288
- }
289
-
290
- if (index < length - 1) {
291
- this.members.set(index, this.members.get(length - 1));
292
- }
293
- this.members.deleteLast();
294
- this.members.save();
295
-
296
- return new BytesWriter(0);
297
- }
298
-
299
- public getMemberCount(_calldata: Calldata): BytesWriter {
300
- const writer = new BytesWriter(4);
301
- writer.writeU32(this.members.getLength());
302
- return writer;
303
- }
304
- }
305
- ```
241
+ For complete contract examples using stored arrays, see the [Examples](../examples/) section.
306
242
 
307
243
  ## Side-by-Side Code Examples
308
244
 
@@ -312,79 +312,7 @@ flowchart LR
312
312
  | Token metadata | `mapping(uint256 => string)` | `StoredMapU256` with encoded strings |
313
313
  | Checkpoints | `mapping(address => mapping(uint256 => uint256))` | `MapOfMap<u256>` or composite keys |
314
314
 
315
- ### Full Example Comparison
316
-
317
- ```solidity
318
- // Solidity
319
- contract Token {
320
- mapping(address => uint256) public balances;
321
- mapping(address => mapping(address => uint256)) public allowances;
322
-
323
- function transfer(address to, uint256 amount) external {
324
- require(balances[msg.sender] >= amount);
325
- balances[msg.sender] -= amount;
326
- balances[to] += amount;
327
- }
328
-
329
- function approve(address spender, uint256 amount) external {
330
- allowances[msg.sender][spender] = amount;
331
- }
332
- }
333
- ```
334
-
335
- ```typescript
336
- // OPNet
337
- @final
338
- export class Token extends OP_NET {
339
- private balancesPointer: u16 = Blockchain.nextPointer;
340
- private allowancesPointer: u16 = Blockchain.nextPointer;
341
-
342
- private balances: StoredMapU256;
343
- private allowances: MapOfMap<u256>;
344
-
345
- constructor() {
346
- super();
347
- this.balances = new StoredMapU256(this.balancesPointer);
348
- this.allowances = new MapOfMap<u256>(this.allowancesPointer);
349
- }
350
-
351
- private addressKey(addr: Address): u256 {
352
- return u256.fromBytes(addr.toBytes());
353
- }
354
-
355
- public transfer(calldata: Calldata): BytesWriter {
356
- const to = calldata.readAddress();
357
- const amount = calldata.readU256();
358
- const sender = Blockchain.tx.sender;
359
-
360
- const senderKey = this.addressKey(sender);
361
- const toKey = this.addressKey(to);
362
-
363
- const senderBalance = this.balances.get(senderKey);
364
- if (senderBalance < amount) {
365
- throw new Revert('Insufficient balance');
366
- }
367
-
368
- this.balances.set(senderKey, SafeMath.sub(senderBalance, amount));
369
- this.balances.set(toKey, SafeMath.add(this.balances.get(toKey), amount));
370
-
371
- return new BytesWriter(0);
372
- }
373
-
374
- public approve(calldata: Calldata): BytesWriter {
375
- const spender = calldata.readAddress();
376
- const amount = calldata.readU256();
377
- const sender = Blockchain.tx.sender;
378
-
379
- // Correct two-step MapOfMap pattern
380
- const senderMap = this.allowances.get(sender);
381
- senderMap.set(spender, amount);
382
- this.allowances.set(sender, senderMap);
383
-
384
- return new BytesWriter(0);
385
- }
386
- }
387
- ```
315
+ For a complete token implementation using these map types, see [Basic Token Example](../examples/basic-token.md).
388
316
 
389
317
  ## Side-by-Side Code Examples
390
318
 
@@ -102,14 +102,7 @@ classDiagram
102
102
 
103
103
  ## Storage Key Generation
104
104
 
105
- Each stored primitive computes its storage key by combining the pointer and subPointer:
106
-
107
- ```mermaid
108
- flowchart LR
109
- A["pointer: u16<br/>subPointer: u256"] --> B["32-byte buffer<br/>[0-1] = pointer<br/>[2-31] = subPointer"]
110
- B --> C["SHA256"]
111
- C --> D["Storage Key<br/>(32 bytes)"]
112
- ```
105
+ Each stored primitive computes its storage key using `SHA256(pointer || subPointer)`. See [Pointers](../core-concepts/pointers.md#encodepointer-function-flow) for the detailed flow diagram.
113
106
 
114
107
  ## Usage
115
108
 
@@ -323,47 +316,7 @@ public override onDeployment(calldata: Calldata): void {
323
316
  | `bool public paused = false;` | `private pausedPtr: u16 = Blockchain.nextPointer;`<br>`private _paused: StoredBoolean = new StoredBoolean(this.pausedPtr, false);` |
324
317
  | `address public owner;` | `private ownerPtr: u16 = Blockchain.nextPointer;`<br>`private _owner: StoredAddress = new StoredAddress(this.ownerPtr);` |
325
318
 
326
- ### Full Example Comparison
327
-
328
- ```solidity
329
- // Solidity
330
- contract Token {
331
- string public name; // slot 0
332
- uint256 public supply; // slot 1
333
- bool public paused; // slot 2 (packed)
334
-
335
- constructor(string memory _name, uint256 _supply) {
336
- name = _name;
337
- supply = _supply;
338
- }
339
- }
340
- ```
341
-
342
- ```typescript
343
- // OPNet
344
- @final
345
- export class Token extends OP_NET {
346
- private namePointer: u16 = Blockchain.nextPointer;
347
- private supplyPointer: u16 = Blockchain.nextPointer;
348
- private pausedPointer: u16 = Blockchain.nextPointer;
349
-
350
- private _name: StoredString = new StoredString(this.namePointer, 0);
351
- private _supply: StoredU256 = new StoredU256(this.supplyPointer, EMPTY_POINTER);
352
- private _paused: StoredBoolean = new StoredBoolean(this.pausedPointer, false);
353
-
354
- public override onDeployment(calldata: Calldata): void {
355
- this._name.value = calldata.readString();
356
- this._supply.value = calldata.readU256();
357
- }
358
-
359
- // Manual getter
360
- public name(_calldata: Calldata): BytesWriter {
361
- const writer = new BytesWriter(256);
362
- writer.writeString(this._name.value);
363
- return writer;
364
- }
365
- }
366
- ```
319
+ For complete token examples using stored primitives, see [Basic Token Example](../examples/basic-token.md).
367
320
 
368
321
  ## Side-by-Side Code Examples
369
322
 
@@ -31,6 +31,7 @@ classDiagram
31
31
  -Uint8Array typedArray
32
32
  -u32 currentOffset
33
33
  +BytesWriter(length)
34
+ +write~T~(value) void
34
35
  +writeU8(value)
35
36
  +writeU16(value, be)
36
37
  +writeU32(value, be)
@@ -38,9 +39,13 @@ classDiagram
38
39
  +writeU128(value, be)
39
40
  +writeU256(value, be)
40
41
  +writeAddress(addr)
42
+ +writeExtendedAddress(extAddr)
43
+ +writeSchnorrSignature(addr, sig)
41
44
  +writeString(str)
42
45
  +writeBytes(data)
43
46
  +writeBoolean(bool)
47
+ +writeExtendedAddressArray(arr)
48
+ +writeExtendedAddressMapU256(map)
44
49
  +getBuffer() Uint8Array
45
50
  }
46
51
 
@@ -48,6 +53,7 @@ classDiagram
48
53
  -DataView buffer
49
54
  -i32 currentOffset
50
55
  +BytesReader(bytes)
56
+ +read~T~() T
51
57
  +readU8() u8
52
58
  +readU16(be) u16
53
59
  +readU32(be) u32
@@ -55,9 +61,13 @@ classDiagram
55
61
  +readU128(be) u128
56
62
  +readU256(be) u256
57
63
  +readAddress() Address
64
+ +readExtendedAddress() ExtendedAddress
65
+ +readSchnorrSignature() SchnorrSignature
58
66
  +readString() string
59
67
  +readBytes(length) Uint8Array
60
68
  +readBoolean() bool
69
+ +readExtendedAddressArray() ExtendedAddress[]
70
+ +readExtendedAddressMapU256() ExtendedAddressMap
61
71
  +hasMoreData() bool
62
72
  }
63
73
 
@@ -113,6 +123,12 @@ writer.writeI64(value);
113
123
  // Address (32 bytes)
114
124
  writer.writeAddress(address);
115
125
 
126
+ // ExtendedAddress (64 bytes: 32 tweaked key + 32 ML-DSA key hash)
127
+ writer.writeExtendedAddress(extendedAddress);
128
+
129
+ // Schnorr signature with signer address (128 bytes total)
130
+ writer.writeSchnorrSignature(signerAddress, signature);
131
+
116
132
  // String without length prefix
117
133
  writer.writeString('Hello, World!');
118
134
 
@@ -129,6 +145,25 @@ writer.writeBytesWithLength(data);
129
145
  writer.writeSelector(selector);
130
146
  ```
131
147
 
148
+ ### Generic Write Method
149
+
150
+ The `write<T>()` method automatically selects the correct write method based on the type:
151
+
152
+ ```typescript
153
+ // Automatically dispatches to the correct write method
154
+ writer.write<u64>(12345); // writeU64
155
+ writer.write<u256>(amount); // writeU256
156
+ writer.write<bool>(true); // writeBoolean
157
+ writer.write<Address>(addr); // writeAddress
158
+ writer.write<ExtendedAddress>(extAddr); // writeExtendedAddress
159
+ writer.write<string>('hello'); // writeStringWithLength
160
+
161
+ // Supported types:
162
+ // - Primitives: bool, u8, u16, u32, u64, i8, i16, i32, i64
163
+ // - Big numbers: u128, u256, i128
164
+ // - Complex: Address, ExtendedAddress, Selector, string, Uint8Array
165
+ ```
166
+
132
167
  ### Writing Arrays
133
168
 
134
169
  All array methods use a u16 length prefix (max 65535 elements):
@@ -137,6 +172,9 @@ All array methods use a u16 length prefix (max 65535 elements):
137
172
  // Address array (u16 length prefix + addresses)
138
173
  writer.writeAddressArray(addresses);
139
174
 
175
+ // ExtendedAddress array (u16 length prefix + 64-byte addresses)
176
+ writer.writeExtendedAddressArray(extendedAddresses);
177
+
140
178
  // Numeric arrays (u16 length prefix + values)
141
179
  writer.writeU8Array(u8Values);
142
180
  writer.writeU16Array(u16Values);
@@ -150,6 +188,9 @@ writer.writeArrayOfBuffer(buffers);
150
188
 
151
189
  // AddressMap<u256> (u16 count, then address + u256 pairs)
152
190
  writer.writeAddressMapU256(addressMap);
191
+
192
+ // ExtendedAddressMap<u256> (u16 count, then 64-byte address + u256 pairs)
193
+ writer.writeExtendedAddressMapU256(extendedAddressMap);
153
194
  ```
154
195
 
155
196
  ### Getting Results
@@ -222,6 +263,14 @@ const i64val: i64 = reader.readI64();
222
263
  // Address (32 bytes)
223
264
  const addr: Address = reader.readAddress();
224
265
 
266
+ // ExtendedAddress (64 bytes: 32 tweaked key + 32 ML-DSA key hash)
267
+ const extAddr: ExtendedAddress = reader.readExtendedAddress();
268
+
269
+ // Schnorr signature with signer address (128 bytes)
270
+ const schnorrSig: SchnorrSignature = reader.readSchnorrSignature();
271
+ const signer: ExtendedAddress = schnorrSig.address;
272
+ const signature: Uint8Array = schnorrSig.signature;
273
+
225
274
  // String with known length (bytes read, zeroStop = true)
226
275
  const name: string = reader.readString(32); // reads up to 32 bytes, stops at null
227
276
 
@@ -238,6 +287,25 @@ const data2: Uint8Array = reader.readBytesWithLength();
238
287
  const selector: Selector = reader.readSelector();
239
288
  ```
240
289
 
290
+ ### Generic Read Method
291
+
292
+ The `read<T>()` method automatically selects the correct read method based on the type:
293
+
294
+ ```typescript
295
+ // Automatically dispatches to the correct read method
296
+ const num: u64 = reader.read<u64>(); // readU64
297
+ const amount: u256 = reader.read<u256>(); // readU256
298
+ const flag: bool = reader.read<bool>(); // readBoolean
299
+ const addr: Address = reader.read<Address>(); // readAddress
300
+ const extAddr: ExtendedAddress = reader.read<ExtendedAddress>(); // readExtendedAddress
301
+ const text: string = reader.read<string>(); // readStringWithLength
302
+
303
+ // Supported types:
304
+ // - Primitives: bool, u8, u16, u32, u64, i8, i16, i32, i64
305
+ // - Big numbers: u128, u256, i128
306
+ // - Complex: Address, ExtendedAddress, Selector, string
307
+ ```
308
+
241
309
  ### Reading Arrays
242
310
 
243
311
  All array methods expect a u16 length prefix:
@@ -246,6 +314,9 @@ All array methods expect a u16 length prefix:
246
314
  // Address array
247
315
  const addresses: Address[] = reader.readAddressArray();
248
316
 
317
+ // ExtendedAddress array (64 bytes each)
318
+ const extAddresses: ExtendedAddress[] = reader.readExtendedAddressArray();
319
+
249
320
  // Numeric arrays
250
321
  const u8Values: u8[] = reader.readU8Array();
251
322
  const u16Values: u16[] = reader.readU16Array();
@@ -259,6 +330,9 @@ const buffers: Uint8Array[] = reader.readArrayOfBuffer();
259
330
 
260
331
  // AddressMap<u256>
261
332
  const addressMap: AddressMap<u256> = reader.readAddressMapU256();
333
+
334
+ // ExtendedAddressMap<u256> (64-byte addresses as keys)
335
+ const extAddressMap: ExtendedAddressMap<u256> = reader.readExtendedAddressMapU256();
262
336
  ```
263
337
 
264
338
  ### Position Management
@@ -291,6 +365,8 @@ reader.verifyEnd(offset + 32); // Throws Revert if not enough bytes
291
365
  | `u128`/`i128` | 16 | Big-endian (default) |
292
366
  | `u256` | 32 | Big-endian (default) |
293
367
  | `Address` | 32 | Raw bytes |
368
+ | `ExtendedAddress` | 64 | 32 bytes tweaked key + 32 bytes ML-DSA key hash |
369
+ | `SchnorrSignature` | 128 | 64 bytes ExtendedAddress + 64 bytes signature |
294
370
  | `Selector` | 4 | Big-endian (u32) |
295
371
  | `string` | 4 + n | Length prefix (u32 BE) + UTF-8 |
296
372
  | `bytes` | 4 + n | Length prefix (u32 BE) + raw |