@rootzero/contracts 1.24.0 → 1.26.0

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 (69) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/Codec.sol +1 -2
  3. package/Core.sol +1 -1
  4. package/Endpoints.sol +3 -0
  5. package/README.md +66 -51
  6. package/Utils.sol +2 -1
  7. package/codec/Blocks.sol +354 -108
  8. package/codec/Buffers.sol +24 -20
  9. package/codec/Decoders.sol +49 -31
  10. package/codec/Descriptors.sol +75 -72
  11. package/codec/Keys.sol +5 -1
  12. package/codec/Schema.sol +5 -1
  13. package/codec/Specs.sol +19 -9
  14. package/codec/Writers.sol +14 -19
  15. package/commands/Allocate.sol +8 -7
  16. package/commands/Base.sol +14 -52
  17. package/commands/Bootstrap.sol +95 -0
  18. package/commands/Burn.sol +7 -7
  19. package/commands/Cashout.sol +85 -0
  20. package/commands/Credit.sol +18 -16
  21. package/commands/Debit.sol +22 -21
  22. package/commands/Deposit.sol +13 -13
  23. package/commands/Payout.sol +8 -8
  24. package/commands/Provision.sol +13 -13
  25. package/commands/Recover.sol +7 -7
  26. package/commands/Relay.sol +22 -23
  27. package/commands/Repay.sol +36 -34
  28. package/commands/Settle.sol +24 -22
  29. package/commands/Withdraw.sol +7 -7
  30. package/commands/admin/AllowAssets.sol +7 -7
  31. package/commands/admin/Allowance.sol +7 -7
  32. package/commands/admin/Annotate.sol +7 -7
  33. package/commands/admin/Appoint.sol +7 -7
  34. package/commands/admin/Authorize.sol +7 -7
  35. package/commands/admin/Base.sol +5 -11
  36. package/commands/admin/DenyAssets.sol +7 -7
  37. package/commands/admin/Dismiss.sol +7 -7
  38. package/commands/admin/Execute.sol +8 -8
  39. package/commands/admin/Unauthorize.sol +7 -7
  40. package/core/Calls.sol +3 -3
  41. package/core/Endpoint.sol +7 -7
  42. package/core/Pipeline.sol +40 -22
  43. package/execution/Budget.sol +24 -3
  44. package/execution/Execution.sol +289 -506
  45. package/guards/Base.sol +1 -1
  46. package/guards/Revoke.sol +7 -7
  47. package/package.json +1 -1
  48. package/ports/Allowance.sol +3 -3
  49. package/ports/Assets.sol +7 -7
  50. package/ports/Base.sol +1 -1
  51. package/ports/Credit.sol +3 -3
  52. package/ports/Debit.sol +3 -3
  53. package/ports/Dispatch.sol +3 -3
  54. package/ports/Pipe.sol +7 -8
  55. package/ports/Post.sol +3 -3
  56. package/ports/Redeem.sol +3 -3
  57. package/queries/Assets.sol +3 -3
  58. package/queries/Balances.sol +3 -3
  59. package/queries/Base.sol +1 -1
  60. package/utils/Accounts.sol +1 -3
  61. package/utils/Actions.sol +2 -0
  62. package/utils/Assets.sol +1 -10
  63. package/utils/Cursors.sol +60 -116
  64. package/utils/Errors.sol +50 -0
  65. package/utils/Ids.sol +2 -5
  66. package/utils/Lanes.sol +0 -2
  67. package/utils/Nodes.sol +1 -3
  68. package/utils/Utils.sol +2 -9
  69. package/codec/Readers.sol +0 -190
package/codec/Blocks.sol CHANGED
@@ -100,16 +100,38 @@ library Blocks {
100
100
  end = body + len;
101
101
  }
102
102
 
103
+ /// @notice Validate a known block key and return its payload bounds.
104
+ /// @dev DANGER: This performs an unchecked calldata read and validates only
105
+ /// the key. The caller must validate the known payload shape and returned end.
106
+ /// @param abs Absolute calldata position of the header.
107
+ /// @param key Expected block key.
108
+ /// @return body Absolute position of the first payload byte.
109
+ /// @return end Absolute position immediately after the payload.
110
+ function expectKey(uint abs, bytes4 key) internal pure returns (uint body, uint end) {
111
+ uint head;
112
+ assembly ("memory-safe") {
113
+ head := calldataload(abs)
114
+ }
115
+ if (uint32(head >> 224) != uint32(key)) revert InvalidBlock();
116
+ uint len = uint32(head >> 192);
117
+ unchecked {
118
+ body = abs + Sizes.Header;
119
+ end = body + len;
120
+ }
121
+ }
122
+
103
123
  /// @dev Validate the key and exact payload size of a fixed-width block.
104
124
  /// @param abs Absolute calldata position of the header.
105
- /// @param spec Expected block specification.
125
+ /// @param key Expected block key.
106
126
  /// @param size Expected payload length.
107
127
  /// @return body Absolute position of the payload.
108
128
  /// @return end Absolute position after the payload.
