@rootzero/contracts 1.25.0 → 1.27.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 (71) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/Codec.sol +1 -2
  3. package/Endpoints.sol +2 -0
  4. package/README.md +73 -51
  5. package/Utils.sol +2 -1
  6. package/codec/Blocks.sol +276 -88
  7. package/codec/Buffers.sol +24 -20
  8. package/codec/Decoders.sol +35 -37
  9. package/codec/Descriptors.sol +75 -72
  10. package/codec/Keys.sol +5 -1
  11. package/codec/Schema.sol +7 -1
  12. package/codec/Specs.sol +19 -9
  13. package/codec/Writers.sol +14 -19
  14. package/commands/Allocate.sol +8 -7
  15. package/commands/Base.sol +14 -49
  16. package/commands/Bootstrap.sol +81 -0
  17. package/commands/Burn.sol +7 -7
  18. package/commands/Cashout.sol +86 -0
  19. package/commands/Credit.sol +20 -17
  20. package/commands/Debit.sol +25 -20
  21. package/commands/Deposit.sol +13 -13
  22. package/commands/Payout.sol +8 -8
  23. package/commands/Provision.sol +13 -13
  24. package/commands/Recover.sol +7 -7
  25. package/commands/Relay.sol +22 -23
  26. package/commands/Repay.sol +38 -35
  27. package/commands/Settle.sol +26 -23
  28. package/commands/Withdraw.sol +7 -7
  29. package/commands/admin/AllowAssets.sol +7 -7
  30. package/commands/admin/Allowance.sol +7 -7
  31. package/commands/admin/Annotate.sol +7 -7
  32. package/commands/admin/Appoint.sol +7 -7
  33. package/commands/admin/Authorize.sol +7 -7
  34. package/commands/admin/Base.sol +5 -8
  35. package/commands/admin/DenyAssets.sol +7 -7
  36. package/commands/admin/Dismiss.sol +7 -7
  37. package/commands/admin/Execute.sol +8 -8
  38. package/commands/admin/Unauthorize.sol +7 -7
  39. package/core/Access.sol +1 -0
  40. package/core/Calls.sol +3 -3
  41. package/core/Endpoint.sol +7 -7
  42. package/core/Pipeline.sol +19 -23
  43. package/core/Settlement.sol +2 -1
  44. package/core/Types.sol +1 -0
  45. package/execution/Budget.sol +2 -3
  46. package/execution/Execution.sol +270 -511
  47. package/guards/Base.sol +1 -1
  48. package/guards/Revoke.sol +7 -7
  49. package/package.json +1 -1
  50. package/ports/Allowance.sol +3 -3
  51. package/ports/Assets.sol +7 -7
  52. package/ports/Base.sol +1 -1
  53. package/ports/Credit.sol +3 -3
  54. package/ports/Debit.sol +3 -3
  55. package/ports/Dispatch.sol +3 -3
  56. package/ports/Pipe.sol +3 -3
  57. package/ports/Post.sol +3 -3
  58. package/ports/Redeem.sol +3 -3
  59. package/queries/Assets.sol +3 -3
  60. package/queries/Balances.sol +3 -3
  61. package/queries/Base.sol +1 -1
  62. package/utils/Accounts.sol +17 -10
  63. package/utils/Actions.sol +2 -0
  64. package/utils/Assets.sol +1 -10
  65. package/utils/Cursors.sol +60 -116
  66. package/utils/Errors.sol +56 -0
  67. package/utils/Ids.sol +2 -5
  68. package/utils/Lanes.sol +0 -2
  69. package/utils/Nodes.sol +1 -3
  70. package/utils/Utils.sol +2 -9
  71. package/codec/Readers.sol +0 -190
package/codec/Blocks.sol CHANGED
@@ -108,7 +108,12 @@ library Blocks {
108
108
  /// @return body Absolute position of the first payload byte.
109
109
  /// @return end Absolute position immediately after the payload.
110
110
  function expectKey(uint abs, bytes4 key) internal pure returns (uint body, uint end) {
111
- uint len = header(abs, key);
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);
112
117
  unchecked {
113
118
  body = abs + Sizes.Header;
114
119
  end = body + len;
@@ -196,6 +201,31 @@ library Blocks {
196
201
  }
197
202
  }
198
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
+
199
229
  /// @notice Count a run that must consume the complete region.
200
230
  /// @dev Reverts when any well-formed trailing block has a different key.
201
231
  /// @param abs Absolute start position.
@@ -350,6 +380,20 @@ library Blocks {
350
380
  }
351
381
  }