109
- function expectFixed(uint abs, uint spec, uint size) private pure returns (uint body, uint end) {
110
- if (header(abs, Specs.key(spec)) != size) revert InvalidBlock();
111
- body = abs + Sizes.Header;
112
- end = body + size;
129
+ function expectFixed(uint abs, bytes4 key, uint size) private pure returns (uint body, uint end) {
130
+ if (header(abs, key) != size) revert InvalidBlock();
131
+ unchecked {
132
+ body = abs + Sizes.Header;
133
+ end = body + size;
134
+ }
113
135
  }
114
136
 
115
137
  /// @notice Validate an empty block at an absolute calldata position.
@@ -139,8 +161,9 @@ library Blocks {
139
161
  /// @param key Expected block key.
140
162
  /// @return Whether the expected key occurs with a zero-length payload.
141
163
  function isEmpty(uint abs, uint end, bytes4 key) internal pure returns (bool) {
142
- if (!hasAt(abs, end, key)) return false;
143
- return uint32(uint(read32(abs)) >> 192) == 0;
164
+ if (abs > end || Sizes.Header > end - abs) return false;
165
+ uint head = uint(read32(abs));
166
+ return uint32(head >> 224) == uint32(key) && uint32(head >> 192) == 0;
144
167
  }
145
168
 
146
169
  /// @notice Find the first block with `key` at or after absolute position `abs`.
@@ -178,6 +201,31 @@ library Blocks {
178
201
  }
179
202
  }
180
203
 
204
+ /// @notice Count consecutive blocks with `key` using a minimal hint-only scan.
205
+ /// @dev DANGER: This is not validation. It stops on a different key or when the
206
+ /// next declared block end exceeds `limit`; malformed or trailing data does not
207
+ /// revert. Use only for optional allocation hints whose result is later validated
208
+ /// by normal decoding and execution finalization.
209
+ /// @param abs Absolute start position.
210
+ /// @param limit Absolute region boundary.
211
+ /// @param key Block key forming the run.
212
+ /// @return total Number of complete consecutive matching blocks.
213
+ function runCount(uint abs, uint limit, bytes4 key) internal pure returns (uint total) {
214
+ uint expected = uint32(key);
215
+ assembly ("memory-safe") {
216
+ for { } lt(abs, limit) { } {
217
+ let head := calldataload(abs)
218
+ if iszero(eq(shr(224, head), expected)) { break }
219
+
220
+ let next := add(add(abs, 8), and(shr(192, head), 0xffffffff))
221
+ if gt(next, limit) { break }
222
+
223
+ abs := next
224
+ total := add(total, 1)
225
+ }
226
+ }
227
+ }
228
+
181
229
  /// @notice Count a run that must consume the complete region.
182
230
  /// @dev Reverts when any well-formed trailing block has a different key.
183
231
  /// @param abs Absolute start position.
@@ -332,6 +380,20 @@ library Blocks {
332
380
  }
333
381
  }
334
382
 
383
+ /// @notice Write a CASHOUT block at `i`.
384
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.Cashout` bytes first.
385
+ /// @param dst Destination buffer.
386
+ /// @param i Relative write position.
387
+ /// @param amount Native-asset amount to withdraw.
388
+ function writeCashout(bytes memory dst, uint i, uint amount) internal pure {
389
+ uint spec = Specs.Cashout;
390
+ assembly ("memory-safe") {
391
+ let p := add(add(dst, 0x20), i)
392
+ mstore(p, spec)
393
+ mstore(add(p, 0x08), amount)
394
+ }
395
+ }
396
+
335
397
  // Two-word payloads
336
398
 
337
399
  /// @notice Write an AMOUNT block at `i`.
@@ -416,6 +478,24 @@ library Blocks {
416
478
 
417
479
  // Three-word payloads
418
480
 
481
+ /// @notice Write a BOOTSTRAP block at `i`.
482
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.Bootstrap` bytes first.
483
+ /// @param dst Destination buffer.
484
+ /// @param i Relative write position.
485
+ /// @param asset Asset identifier to bootstrap.
486
+ /// @param amount Balance amount to source.
487
+ /// @param budget Native-value budget to source.
488
+ function writeBootstrap(bytes memory dst, uint i, bytes32 asset, uint amount, uint budget) internal pure {
489
+ uint spec = Specs.Bootstrap;
490
+ assembly ("memory-safe") {
491
+ let p := add(add(dst, 0x20), i)
492
+ mstore(p, spec)
493
+ mstore(add(p, 0x08), asset)
494
+ mstore(add(p, 0x28), amount)
495
+ mstore(add(p, 0x48), budget)
496
+ }
497
+ }
498
+
419
499
  /// @notice Write an ALLOCATION block at `i`.
420
500
  /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
421
501
  /// @param dst Destination buffer.
@@ -679,19 +759,19 @@ library Blocks {
679
759
  /// @param dst Destination buffer.
680
760
  /// @param i Relative write position.
681
761
  /// @param cmd Command identifier.
682
- /// @param resources Packed resources.
762
+ /// @param value Native value assigned to the step.
683
763
  /// @param input Command input.
684
- function writeStep(bytes memory dst, uint i, uint cmd, uint resources, bytes memory input) internal pure {
685
- uint len = 64 + Sizes.Header + input.length;
764
+ function writeStep(bytes memory dst, uint i, uint cmd, uint128 value, bytes memory input) internal pure {
765
+ uint len = 48 + Sizes.Header + input.length;
686
766
  uint key = uint32(Keys.Step);
687
767
  uint byteskey = uint32(Keys.Bytes);
688
768
  assembly ("memory-safe") {
689
769
  let p := add(add(dst, 0x20), i)
690
770
  mstore(p, or(shl(224, key), shl(192, len)))
691
771
  mstore(add(p, 0x08), cmd)
692
- mstore(add(p, 0x28), resources)
772
+ mstore(add(p, 0x28), shl(128, value))
693
773
 
694
- let q := add(p, 0x48)
774
+ let q := add(p, 0x38)
695
775
  let inputlen := mload(input)
696
776
  mstore(q, or(shl(224, byteskey), shl(192, inputlen)))
697
777
  mcopy(add(q, 0x08), add(input, 0x20), inputlen)
@@ -951,8 +1031,21 @@ library Blocks {
951
1031
  }
952
1032
 
953
1033
  /// @notice Encode a STEP block at `i`, copying its nested input from calldata.
954
- function copyStep(bytes memory dst, uint i, uint cmd, uint resources, bytes calldata input) internal pure {
955
- copyComposite(dst, i, Keys.Step, cmd, resources, input);
1034
+ function copyStep(bytes memory dst, uint i, uint cmd, uint128 value, bytes calldata input) internal pure {
1035
+ uint len = max32(48 + Sizes.Header + input.length);
1036
+ uint key = uint32(Keys.Step);
1037
+ uint byteskey = uint32(Keys.Bytes);
1038
+ assembly ("memory-safe") {
1039
+ let p := add(add(dst, 0x20), i)
1040
+ mstore(p, or(shl(224, key), shl(192, len)))
1041
+ mstore(add(p, 0x08), cmd)
1042
+ mstore(add(p, 0x28), shl(128, value))
1043
+
1044
+ let q := add(p, 0x38)
1045
+ let inputlen := input.length
1046
+ mstore(q, or(shl(224, byteskey), shl(192, inputlen)))
1047
+ calldatacopy(add(q, 0x08), input.offset, inputlen)
1048
+ }
956
1049
  }
957
1050
 
958
1051
  /// @notice Encode a CALL block at `i`, copying its nested payload from calldata.
@@ -1080,6 +1173,46 @@ library Blocks {
1080
1173
  }
1081
1174
  }
1082
1175
 
1176
+ /// @notice Require the byte at an absolute calldata position to match `expected`.
1177
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
1178
+ /// @param abs Absolute calldata position.
1179
+ /// @param expected Expected byte.
1180
+ function require1(uint abs, bytes1 expected) internal pure {
1181
+ if (read1(abs) != expected) revert UnexpectedValue();
1182
+ }
1183
+
1184
+ /// @notice Require the two bytes at an absolute calldata position to match `expected`.
1185
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
1186
+ /// @param abs Absolute calldata position.
1187
+ /// @param expected Expected two-byte value.
1188
+ function require2(uint abs, bytes2 expected) internal pure {
1189
+ if (read2(abs) != expected) revert UnexpectedValue();
1190
+ }
1191
+
1192
+ /// @notice Require the four bytes at an absolute calldata position to match `expected`.
1193
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
1194
+ /// @param abs Absolute calldata position.
1195
+ /// @param expected Expected four-byte value.
1196
+ function require4(uint abs, bytes4 expected) internal pure {
1197
+ if (read4(abs) != expected) revert UnexpectedValue();
1198
+ }
1199
+
1200
+ /// @notice Require the eight bytes at an absolute calldata position to match `expected`.
1201
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
1202
+ /// @param abs Absolute calldata position.
1203
+ /// @param expected Expected eight-byte value.
1204
+ function require8(uint abs, bytes8 expected) internal pure {
1205
+ if (read8(abs) != expected) revert UnexpectedValue();
1206
+ }
1207
+
1208
+ /// @notice Require the sixteen bytes at an absolute calldata position to match `expected`.
1209
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
1210
+ /// @param abs Absolute calldata position.
1211
+ /// @param expected Expected sixteen-byte value.
1212
+ function require16(uint abs, bytes16 expected) internal pure {
1213
+ if (read16(abs) != expected) revert UnexpectedValue();
1214
+ }
1215
+
1083
1216
  /// @notice Require the word at an absolute calldata position to match `expected`.
1084
1217
  /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
1085
1218
  /// @param abs Absolute calldata position.
@@ -1106,7 +1239,7 @@ library Blocks {
1106
1239
  /// @return a First payload word.
1107
1240
  /// @return end Absolute position after the block.
1108
1241
  function unpack32(uint abs, uint spec) internal pure returns (bytes32 a, uint end) {
1109
- (abs, end) = expectFixed(abs, spec, 32);
1242
+ (abs, end) = expectFixed(abs, Specs.key(spec), 32);
1110
1243
  a = read32(abs);
1111
1244
  }
1112
1245
 
@@ -1117,7 +1250,7 @@ library Blocks {
1117
1250
  /// @return b Second payload word.
1118
1251
  /// @return end Absolute position after the block.
1119
1252
  function unpack64(uint abs, uint spec) internal pure returns (bytes32 a, bytes32 b, uint end) {
1120
- (abs, end) = expectFixed(abs, spec, 64);
1253
+ (abs, end) = expectFixed(abs, Specs.key(spec), 64);
1121
1254
  assembly ("memory-safe") {
1122
1255
  a := calldataload(abs)
1123
1256
  b := calldataload(add(abs, 0x20))
@@ -1135,7 +1268,7 @@ library Blocks {
1135
1268
  uint abs,
1136
1269
  uint spec
1137
1270
  ) internal pure returns (bytes32 a, bytes32 b, bytes32 c, uint end) {
1138
- (abs, end) = expectFixed(abs, spec, 96);
1271
+ (abs, end) = expectFixed(abs, Specs.key(spec), 96);
1139
1272
  assembly ("memory-safe") {
1140
1273
  a := calldataload(abs)
1141
1274
  b := calldataload(add(abs, 0x20))
@@ -1155,7 +1288,7 @@ library Blocks {
1155
1288
  uint abs,
1156
1289
  uint spec
1157
1290
  ) internal pure returns (bytes32 a, bytes32 b, bytes32 c, bytes32 d, uint end) {
1158
- (abs, end) = expectFixed(abs, spec, 128);
1291
+ (abs, end) = expectFixed(abs, Specs.key(spec), 128);
1159
1292
  assembly ("memory-safe") {
1160
1293
  a := calldataload(abs)
1161
1294
  b := calldataload(add(abs, 0x20))
@@ -1177,7 +1310,7 @@ library Blocks {
1177
1310
  uint abs,
1178
1311
  uint spec
1179
1312
  ) internal pure returns (bytes32 a, bytes32 b, bytes32 c, bytes32 d, bytes32 e, uint end) {
1180
- (abs, end) = expectFixed(abs, spec, 160);
1313
+ (abs, end) = expectFixed(abs, Specs.key(spec), 160);
1181
1314
  assembly ("memory-safe") {
1182
1315
  a := calldataload(abs)
1183
1316
  b := calldataload(add(abs, 0x20))
@@ -1284,11 +1417,9 @@ library Blocks {
1284
1417
  uint head;
1285
1418
  assembly ("memory-safe") {
1286
1419
  head := calldataload(abs)
1287
- }
1288
- if (head >> 192 != Specs.Account >> 192) revert InvalidBlock();
1289
- assembly ("memory-safe") {
1290
1420
  account := calldataload(add(abs, 0x08))
1291
1421
  }
1422
+ if (head >> 192 != Specs.Account >> 192) revert InvalidBlock();
1292
1423
  }
1293
1424
 
1294
1425
  /// @notice Decode a low-level fixed-width ASSET block at `abs`.
@@ -1298,11 +1429,9 @@ library Blocks {
1298
1429
  uint head;
1299
1430
  assembly ("memory-safe") {
1300
1431
  head := calldataload(abs)
1301
- }
1302
- if (head >> 192 != Specs.Asset >> 192) revert InvalidBlock();
1303
- assembly ("memory-safe") {
1304
1432
  asset := calldataload(add(abs, 0x08))
1305
1433
  }
1434
+ if (head >> 192 != Specs.Asset >> 192) revert InvalidBlock();
1306
1435
  }
1307
1436
 
1308
1437
  /// @notice Decode a low-level fixed-width NODE block at `abs`.
@@ -1312,11 +1441,9 @@ library Blocks {
1312
1441
  uint head;
1313
1442
  assembly ("memory-safe") {
1314
1443
  head := calldataload(abs)
1315
- }
1316
- if (head >> 192 != Specs.Node >> 192) revert InvalidBlock();
1317
- assembly ("memory-safe") {
1318
1444
  node := calldataload(add(abs, 0x08))
1319
1445
  }
1446
+ if (head >> 192 != Specs.Node >> 192) revert InvalidBlock();
1320
1447
  }
1321
1448
 
1322
1449
  /// @notice Decode a low-level fixed-width STATUS block at `abs`.
@@ -1326,11 +1453,21 @@ library Blocks {
1326
1453
  uint head;
1327
1454
  assembly ("memory-safe") {
1328
1455
  head := calldataload(abs)
1456
+ code := calldataload(add(abs, 0x08))
1329
1457
  }
1330
1458
  if (head >> 192 != Specs.Status >> 192) revert InvalidBlock();
1459
+ }
1460
+
1461
+ /// @notice Decode a low-level fixed-width CASHOUT block at `abs`.
1462
+ /// @param abs Absolute block position.
1463
+ /// @return amount Native-asset amount to withdraw.
1464
+ function unpackCashout(uint abs) internal pure returns (uint amount) {
1465
+ uint head;
1331
1466
  assembly ("memory-safe") {
1332
- code := calldataload(add(abs, 0x08))
1467
+ head := calldataload(abs)
1468
+ amount := calldataload(add(abs, 0x08))
1333
1469
  }
1470
+ if (head >> 192 != Specs.Cashout >> 192) revert InvalidBlock();
1334
1471
  }
1335
1472
 
1336
1473
  // Two-word payloads
@@ -1343,12 +1480,10 @@ library Blocks {
1343
1480
  uint head;
1344
1481
  assembly ("memory-safe") {
1345
1482
  head := calldataload(abs)
1346
- }
1347
- if (head >> 192 != Specs.Amount >> 192) revert InvalidBlock();
1348
- assembly ("memory-safe") {
1349
1483
  asset := calldataload(add(abs, 0x08))
1350
1484
  amount := calldataload(add(abs, 0x28))
1351
1485
  }
1486
+ if (head >> 192 != Specs.Amount >> 192) revert InvalidBlock();
1352
1487
  }
1353
1488
 
1354
1489
  /// @notice Decode a low-level fixed-width BALANCE block at `abs`.
@@ -1359,13 +1494,10 @@ library Blocks {
1359
1494
  uint head;
1360
1495
  assembly ("memory-safe") {
1361
1496
  head := calldataload(abs)
1362
- }
1363
- if (head >> 192 != Specs.Balance >> 192) revert InvalidBlock();
1364
-
1365
- assembly ("memory-safe") {
1366
1497
  asset := calldataload(add(abs, 0x08))
1367
1498
  amount := calldataload(add(abs, 0x28))
1368
1499
  }
1500
+ if (head >> 192 != Specs.Balance >> 192) revert InvalidBlock();
1369
1501
  }
1370
1502
 
1371
1503
  /// @notice Decode a low-level fixed-width DEBT block at `abs`.
@@ -1376,12 +1508,10 @@ library Blocks {
1376
1508
  uint head;
1377
1509
  assembly ("memory-safe") {
1378
1510
  head := calldataload(abs)
1379
- }
1380
- if (head >> 192 != Specs.Debt >> 192) revert InvalidBlock();
1381
- assembly ("memory-safe") {
1382
1511
  liability := calldataload(add(abs, 0x08))
1383
1512
  debt := calldataload(add(abs, 0x28))
1384
1513
  }
1514
+ if (head >> 192 != Specs.Debt >> 192) revert InvalidBlock();
1385
1515
  }
1386
1516
 
1387
1517
  /// @notice Decode a low-level fixed-width ACCOUNT_ASSET block at `abs`.
@@ -1392,16 +1522,30 @@ library Blocks {
1392
1522
  uint head;
1393
1523
  assembly ("memory-safe") {
1394
1524
  head := calldataload(abs)
1395
- }
1396
- if (head >> 192 != Specs.AccountAsset >> 192) revert InvalidBlock();
1397
- assembly ("memory-safe") {
1398
1525
  account := calldataload(add(abs, 0x08))
1399
1526
  asset := calldataload(add(abs, 0x28))
1400
1527
  }
1528
+ if (head >> 192 != Specs.AccountAsset >> 192) revert InvalidBlock();
1401
1529
  }
1402
1530
 
1403
1531
  // Three-word payloads
1404
1532
 
1533
+ /// @notice Decode a low-level fixed-width BOOTSTRAP block at `abs`.
1534
+ /// @param abs Absolute block position.
1535
+ /// @return asset Decoded asset identifier.
1536
+ /// @return amount Decoded balance amount.
1537
+ /// @return budget Decoded native-value budget contribution.
1538
+ function unpackBootstrap(uint abs) internal pure returns (bytes32 asset, uint amount, uint budget) {
1539
+ uint head;
1540
+ assembly ("memory-safe") {
1541
+ head := calldataload(abs)
1542
+ asset := calldataload(add(abs, 0x08))
1543
+ amount := calldataload(add(abs, 0x28))
1544
+ budget := calldataload(add(abs, 0x48))
1545
+ }
1546
+ if (head >> 192 != Specs.Bootstrap >> 192) revert InvalidBlock();
1547
+ }
1548
+
1405
1549
  /// @notice Decode a low-level fixed-width ALLOCATION block at `abs`.
1406
1550
  /// @param abs Absolute block position.
1407
1551
  /// @return host Decoded host identifier.
@@ -1411,13 +1555,11 @@ library Blocks {
1411
1555
  uint head;
1412
1556
  assembly ("memory-safe") {
1413
1557
  head := calldataload(abs)
1414
- }
1415
- if (head >> 192 != Specs.Allocation >> 192) revert InvalidBlock();
1416
- assembly ("memory-safe") {
1417
1558
  host := calldataload(add(abs, 0x08))
1418
1559
  asset := calldataload(add(abs, 0x28))
1419
1560
  amount := calldataload(add(abs, 0x48))
1420
1561
  }
1562
+ if (head >> 192 != Specs.Allocation >> 192) revert InvalidBlock();
1421
1563
  }
1422
1564
 
1423
1565
  /// @notice Decode a low-level fixed-width ALLOWANCE block at `abs`.
@@ -1429,13 +1571,11 @@ library Blocks {
1429
1571
  uint head;
1430
1572
  assembly ("memory-safe") {
1431
1573
  head := calldataload(abs)
1432
- }
1433
- if (head >> 192 != Specs.Allowance >> 192) revert InvalidBlock();
1434
- assembly ("memory-safe") {
1435
1574
  host := calldataload(add(abs, 0x08))
1436
1575
  asset := calldataload(add(abs, 0x28))
1437
1576
  amount := calldataload(add(abs, 0x48))
1438
1577
  }
1578
+ if (head >> 192 != Specs.Allowance >> 192) revert InvalidBlock();
1439
1579
  }
1440
1580
 
1441
1581
  /// @notice Decode a low-level fixed-width CUSTODY block at `abs`.
@@ -1447,13 +1587,11 @@ library Blocks {
1447
1587
  uint head;
1448
1588
  assembly ("memory-safe") {
1449
1589
  head := calldataload(abs)
1450
- }
1451
- if (head >> 192 != Specs.Custody >> 192) revert InvalidBlock();
1452
- assembly ("memory-safe") {
1453
1590
  host := calldataload(add(abs, 0x08))
1454
1591
  asset := calldataload(add(abs, 0x28))
1455
1592
  amount := calldataload(add(abs, 0x48))
1456
1593
  }
1594
+ if (head >> 192 != Specs.Custody >> 192) revert InvalidBlock();
1457
1595
  }
1458
1596
 
1459
1597
  /// @notice Decode a low-level fixed-width ACCOUNT_AMOUNT block at `abs`.
@@ -1465,13 +1603,11 @@ library Blocks {
1465
1603
  uint head;
1466
1604
  assembly ("memory-safe") {
1467
1605
  head := calldataload(abs)
1468
- }
1469
- if (head >> 192 != Specs.AccountAmount >> 192) revert InvalidBlock();
1470
- assembly ("memory-safe") {
1471
1606
  account := calldataload(add(abs, 0x08))
1472
1607
  asset := calldataload(add(abs, 0x28))
1473
1608
  amount := calldataload(add(abs, 0x48))
1474
1609
  }
1610
+ if (head >> 192 != Specs.AccountAmount >> 192) revert InvalidBlock();
1475
1611
  }
1476
1612
 
1477
1613
  /// @notice Decode a low-level fixed-width HOST_AMOUNT block at `abs`.
@@ -1483,13 +1619,11 @@ library Blocks {
1483
1619
  uint head;
1484
1620
  assembly ("memory-safe") {
1485
1621
  head := calldataload(abs)
1486
- }
1487
- if (head >> 192 != Specs.HostAmount >> 192) revert InvalidBlock();
1488
- assembly ("memory-safe") {
1489
1622
  host := calldataload(add(abs, 0x08))
1490
1623
  asset := calldataload(add(abs, 0x28))
1491
1624
  amount := calldataload(add(abs, 0x48))
1492
1625
  }
1626
+ if (head >> 192 != Specs.HostAmount >> 192) revert InvalidBlock();
1493
1627
  }
1494
1628
 
1495
1629
  /// @notice Decode a low-level fixed-width HOST_ACCOUNT_ASSET block at `abs`.
@@ -1501,13 +1635,11 @@ library Blocks {
1501
1635
  uint head;
1502
1636
  assembly ("memory-safe") {
1503
1637
  head := calldataload(abs)
1504
- }
1505
- if (head >> 192 != Specs.HostAccountAsset >> 192) revert InvalidBlock();
1506
- assembly ("memory-safe") {
1507
1638
  host := calldataload(add(abs, 0x08))
1508
1639
  account := calldataload(add(abs, 0x28))
1509
1640
  asset := calldataload(add(abs, 0x48))
1510
1641
  }
1642
+ if (head >> 192 != Specs.HostAccountAsset >> 192) revert InvalidBlock();
1511
1643
  }
1512
1644
 
1513
1645
  // Four-word payloads
@@ -1524,14 +1656,12 @@ library Blocks {
1524
1656
  uint head;
1525
1657
  assembly ("memory-safe") {
1526
1658
  head := calldataload(abs)
1527
- }
1528
- if (head >> 192 != Specs.Position >> 192) revert InvalidBlock();
1529
- assembly ("memory-safe") {
1530
1659
  asset := calldataload(add(abs, 0x08))
1531
1660
  amount := calldataload(add(abs, 0x28))
1532
1661
  liability := calldataload(add(abs, 0x48))
1533
1662
  debt := calldataload(add(abs, 0x68))
1534
1663
  }
1664
+ if (head >> 192 != Specs.Position >> 192) revert InvalidBlock();
1535
1665
  }
1536
1666
 
1537
1667
  /// @notice Decode a low-level fixed-width HOST_ASSET block at `abs`.
@@ -1542,12 +1672,10 @@ library Blocks {
1542
1672
  uint head;
1543
1673
  assembly ("memory-safe") {
1544
1674
  head := calldataload(abs)
1545
- }
1546
- if (head >> 192 != Specs.HostAsset >> 192) revert InvalidBlock();
1547
- assembly ("memory-safe") {
1548
1675
  host := calldataload(add(abs, 0x08))
1549
1676
  asset := calldataload(add(abs, 0x28))
1550
1677
  }
1678
+ if (head >> 192 != Specs.HostAsset >> 192) revert InvalidBlock();
1551
1679
  }
1552
1680
 
1553
1681
  /// @notice Decode a low-level fixed-width TRANSACTION block at `abs`.
@@ -1560,14 +1688,12 @@ library Blocks {
1560
1688
  uint head;
1561
1689
  assembly ("memory-safe") {
1562
1690
  head := calldataload(abs)
1563
- }
1564
- if (head >> 192 != Specs.Transaction >> 192) revert InvalidBlock();
1565
- assembly ("memory-safe") {
1566
1691
  from := calldataload(add(abs, 0x08))
1567
1692
  to := calldataload(add(abs, 0x28))
1568
1693
  asset := calldataload(add(abs, 0x48))
1569
1694
  amount := calldataload(add(abs, 0x68))
1570
1695
  }
1696
+ if (head >> 192 != Specs.Transaction >> 192) revert InvalidBlock();
1571
1697
  }
1572
1698
 
1573
1699
  /// @notice Decode a low-level fixed-width HOST_ACCOUNT_AMOUNT block at `abs`.
@@ -1582,14 +1708,12 @@ library Blocks {
1582
1708
  uint head;
1583
1709
  assembly ("memory-safe") {
1584
1710
  head := calldataload(abs)
1585
- }
1586
- if (head >> 192 != Specs.HostAccountAmount >> 192) revert InvalidBlock();
1587
- assembly ("memory-safe") {
1588
1711
  host := calldataload(add(abs, 0x08))
1589
1712
  account := calldataload(add(abs, 0x28))
1590
1713
  asset := calldataload(add(abs, 0x48))
1591
1714
  amount := calldataload(add(abs, 0x68))
1592
1715
  }
1716
+ if (head >> 192 != Specs.HostAccountAmount >> 192) revert InvalidBlock();
1593
1717
  }
1594
1718
 
1595
1719
  // Dynamic leaf blocks
@@ -1599,7 +1723,16 @@ library Blocks {
1599
1723
  /// @return value Decoded list payload.
1600
1724
  /// @return end Absolute position after the block.
1601
1725
  function unpackList(uint abs) internal pure returns (bytes calldata value, uint end) {
1602
- return unpackRaw(abs, Keys.List);
1726
+ uint head;
1727
+ uint len;
1728
+ assembly ("memory-safe") {
1729
+ head := calldataload(abs)
1730
+ len := and(shr(192, head), 0xffffffff)
1731
+ value.offset := add(abs, 0x08)
1732
+ value.length := len
1733
+ }
1734
+ if (uint32(head >> 224) != uint32(Keys.List)) revert InvalidBlock();
1735
+ end = abs + Sizes.Header + len;
1603
1736
  }
1604
1737
 
1605
1738
  /// @notice Decode one EVM payload and its absolute end position.
@@ -1607,7 +1740,16 @@ library Blocks {
1607
1740
  /// @return value Decoded EVM payload.
1608
1741
  /// @return end Absolute position after the block.
1609
1742
  function unpackEvm(uint abs) internal pure returns (bytes calldata value, uint end) {
1610
- return unpackRaw(abs, Keys.Evm);
1743
+ uint head;
1744
+ uint len;
1745
+ assembly ("memory-safe") {
1746
+ head := calldataload(abs)
1747
+ len := and(shr(192, head), 0xffffffff)
1748
+ value.offset := add(abs, 0x08)
1749
+ value.length := len
1750
+ }
1751
+ if (uint32(head >> 224) != uint32(Keys.Evm)) revert InvalidBlock();
1752
+ end = abs + Sizes.Header + len;
1611
1753
  }
1612
1754
 
1613
1755
  /// @notice Decode one BYTES payload and its absolute end position.
@@ -1615,7 +1757,16 @@ library Blocks {
1615
1757
  /// @return value Decoded byte payload.
1616
1758
  /// @return end Absolute position after the block.
1617
1759
  function unpackBytes(uint abs) internal pure returns (bytes calldata value, uint end) {
1618
- return unpackRaw(abs, Keys.Bytes);
1760
+ uint head;
1761
+ uint len;
1762
+ assembly ("memory-safe") {
1763
+ head := calldataload(abs)
1764
+ len := and(shr(192, head), 0xffffffff)
1765
+ value.offset := add(abs, 0x08)
1766
+ value.length := len
1767
+ }
1768
+ if (uint32(head >> 224) != uint32(Keys.Bytes)) revert InvalidBlock();
1769
+ end = abs + Sizes.Header + len;
1619
1770
  }
1620
1771
 
1621
1772
  /// @notice Decode one STRING payload and its absolute end position.
@@ -1623,20 +1774,15 @@ library Blocks {
1623
1774
  /// @return value Decoded string bytes.
1624
1775
  /// @return end Absolute position after the block.
1625
1776
  function unpackString(uint abs) internal pure returns (bytes calldata value, uint end) {
1626
- return unpackRaw(abs, Keys.String);
1627
- }
1628
-
1629
- /// @dev Decode a dynamic leaf block after validating its key.
1630
- /// @param abs Absolute block position.
1631
- /// @param expected Expected block key.
1632
- /// @return value Decoded payload.
1633
- /// @return end Absolute position after the block.
1634
- function unpackRaw(uint abs, bytes4 expected) private pure returns (bytes calldata value, uint end) {
1635
- uint len = header(abs, expected);
1777
+ uint head;
1778
+ uint len;
1636
1779
  assembly ("memory-safe") {
1780
+ head := calldataload(abs)
1781
+ len := and(shr(192, head), 0xffffffff)
1637
1782
  value.offset := add(abs, 0x08)
1638
1783
  value.length := len
1639
1784
  }
1785
+ if (uint32(head >> 224) != uint32(Keys.String)) revert InvalidBlock();
1640
1786
  end = abs + Sizes.Header + len;
1641
1787
  }
1642
1788
 
@@ -1653,7 +1799,7 @@ library Blocks {
1653
1799
  uint abs
1654
1800
  ) internal pure returns (uint entity, bytes calldata stream, uint end) {
1655
1801
  uint limit;
1656
- (abs, limit) = expect(abs, Specs.Annotation);
1802
+ (abs, limit) = expectKey(abs, Keys.Annotation);
1657
1803
  assembly ("memory-safe") {
1658
1804
  entity := calldataload(abs)
1659
1805
  }
@@ -1671,7 +1817,7 @@ library Blocks {
1671
1817
  uint abs
1672
1818
  ) internal pure returns (bytes32 account, bytes calldata state, bytes calldata input, uint end) {
1673
1819
  uint limit;
1674
- (abs, limit) = expect(abs, Specs.Context);
1820
+ (abs, limit) = expectKey(abs, Keys.Context);
1675
1821
  assembly ("memory-safe") {
1676
1822
  account := calldataload(abs)
1677
1823
  }
@@ -1685,19 +1831,19 @@ library Blocks {
1685
1831
  /// @notice Decode one STEP block and its nested input.
1686
1832
  /// @param abs Absolute block position.
1687
1833
  /// @return cmd Decoded command identifier.
1688
- /// @return resources Decoded packed resources.
1834
+ /// @return value Decoded native value.
1689
1835
  /// @return input Decoded command input.
1690
1836
  /// @return end Absolute position after the block.
1691
1837
  function unpackStep(
1692
1838
  uint abs
1693
- ) internal pure returns (uint cmd, uint resources, bytes calldata input, uint end) {
1839
+ ) internal pure returns (uint cmd, uint128 value, bytes calldata input, uint end) {
1694
1840
  uint limit;
1695
- (abs, limit) = expect(abs, Specs.Step);
1841
+ (abs, limit) = expectKey(abs, Keys.Step);
1696
1842
  assembly ("memory-safe") {
1697
1843
  cmd := calldataload(abs)
1698
- resources := calldataload(add(abs, 0x20))
1844
+ value := shr(128, calldataload(add(abs, 0x20)))
1699
1845
  }
1700
- (input, end) = unpackBytes(abs + 64);
1846
+ (input, end) = unpackBytes(abs + 48);
1701
1847
  if (end != limit) revert InvalidBlock();
1702
1848
  }
1703
1849
 
@@ -1711,7 +1857,7 @@ library Blocks {
1711
1857
  uint abs
1712
1858
  ) internal pure returns (uint target, uint resources, bytes calldata payload, uint end) {
1713
1859
  uint limit;
1714
- (abs, limit) = expect(abs, Specs.Call);
1860
+ (abs, limit) = expectKey(abs, Keys.Call);
1715
1861
  assembly ("memory-safe") {
1716
1862
  target := calldataload(abs)
1717
1863
  resources := calldataload(add(abs, 0x20))
@@ -1730,7 +1876,7 @@ library Blocks {
1730
1876
  uint abs
1731
1877
  ) internal pure returns (uint portal, uint resources, bytes calldata input, uint end) {
1732
1878
  uint limit;
1733
- (abs, limit) = expect(abs, Specs.Relay);
1879
+ (abs, limit) = expectKey(abs, Keys.Relay);
1734
1880
  assembly ("memory-safe") {
1735
1881
  portal := calldataload(abs)
1736
1882
  resources := calldataload(add(abs, 0x20))
@@ -1749,7 +1895,7 @@ library Blocks {
1749
1895
  uint abs
1750
1896
  ) internal pure returns (uint portal, uint resources, bytes calldata payload, uint end) {
1751
1897
  uint limit;
1752
- (abs, limit) = expect(abs, Specs.Dispatch);
1898
+ (abs, limit) = expectKey(abs, Keys.Dispatch);
1753
1899
  assembly ("memory-safe") {
1754
1900
  portal := calldataload(abs)
1755
1901
  resources := calldataload(add(abs, 0x20))
@@ -1765,7 +1911,7 @@ library Blocks {
1765
1911
  /// @return end Absolute position after the block.
1766
1912
  function unpackLabel(uint abs) internal pure returns (bytes32 namespace, string memory name, uint end) {
1767
1913
  uint limit;
1768
- (abs, limit) = expect(abs, Specs.Label);
1914
+ (abs, limit) = expectKey(abs, Keys.Label);
1769
1915
  assembly ("memory-safe") {
1770
1916
  namespace := calldataload(abs)
1771
1917
  }
@@ -1783,7 +1929,7 @@ library Blocks {
1783
1929
  /// @return end Absolute position after the block.
1784
1930
  function unpackSchema(uint abs) internal pure returns (uint spec, string memory body, bytes32 name, uint end) {
1785
1931
  uint limit;
1786
- (abs, limit) = expect(abs, Specs.Schema);
1932
+ (abs, limit) = expectKey(abs, Keys.Schema);
1787
1933
  assembly ("memory-safe") {
1788
1934
  spec := calldataload(abs)
1789
1935
  }
@@ -1810,7 +1956,7 @@ library Blocks {
1810
1956
  uint abs
1811
1957
  ) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness, uint end) {
1812
1958
  uint limit;
1813
- (abs, limit) = expect(abs, Specs.Recover);
1959
+ (abs, limit) = expectKey(abs, Keys.Recover);
1814
1960
  assembly ("memory-safe") {
1815
1961
  handler := calldataload(abs)
1816
1962
  resources := calldataload(add(abs, 0x20))
@@ -1963,6 +2109,24 @@ library Blocks {
1963
2109
 
1964
2110
  // Fixed-width factories
1965
2111
 
2112
+ /// @notice Encode a BOOTSTRAP block.
2113
+ /// @param asset Asset identifier.
2114
+ /// @param amount Balance amount to source.
2115
+ /// @param budget Native-value budget to source.
2116
+ /// @return value Encoded BOOTSTRAP block bytes.
2117
+ function createBootstrap(bytes32 asset, uint amount, uint budget) internal pure returns (bytes memory value) {
2118
+ value = allocate(Sizes.Bootstrap);
2119
+ writeBootstrap(value, 0, asset, amount, budget);
2120
+ }
2121
+
2122
+ /// @notice Encode a CASHOUT block.
2123
+ /// @param amount Native-asset amount to withdraw.
2124
+ /// @return value Encoded CASHOUT block bytes.
2125
+ function createCashout(uint amount) internal pure returns (bytes memory value) {
2126
+ value = allocate(Sizes.Cashout);
2127
+ writeCashout(value, 0, amount);
2128
+ }
2129
+
1966
2130
  /// @notice Encode an AMOUNT block.
1967
2131
  /// @param asset Asset identifier.
1968
2132
  /// @param amount Token amount.
@@ -2036,20 +2200,20 @@ library Blocks {
2036
2200
 
2037
2201
  /// @notice Encode a STEP block.
2038
2202
  /// @param cmd Command identifier.
2039
- /// @param resources Packed resources assigned to the step.
2203
+ /// @param value Native value assigned to the step.
2040
2204
  /// @param input Raw nested input payload.
2041
- /// @return value Encoded STEP block bytes.
2042
- function createStep(uint cmd, uint resources, bytes memory input) internal pure returns (bytes memory value) {
2043
- uint len = max32(Sizes.B64 + Sizes.Header + input.length);
2044
- value = allocate(len);
2045
- writeStep(value, 0, cmd, resources, input);
2205
+ /// @return encoded Encoded STEP block bytes.
2206
+ function createStep(uint cmd, uint128 value, bytes memory input) internal pure returns (bytes memory encoded) {
2207
+ uint len = max32(Sizes.Step + input.length);
2208
+ encoded = allocate(len);
2209
+ writeStep(encoded, 0, cmd, value, input);
2046
2210
  }
2047
2211
 
2048
2212
  /// @notice Encode a STEP block by copying its nested input from calldata.
2049
- function createStepCopy(uint cmd, uint resources, bytes calldata input) internal pure returns (bytes memory value) {
2050
- uint len = max32(Sizes.B64 + Sizes.Header + input.length);
2051
- value = allocate(len);
2052
- copyStep(value, 0, cmd, resources, input);
2213
+ function createStepCopy(uint cmd, uint128 value, bytes calldata input) internal pure returns (bytes memory encoded) {
2214
+ uint len = max32(Sizes.Step + input.length);
2215
+ encoded = allocate(len);
2216
+ copyStep(encoded, 0, cmd, value, input);
2053
2217
  }
2054
2218
 
2055
2219
  /// @notice Encode a CALL block.
@@ -2158,3 +2322,85 @@ library Blocks {
2158
2322
  copyRecover(value, 0, handler, resources, recoverykey, witness);
2159
2323
  }
2160
2324
  }
2325
+
2326
+ /// @title Memory
2327
+ /// @notice Fixed-stride decoding for homogeneous block streams held in memory.
2328
+ /// @dev The unpackers are intentionally unchecked beyond their exact header
2329
+ /// comparison. Callers must obtain bounds with `bounds`, advance by the matching
2330
+ /// complete encoded block size, and stop at the returned end position.
2331
+ library Memory {
2332
+ uint64 private constant BalanceHeader = (uint64(uint32(Keys.Balance)) << 32) | 64;
2333
+ uint64 private constant DebtHeader = (uint64(uint32(Keys.Debt)) << 32) | 64;
2334
+ uint64 private constant PositionHeader = (uint64(uint32(Keys.Position)) << 32) | 128;
2335
+ uint64 private constant TransactionHeader = (uint64(uint32(Keys.Transaction)) << 32) | 128;
2336
+
2337
+ /// @notice Return absolute bounds for a fixed-stride memory block stream.
2338
+ /// @dev DANGER: Empty streams are valid and `size` must be nonzero. The size
2339
+ /// must include the complete block header and payload.
2340
+ /// @param source Memory block stream.
2341
+ /// @param size Complete encoded size of each block.
2342
+ /// @return abs Absolute memory position of the first block header.
2343
+ /// @return end Absolute memory position immediately after the source.
2344
+ function bounds(bytes memory source, uint size) internal pure returns (uint abs, uint end) {
2345
+ uint len = source.length;
2346
+ uint remainder;
2347
+ assembly ("memory-safe") {
2348
+ remainder := mod(len, size)
2349
+ abs := add(source, 0x20)
2350
+ end := add(abs, len)
2351
+ }
2352
+ if (remainder != 0) revert Blocks.InvalidBlock();
2353
+ }
2354
+
2355
+ /// @notice Decode a BALANCE block at an in-bounds absolute memory position.
2356
+ function unpackBalance(uint abs) internal pure returns (bytes32 asset, uint amount) {
2357
+ uint64 actual;
2358
+ assembly ("memory-safe") {
2359
+ actual := shr(192, mload(abs))
2360
+ asset := mload(add(abs, 0x08))
2361
+ amount := mload(add(abs, 0x28))
2362
+ }
2363
+ if (actual != BalanceHeader) revert Blocks.InvalidBlock();
2364
+ }
2365
+
2366
+ /// @notice Decode a DEBT block at an in-bounds absolute memory position.
2367
+ function unpackDebt(uint abs) internal pure returns (bytes32 liability, uint debt) {
2368
+ uint64 actual;
2369
+ assembly ("memory-safe") {
2370
+ actual := shr(192, mload(abs))
2371
+ liability := mload(add(abs, 0x08))
2372
+ debt := mload(add(abs, 0x28))
2373
+ }
2374
+ if (actual != DebtHeader) revert Blocks.InvalidBlock();
2375
+ }
2376
+
2377
+ /// @notice Decode a POSITION block at an in-bounds absolute memory position.
2378
+ function unpackPosition(
2379
+ uint abs
2380
+ ) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
2381
+ uint64 actual;
2382
+ assembly ("memory-safe") {
2383
+ actual := shr(192, mload(abs))
2384
+ asset := mload(add(abs, 0x08))
2385
+ amount := mload(add(abs, 0x28))
2386
+ liability := mload(add(abs, 0x48))
2387
+ debt := mload(add(abs, 0x68))
2388
+ }
2389
+ if (actual != PositionHeader) revert Blocks.InvalidBlock();
2390
+ }
2391
+
2392
+ /// @notice Decode a TRANSACTION block at an in-bounds absolute memory position.
2393
+ function unpackTransaction(
2394
+ uint abs
2395
+ ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
2396
+ uint64 actual;
2397
+ assembly ("memory-safe") {
2398
+ actual := shr(192, mload(abs))
2399
+ from := mload(add(abs, 0x08))
2400
+ to := mload(add(abs, 0x28))
2401
+ asset := mload(add(abs, 0x48))
2402
+ amount := mload(add(abs, 0x68))
2403
+ }
2404
+ if (actual != TransactionHeader) revert Blocks.InvalidBlock();
2405
+ }
2406
+ }