352
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
+
353
397
  // Two-word payloads
354
398
 
355
399
  /// @notice Write an AMOUNT block at `i`.
@@ -434,6 +478,24 @@ library Blocks {
434
478
 
435
479
  // Three-word payloads
436
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
+
437
499
  /// @notice Write an ALLOCATION block at `i`.
438
500
  /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
439
501
  /// @param dst Destination buffer.
@@ -697,19 +759,19 @@ library Blocks {
697
759
  /// @param dst Destination buffer.
698
760
  /// @param i Relative write position.
699
761
  /// @param cmd Command identifier.
700
- /// @param resources Packed resources.
762
+ /// @param value Native value assigned to the step.
701
763
  /// @param input Command input.
702
- function writeStep(bytes memory dst, uint i, uint cmd, uint resources, bytes memory input) internal pure {
703
- 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;
704
766
  uint key = uint32(Keys.Step);
705
767
  uint byteskey = uint32(Keys.Bytes);
706
768
  assembly ("memory-safe") {
707
769
  let p := add(add(dst, 0x20), i)
708
770
  mstore(p, or(shl(224, key), shl(192, len)))
709
771
  mstore(add(p, 0x08), cmd)
710
- mstore(add(p, 0x28), resources)
772
+ mstore(add(p, 0x28), shl(128, value))
711
773
 
712
- let q := add(p, 0x48)
774
+ let q := add(p, 0x38)
713
775
  let inputlen := mload(input)
714
776
  mstore(q, or(shl(224, byteskey), shl(192, inputlen)))
715
777
  mcopy(add(q, 0x08), add(input, 0x20), inputlen)
@@ -969,8 +1031,21 @@ library Blocks {
969
1031
  }
970
1032
 
971
1033
  /// @notice Encode a STEP block at `i`, copying its nested input from calldata.
972
- function copyStep(bytes memory dst, uint i, uint cmd, uint resources, bytes calldata input) internal pure {
973
- 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
+ }
974
1049
  }
975
1050
 
976
1051
  /// @notice Encode a CALL block at `i`, copying its nested payload from calldata.
@@ -1342,11 +1417,9 @@ library Blocks {
1342
1417
  uint head;
1343
1418
  assembly ("memory-safe") {
1344
1419
  head := calldataload(abs)
1345
- }
1346
- if (head >> 192 != Specs.Account >> 192) revert InvalidBlock();
1347
- assembly ("memory-safe") {
1348
1420
  account := calldataload(add(abs, 0x08))
1349
1421
  }
1422
+ if (head >> 192 != Specs.Account >> 192) revert InvalidBlock();
1350
1423
  }
1351
1424
 
1352
1425
  /// @notice Decode a low-level fixed-width ASSET block at `abs`.
@@ -1356,11 +1429,9 @@ library Blocks {
1356
1429
  uint head;
1357
1430
  assembly ("memory-safe") {
1358
1431
  head := calldataload(abs)
1359
- }
1360
- if (head >> 192 != Specs.Asset >> 192) revert InvalidBlock();
1361
- assembly ("memory-safe") {
1362
1432
  asset := calldataload(add(abs, 0x08))
1363
1433
  }
1434
+ if (head >> 192 != Specs.Asset >> 192) revert InvalidBlock();
1364
1435
  }
1365
1436
 
1366
1437
  /// @notice Decode a low-level fixed-width NODE block at `abs`.
@@ -1370,11 +1441,9 @@ library Blocks {
1370
1441
  uint head;
1371
1442
  assembly ("memory-safe") {
1372
1443
  head := calldataload(abs)
1373
- }
1374
- if (head >> 192 != Specs.Node >> 192) revert InvalidBlock();
1375
- assembly ("memory-safe") {
1376
1444
  node := calldataload(add(abs, 0x08))
1377
1445
  }
1446
+ if (head >> 192 != Specs.Node >> 192) revert InvalidBlock();
1378
1447
  }
1379
1448
 
1380
1449
  /// @notice Decode a low-level fixed-width STATUS block at `abs`.
@@ -1384,11 +1453,21 @@ library Blocks {
1384
1453
  uint head;
1385
1454
  assembly ("memory-safe") {
1386
1455
  head := calldataload(abs)
1456
+ code := calldataload(add(abs, 0x08))
1387
1457
  }
1388
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;
1389
1466
  assembly ("memory-safe") {
1390
- code := calldataload(add(abs, 0x08))
1467
+ head := calldataload(abs)
1468
+ amount := calldataload(add(abs, 0x08))
1391
1469
  }
1470
+ if (head >> 192 != Specs.Cashout >> 192) revert InvalidBlock();
1392
1471
  }
1393
1472
 
1394
1473
  // Two-word payloads
@@ -1401,12 +1480,10 @@ library Blocks {
1401
1480
  uint head;
1402
1481
  assembly ("memory-safe") {
1403
1482
  head := calldataload(abs)
1404
- }
1405
- if (head >> 192 != Specs.Amount >> 192) revert InvalidBlock();
1406
- assembly ("memory-safe") {
1407
1483
  asset := calldataload(add(abs, 0x08))
1408
1484
  amount := calldataload(add(abs, 0x28))
1409
1485
  }
1486
+ if (head >> 192 != Specs.Amount >> 192) revert InvalidBlock();
1410
1487
  }
1411
1488
 
1412
1489
  /// @notice Decode a low-level fixed-width BALANCE block at `abs`.
@@ -1417,13 +1494,10 @@ library Blocks {
1417
1494
  uint head;
1418
1495
  assembly ("memory-safe") {
1419
1496
  head := calldataload(abs)
1420
- }
1421
- if (head >> 192 != Specs.Balance >> 192) revert InvalidBlock();
1422
-
1423
- assembly ("memory-safe") {
1424
1497
  asset := calldataload(add(abs, 0x08))
1425
1498
  amount := calldataload(add(abs, 0x28))
1426
1499
  }
1500
+ if (head >> 192 != Specs.Balance >> 192) revert InvalidBlock();
1427
1501
  }
1428
1502
 
1429
1503
  /// @notice Decode a low-level fixed-width DEBT block at `abs`.
@@ -1434,12 +1508,10 @@ library Blocks {
1434
1508
  uint head;
1435
1509
  assembly ("memory-safe") {
1436
1510
  head := calldataload(abs)
1437
- }
1438
- if (head >> 192 != Specs.Debt >> 192) revert InvalidBlock();
1439
- assembly ("memory-safe") {
1440
1511
  liability := calldataload(add(abs, 0x08))
1441
1512
  debt := calldataload(add(abs, 0x28))
1442
1513
  }
1514
+ if (head >> 192 != Specs.Debt >> 192) revert InvalidBlock();
1443
1515
  }
1444
1516
 
1445
1517
  /// @notice Decode a low-level fixed-width ACCOUNT_ASSET block at `abs`.
@@ -1450,16 +1522,30 @@ library Blocks {
1450
1522
  uint head;
1451
1523
  assembly ("memory-safe") {
1452
1524
  head := calldataload(abs)
1453
- }
1454
- if (head >> 192 != Specs.AccountAsset >> 192) revert InvalidBlock();
1455
- assembly ("memory-safe") {
1456
1525
  account := calldataload(add(abs, 0x08))
1457
1526
  asset := calldataload(add(abs, 0x28))
1458
1527
  }
1528
+ if (head >> 192 != Specs.AccountAsset >> 192) revert InvalidBlock();
1459
1529
  }
1460
1530
 
1461
1531
  // Three-word payloads
1462
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
+
1463
1549
  /// @notice Decode a low-level fixed-width ALLOCATION block at `abs`.
1464
1550
  /// @param abs Absolute block position.
1465
1551
  /// @return host Decoded host identifier.
@@ -1469,13 +1555,11 @@ library Blocks {
1469
1555
  uint head;
1470
1556
  assembly ("memory-safe") {
1471
1557
  head := calldataload(abs)
1472
- }
1473
- if (head >> 192 != Specs.Allocation >> 192) revert InvalidBlock();
1474
- assembly ("memory-safe") {
1475
1558
  host := calldataload(add(abs, 0x08))
1476
1559
  asset := calldataload(add(abs, 0x28))
1477
1560
  amount := calldataload(add(abs, 0x48))
1478
1561
  }
1562
+ if (head >> 192 != Specs.Allocation >> 192) revert InvalidBlock();
1479
1563
  }
1480
1564
 
1481
1565
  /// @notice Decode a low-level fixed-width ALLOWANCE block at `abs`.
@@ -1487,13 +1571,11 @@ library Blocks {
1487
1571
  uint head;
1488
1572
  assembly ("memory-safe") {
1489
1573
  head := calldataload(abs)
1490
- }
1491
- if (head >> 192 != Specs.Allowance >> 192) revert InvalidBlock();
1492
- assembly ("memory-safe") {
1493
1574
  host := calldataload(add(abs, 0x08))
1494
1575
  asset := calldataload(add(abs, 0x28))
1495
1576
  amount := calldataload(add(abs, 0x48))
1496
1577
  }
1578
+ if (head >> 192 != Specs.Allowance >> 192) revert InvalidBlock();
1497
1579
  }
1498
1580
 
1499
1581
  /// @notice Decode a low-level fixed-width CUSTODY block at `abs`.
@@ -1505,13 +1587,11 @@ library Blocks {
1505
1587
  uint head;
1506
1588
  assembly ("memory-safe") {
1507
1589
  head := calldataload(abs)
1508
- }
1509
- if (head >> 192 != Specs.Custody >> 192) revert InvalidBlock();
1510
- assembly ("memory-safe") {
1511
1590
  host := calldataload(add(abs, 0x08))
1512
1591
  asset := calldataload(add(abs, 0x28))
1513
1592
  amount := calldataload(add(abs, 0x48))
1514
1593
  }
1594
+ if (head >> 192 != Specs.Custody >> 192) revert InvalidBlock();
1515
1595
  }
1516
1596
 
1517
1597
  /// @notice Decode a low-level fixed-width ACCOUNT_AMOUNT block at `abs`.
@@ -1523,13 +1603,11 @@ library Blocks {
1523
1603
  uint head;
1524
1604
  assembly ("memory-safe") {
1525
1605
  head := calldataload(abs)
1526
- }
1527
- if (head >> 192 != Specs.AccountAmount >> 192) revert InvalidBlock();
1528
- assembly ("memory-safe") {
1529
1606
  account := calldataload(add(abs, 0x08))
1530
1607
  asset := calldataload(add(abs, 0x28))
1531
1608
  amount := calldataload(add(abs, 0x48))
1532
1609
  }
1610
+ if (head >> 192 != Specs.AccountAmount >> 192) revert InvalidBlock();
1533
1611
  }
1534
1612
 
1535
1613
  /// @notice Decode a low-level fixed-width HOST_AMOUNT block at `abs`.
@@ -1541,13 +1619,11 @@ library Blocks {
1541
1619
  uint head;
1542
1620
  assembly ("memory-safe") {
1543
1621
  head := calldataload(abs)
1544
- }
1545
- if (head >> 192 != Specs.HostAmount >> 192) revert InvalidBlock();
1546
- assembly ("memory-safe") {
1547
1622
  host := calldataload(add(abs, 0x08))
1548
1623
  asset := calldataload(add(abs, 0x28))
1549
1624
  amount := calldataload(add(abs, 0x48))
1550
1625
  }
1626
+ if (head >> 192 != Specs.HostAmount >> 192) revert InvalidBlock();
1551
1627
  }
1552
1628
 
1553
1629
  /// @notice Decode a low-level fixed-width HOST_ACCOUNT_ASSET block at `abs`.
@@ -1559,13 +1635,11 @@ library Blocks {
1559
1635
  uint head;
1560
1636
  assembly ("memory-safe") {
1561
1637
  head := calldataload(abs)
1562
- }
1563
- if (head >> 192 != Specs.HostAccountAsset >> 192) revert InvalidBlock();
1564
- assembly ("memory-safe") {
1565
1638
  host := calldataload(add(abs, 0x08))
1566
1639
  account := calldataload(add(abs, 0x28))
1567
1640
  asset := calldataload(add(abs, 0x48))
1568
1641
  }
1642
+ if (head >> 192 != Specs.HostAccountAsset >> 192) revert InvalidBlock();
1569
1643
  }
1570
1644
 
1571
1645
  // Four-word payloads
@@ -1582,14 +1656,12 @@ library Blocks {
1582
1656
  uint head;
1583
1657
  assembly ("memory-safe") {
1584
1658
  head := calldataload(abs)
1585
- }
1586
- if (head >> 192 != Specs.Position >> 192) revert InvalidBlock();
1587
- assembly ("memory-safe") {
1588
1659
  asset := calldataload(add(abs, 0x08))
1589
1660
  amount := calldataload(add(abs, 0x28))
1590
1661
  liability := calldataload(add(abs, 0x48))
1591
1662
  debt := calldataload(add(abs, 0x68))
1592
1663
  }
1664
+ if (head >> 192 != Specs.Position >> 192) revert InvalidBlock();
1593
1665
  }
1594
1666
 
1595
1667
  /// @notice Decode a low-level fixed-width HOST_ASSET block at `abs`.
@@ -1600,12 +1672,10 @@ library Blocks {
1600
1672
  uint head;
1601
1673
  assembly ("memory-safe") {
1602
1674
  head := calldataload(abs)
1603
- }
1604
- if (head >> 192 != Specs.HostAsset >> 192) revert InvalidBlock();
1605
- assembly ("memory-safe") {
1606
1675
  host := calldataload(add(abs, 0x08))
1607
1676
  asset := calldataload(add(abs, 0x28))
1608
1677
  }
1678
+ if (head >> 192 != Specs.HostAsset >> 192) revert InvalidBlock();
1609
1679
  }
1610
1680
 
1611
1681
  /// @notice Decode a low-level fixed-width TRANSACTION block at `abs`.
@@ -1618,14 +1688,12 @@ library Blocks {
1618
1688
  uint head;
1619
1689
  assembly ("memory-safe") {
1620
1690
  head := calldataload(abs)
1621
- }
1622
- if (head >> 192 != Specs.Transaction >> 192) revert InvalidBlock();
1623
- assembly ("memory-safe") {
1624
1691
  from := calldataload(add(abs, 0x08))
1625
1692
  to := calldataload(add(abs, 0x28))
1626
1693
  asset := calldataload(add(abs, 0x48))
1627
1694
  amount := calldataload(add(abs, 0x68))
1628
1695
  }
1696
+ if (head >> 192 != Specs.Transaction >> 192) revert InvalidBlock();
1629
1697
  }
1630
1698
 
1631
1699
  /// @notice Decode a low-level fixed-width HOST_ACCOUNT_AMOUNT block at `abs`.
@@ -1640,14 +1708,12 @@ library Blocks {
1640
1708
  uint head;
1641
1709
  assembly ("memory-safe") {
1642
1710
  head := calldataload(abs)
1643
- }
1644
- if (head >> 192 != Specs.HostAccountAmount >> 192) revert InvalidBlock();
1645
- assembly ("memory-safe") {
1646
1711
  host := calldataload(add(abs, 0x08))
1647
1712
  account := calldataload(add(abs, 0x28))
1648
1713
  asset := calldataload(add(abs, 0x48))
1649
1714
  amount := calldataload(add(abs, 0x68))
1650
1715
  }
1716
+ if (head >> 192 != Specs.HostAccountAmount >> 192) revert InvalidBlock();
1651
1717
  }
1652
1718
 
1653
1719
  // Dynamic leaf blocks
@@ -1657,7 +1723,16 @@ library Blocks {
1657
1723
  /// @return value Decoded list payload.
1658
1724
  /// @return end Absolute position after the block.
1659
1725
  function unpackList(uint abs) internal pure returns (bytes calldata value, uint end) {
1660
- 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;
1661
1736
  }
1662
1737
 
1663
1738
  /// @notice Decode one EVM payload and its absolute end position.
@@ -1665,7 +1740,16 @@ library Blocks {
1665
1740
  /// @return value Decoded EVM payload.
1666
1741
  /// @return end Absolute position after the block.
1667
1742
  function unpackEvm(uint abs) internal pure returns (bytes calldata value, uint end) {
1668
- 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;
1669
1753
  }
1670
1754
 
1671
1755
  /// @notice Decode one BYTES payload and its absolute end position.
@@ -1673,7 +1757,16 @@ library Blocks {
1673
1757
  /// @return value Decoded byte payload.
1674
1758
  /// @return end Absolute position after the block.
1675
1759
  function unpackBytes(uint abs) internal pure returns (bytes calldata value, uint end) {
1676
- 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;
1677
1770
  }
1678
1771
 
1679
1772
  /// @notice Decode one STRING payload and its absolute end position.
@@ -1681,20 +1774,15 @@ library Blocks {
1681
1774
  /// @return value Decoded string bytes.
1682
1775
  /// @return end Absolute position after the block.
1683
1776
  function unpackString(uint abs) internal pure returns (bytes calldata value, uint end) {
1684
- return unpackRaw(abs, Keys.String);
1685
- }
1686
-
1687
- /// @dev Decode a dynamic leaf block after validating its key.
1688
- /// @param abs Absolute block position.
1689
- /// @param expected Expected block key.
1690
- /// @return value Decoded payload.
1691
- /// @return end Absolute position after the block.
1692
- function unpackRaw(uint abs, bytes4 expected) private pure returns (bytes calldata value, uint end) {
1693
- uint len = header(abs, expected);
1777
+ uint head;
1778
+ uint len;
1694
1779
  assembly ("memory-safe") {
1780
+ head := calldataload(abs)
1781
+ len := and(shr(192, head), 0xffffffff)
1695
1782
  value.offset := add(abs, 0x08)
1696
1783
  value.length := len
1697
1784
  }
1785
+ if (uint32(head >> 224) != uint32(Keys.String)) revert InvalidBlock();
1698
1786
  end = abs + Sizes.Header + len;
1699
1787
  }
1700
1788
 
@@ -1743,19 +1831,19 @@ library Blocks {
1743
1831
  /// @notice Decode one STEP block and its nested input.
1744
1832
  /// @param abs Absolute block position.
1745
1833
  /// @return cmd Decoded command identifier.
1746
- /// @return resources Decoded packed resources.
1834
+ /// @return value Decoded native value.
1747
1835
  /// @return input Decoded command input.
1748
1836
  /// @return end Absolute position after the block.
1749
1837
  function unpackStep(
1750
1838
  uint abs
1751
- ) 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) {
1752
1840
  uint limit;
1753
1841
  (abs, limit) = expectKey(abs, Keys.Step);
1754
1842
  assembly ("memory-safe") {
1755
1843
  cmd := calldataload(abs)
1756
- resources := calldataload(add(abs, 0x20))
1844
+ value := shr(128, calldataload(add(abs, 0x20)))
1757
1845
  }
1758
- (input, end) = unpackBytes(abs + 64);
1846
+ (input, end) = unpackBytes(abs + 48);
1759
1847
  if (end != limit) revert InvalidBlock();
1760
1848
  }
1761
1849
 
@@ -2021,6 +2109,24 @@ library Blocks {
2021
2109
 
2022
2110
  // Fixed-width factories
2023
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
+
2024
2130
  /// @notice Encode an AMOUNT block.
2025
2131
  /// @param asset Asset identifier.
2026
2132
  /// @param amount Token amount.
@@ -2094,20 +2200,20 @@ library Blocks {
2094
2200
 
2095
2201
  /// @notice Encode a STEP block.
2096
2202
  /// @param cmd Command identifier.
2097
- /// @param resources Packed resources assigned to the step.
2203
+ /// @param value Native value assigned to the step.
2098
2204
  /// @param input Raw nested input payload.
2099
- /// @return value Encoded STEP block bytes.
2100
- function createStep(uint cmd, uint resources, bytes memory input) internal pure returns (bytes memory value) {
2101
- uint len = max32(Sizes.B64 + Sizes.Header + input.length);
2102
- value = allocate(len);
2103
- 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);
2104
2210
  }
2105
2211
 
2106
2212
  /// @notice Encode a STEP block by copying its nested input from calldata.
2107
- function createStepCopy(uint cmd, uint resources, bytes calldata input) internal pure returns (bytes memory value) {
2108
- uint len = max32(Sizes.B64 + Sizes.Header + input.length);
2109
- value = allocate(len);
2110
- 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);
2111
2217
  }
2112
2218
 
2113
2219
  /// @notice Encode a CALL block.
@@ -2216,3 +2322,85 @@ library Blocks {
2216
2322
  copyRecover(value, 0, handler, resources, recoverykey, witness);
2217
2323
  }
2218
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
+ }