@rootzero/contracts 0.9.3 → 0.9.5

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 (49) hide show
  1. package/Commands.sol +3 -2
  2. package/Core.sol +4 -3
  3. package/Cursors.sol +1 -1
  4. package/Events.sol +2 -3
  5. package/README.md +18 -24
  6. package/blocks/Cursors.sol +316 -337
  7. package/blocks/Keys.sol +40 -57
  8. package/blocks/Schema.sol +57 -208
  9. package/blocks/Writers.sol +376 -135
  10. package/commands/Base.sol +6 -48
  11. package/commands/Burn.sol +2 -2
  12. package/commands/Credit.sol +3 -3
  13. package/commands/Debit.sol +3 -2
  14. package/commands/Deposit.sol +11 -8
  15. package/commands/Provision.sol +11 -8
  16. package/commands/Transfer.sol +2 -2
  17. package/commands/Withdraw.sol +3 -3
  18. package/commands/admin/AllowAssets.sol +1 -1
  19. package/commands/admin/Allowance.sol +1 -1
  20. package/commands/admin/Authorize.sol +1 -1
  21. package/commands/admin/DenyAssets.sol +1 -1
  22. package/commands/admin/Execute.sol +7 -6
  23. package/commands/admin/Unauthorize.sol +1 -1
  24. package/core/Access.sol +11 -0
  25. package/core/Calls.sol +5 -5
  26. package/core/Context.sol +3 -4
  27. package/core/Host.sol +25 -20
  28. package/core/Payable.sol +57 -0
  29. package/core/Pipeline.sol +55 -0
  30. package/docs/Schema.md +196 -0
  31. package/events/Command.sol +1 -2
  32. package/events/Introduction.sol +22 -0
  33. package/events/{Piped.sol → Rooted.sol} +3 -3
  34. package/package.json +2 -2
  35. package/peer/AllowAssets.sol +1 -1
  36. package/peer/Allowance.sol +1 -1
  37. package/peer/BalancePull.sol +1 -1
  38. package/peer/DenyAssets.sol +1 -1
  39. package/peer/Pipe.sol +38 -0
  40. package/peer/Settle.sol +1 -1
  41. package/queries/Assets.sol +4 -3
  42. package/queries/Balances.sol +2 -1
  43. package/queries/Positions.sol +12 -12
  44. package/utils/Value.sol +8 -14
  45. package/commands/Pipe.sol +0 -67
  46. package/docs/GETTING_STARTED.md +0 -294
  47. package/events/Governed.sol +0 -21
  48. package/events/Host.sol +0 -22
  49. package/interfaces/IHostDiscovery.sol +0 -16
@@ -12,11 +12,24 @@ struct Writer {
12
12
  uint i;
13
13
  /// @dev Logical buffer capacity in bytes; writers should not advance past this limit.
14
14
  uint end;
15
+ /// @dev Whether append helpers may expand the backing buffer when more capacity is needed.
16
+ bool growable;
15
17
  /// @dev Destination buffer. Physical capacity may be padded up to a full 32-byte word;
16
18
  /// final length is set to `i` by `finish`.
17
19
  bytes dst;
18
20
  }
19
21
 
22
+ /// @title Hints
23
+ /// @notice Initial per-block capacity estimates for growable writers.
24
+ library Hints {
25
+ uint constant Any = 128;
26
+ uint constant Bytes = 128;
27
+ uint constant Step = 256;
28
+ uint constant Call = 256;
29
+ uint constant Context = 512;
30
+ uint constant Relay = 640;
31
+ }
32
+
20
33
  /// @title Writers
21
34
  /// @notice Response block stream builder for the rootzero protocol.
22
35
  /// Allocates a fixed-size memory buffer up front and writes binary-encoded
@@ -47,7 +60,15 @@ library Writers {
47
60
  // Extra 32 bytes ensure mstore in write/append32 never reaches past allocated memory,
48
61
  // even when a sub-word packed write starts within the last 31 bytes of the logical region.
49
62
  uint padded = ((len + 31) & ~uint(31)) + 32;
50
- writer = Writer({i: 0, end: len, dst: new bytes(padded)});
63
+ writer = Writer({i: 0, end: len, growable: false, dst: new bytes(padded)});
64
+ }
65
+
66
+ /// @notice Allocate a growable writer with an initial logical byte capacity.
67
+ /// @param hint Initial logical byte capacity to allocate.
68
+ /// @return writer Freshly allocated growable writer positioned at index 0.
69
+ function dynamic(uint hint) internal pure returns (Writer memory writer) {
70
+ writer = alloc(hint);
71
+ writer.growable = true;
51
72
  }
52
73
 
53
74
  /// @notice Core allocation routine used by all counted `alloc*` helpers.
@@ -60,6 +81,16 @@ library Writers {
60
81
  writer = alloc(count * blockLen);
61
82
  }
62
83
 
84
+ /// @notice Core allocation routine used by counted growable `alloc*` helpers.
85
+ /// Computes `count * hint` and allocates an expandable writer with that initial capacity.
86
+ /// @param count Number of output blocks.
87
+ /// @param hint Initial logical byte capacity per output block.
88
+ /// @return writer Allocated growable writer.
89
+ function allocFromHint(uint count, uint hint) internal pure returns (Writer memory writer) {
90
+ if (count == 0) revert EmptyRequest();
91
+ writer = dynamic(count * hint);
92
+ }
93
+
63
94
  /// @notice Allocate a writer sized for exactly `count` dynamic blocks with a shared payload length.
64
95
  /// Each block reserves `Sizes.Header + payloadLen` bytes.
65
96
  /// @param count Number of blocks to allocate space for.
@@ -69,6 +100,22 @@ library Writers {
69
100
  return allocFromCount(count, Sizes.Header + payloadLen);
70
101
  }
71
102
 
103
+ /// @notice Allocate a writer for `count` variable-sized blocks using a per-block capacity hint.
104
+ /// @dev The backing buffer expands automatically if encoded blocks exceed the initial hint.
105
+ /// @param count Number of blocks to allocate space for.
106
+ /// @return writer Allocated growable writer.
107
+ function allocAny(uint count) internal pure returns (Writer memory writer) {
108
+ return allocFromHint(count, Hints.Any);
109
+ }
110
+
111
+ /// @notice Allocate a writer for `count` BYTES blocks using a per-block capacity hint.
112
+ /// @dev The backing buffer expands automatically if encoded bytes blocks exceed the initial hint.
113
+ /// @param count Number of bytes blocks to allocate space for.
114
+ /// @return writer Allocated growable writer.
115
+ function allocBytes(uint count) internal pure returns (Writer memory writer) {
116
+ return allocFromHint(count, Hints.Bytes);
117
+ }
118
+
72
119
  /// @notice Allocate a writer sized for exactly `count` 32-byte-payload blocks.
73
120
  /// @param count Number of blocks to allocate space for.
74
121
  /// @return writer Allocated writer.
@@ -108,7 +155,7 @@ library Writers {
108
155
  /// @param count Number of blocks to allocate space for.
109
156
  /// @return writer Allocated writer.
110
157
  function allocStatuses(uint count) internal pure returns (Writer memory writer) {
111
- return alloc32s(count);
158
+ return allocFromCount(count, Sizes.Status);
112
159
  }
113
160
 
114
161
  /// @notice Allocate a writer sized for exactly `count` ASSET blocks.
@@ -153,6 +200,38 @@ library Writers {
153
200
  return alloc160s(count);
154
201
  }
155
202
 
203
+ /// @notice Allocate a writer for `count` STEP blocks using a per-block capacity hint.
204
+ /// @dev The backing buffer expands automatically if encoded steps exceed the initial hint.
205
+ /// @param count Number of step blocks to allocate space for.
206
+ /// @return writer Allocated growable writer.
207
+ function allocSteps(uint count) internal pure returns (Writer memory writer) {
208
+ return allocFromHint(count, Hints.Step);
209
+ }
210
+
211
+ /// @notice Allocate a writer for `count` CALL blocks using a per-block capacity hint.
212
+ /// @dev The backing buffer expands automatically if encoded calls exceed the initial hint.
213
+ /// @param count Number of call blocks to allocate space for.
214
+ /// @return writer Allocated growable writer.
215
+ function allocCalls(uint count) internal pure returns (Writer memory writer) {
216
+ return allocFromHint(count, Hints.Call);
217
+ }
218
+
219
+ /// @notice Allocate a writer for `count` CONTEXT blocks using a per-block capacity hint.
220
+ /// @dev The backing buffer expands automatically if encoded contexts exceed the initial hint.
221
+ /// @param count Number of context blocks to allocate space for.
222
+ /// @return writer Allocated growable writer.
223
+ function allocContexts(uint count) internal pure returns (Writer memory writer) {
224
+ return allocFromHint(count, Hints.Context);
225
+ }
226
+
227
+ /// @notice Allocate a writer for `count` RELAY blocks using a per-block capacity hint.
228
+ /// @dev The backing buffer expands automatically if encoded relays exceed the initial hint.
229
+ /// @param count Number of relay blocks to allocate space for.
230
+ /// @return writer Allocated growable writer.
231
+ function allocRelays(uint count) internal pure returns (Writer memory writer) {
232
+ return allocFromHint(count, Hints.Relay);
233
+ }
234
+
156
235
  // -------------------------------------------------------------------------
157
236
  // Fixed-width write helpers
158
237
  // -------------------------------------------------------------------------
@@ -172,14 +251,6 @@ library Writers {
172
251
  }
173
252
  }
174
253
 
175
- /// @notice Commit a logical writer advance after a low-level write.
176
- /// @dev Low-level write helpers validate the padded backing buffer. This
177
- /// enforces the caller-requested logical capacity recorded in `end`.
178
- function commit(Writer memory writer, uint next) private pure {
179
- if (next > writer.end) revert WriterOverflow();
180
- writer.i = next;
181
- }
182
-
183
254
  /// @notice Write raw bytes directly into `dst` at byte offset `i` without a block header.
184
255
  /// @param dst Destination buffer.
185
256
  /// @param i Write offset within `dst`.
@@ -431,57 +502,160 @@ library Writers {
431
502
  }
432
503
  }
433
504
 
434
- /// @notice Write a dynamic block with a fixed 32-byte head word.
435
- /// @param dst Destination buffer; must have at least `i + Sizes.B32 + tail.length` bytes.
505
+ /// @notice Write a block with a 32-byte head and two nested BYTES payloads.
506
+ /// @param dst Destination buffer; must have at least `i + Sizes.B32 + 2 * Sizes.Header + b.length + c.length` bytes.
436
507
  /// @param i Write offset within `dst`.
437
- /// @param key Block type key.
508
+ /// @param key Block key.
438
509
  /// @param a Fixed head word.
439
- /// @param tail Dynamic payload bytes appended after the head.
510
+ /// @param b First raw nested payload.
511
+ /// @param c Second raw nested payload.
440
512
  /// @return next Byte offset immediately after the written block.
441
- function writeBlockHead32(
513
+ function writeBlock32BytesBytes(
442
514
  bytes memory dst,
443
515
  uint i,
444
516
  bytes4 key,
445
517
  bytes32 a,
446
- bytes memory tail
518
+ bytes memory b,
519
+ bytes memory c
447
520
  ) internal pure returns (uint next) {
448
- uint len = 32 + tail.length;
521
+ uint bLen = b.length;
522
+ uint len = 32 + 2 * Sizes.Header + bLen + c.length;
449
523
  next = i + Sizes.Header + len;
450
- if (i + Sizes.B32 + tail.length > dst.length) revert WriterOverflow();
451
- uint p = writeHeader(dst, i, key, uint32(max32(len)));
452
- assembly ("memory-safe") {
453
- mstore(add(p, 0x08), a)
454
- mcopy(add(p, 0x28), add(tail, 0x20), mload(tail))
524
+ if (next > dst.length) revert WriterOverflow();
525
+
526
+ {
527
+ uint p = writeHeader(dst, i, key, uint32(max32(len)));
528
+ assembly ("memory-safe") {
529
+ mstore(add(p, 0x08), a)
530
+ }
531
+ }
532
+
533
+ {
534
+ uint q = writeHeader(dst, i + Sizes.Header + 32, Keys.Bytes, uint32(max32(bLen)));
535
+ assembly ("memory-safe") {
536
+ mcopy(add(q, 0x08), add(b, 0x20), mload(b))
537
+ }
538
+ }
539
+
540
+ {
541
+ uint r = writeHeader(dst, i + Sizes.Header + 32 + Sizes.Header + bLen, Keys.Bytes, uint32(max32(c.length)));
542
+ assembly ("memory-safe") {
543
+ mcopy(add(r, 0x08), add(c, 0x20), mload(c))
544
+ }
455
545
  }
456
546
  }
457
547
 
458
- /// @notice Write a dynamic block with a fixed 64-byte head.
459
- /// @param dst Destination buffer; must have at least `i + Sizes.B64 + tail.length` bytes.
548
+ /// @notice Write a block with a 64-byte head and two nested BYTES payloads.
549
+ /// @param dst Destination buffer; must have at least `i + Sizes.B64 + 2 * Sizes.Header + c.length + d.length` bytes.
460
550
  /// @param i Write offset within `dst`.
461
- /// @param key Block type key.
462
- /// @param a First fixed head word.
463
- /// @param b Second fixed head word.
464
- /// @param tail Dynamic payload bytes appended after the head.
551
+ /// @param key Block key.
552
+ /// @param a First head word.
553
+ /// @param b Second head word.
554
+ /// @param c First raw nested payload.
555
+ /// @param d Second raw nested payload.
465
556
  /// @return next Byte offset immediately after the written block.
466
- function writeBlockHead64(
557
+ function writeBlock64BytesBytes(
467
558
  bytes memory dst,
468
559
  uint i,
469
560
  bytes4 key,
470
561
  bytes32 a,
471
562
  bytes32 b,
472
- bytes memory tail
563
+ bytes memory c,
564
+ bytes memory d
473
565
  ) internal pure returns (uint next) {
474
- uint len = 64 + tail.length;
566
+ uint cLen = c.length;
567
+ uint len = 64 + 2 * Sizes.Header + cLen + d.length;
475
568
  next = i + Sizes.Header + len;
476
- if (i + Sizes.B64 + tail.length > dst.length) revert WriterOverflow();
477
- uint p = writeHeader(dst, i, key, uint32(max32(len)));
478
- assembly ("memory-safe") {
479
- mstore(add(p, 0x08), a)
480
- mstore(add(p, 0x28), b)
481
- mcopy(add(p, 0x48), add(tail, 0x20), mload(tail))
569
+ if (next > dst.length) revert WriterOverflow();
570
+
571
+ {
572
+ uint p = writeHeader(dst, i, key, uint32(max32(len)));
573
+ assembly ("memory-safe") {
574
+ mstore(add(p, 0x08), a)
575
+ mstore(add(p, 0x28), b)
576
+ }
577
+ }
578
+
579
+ {
580
+ uint q = writeHeader(dst, i + Sizes.Header + 64, Keys.Bytes, uint32(max32(cLen)));
581
+ assembly ("memory-safe") {
582
+ mcopy(add(q, 0x08), add(c, 0x20), mload(c))
583
+ }
584
+ }
585
+
586
+ {
587
+ uint r = writeHeader(dst, i + Sizes.Header + 64 + Sizes.Header + cLen, Keys.Bytes, uint32(max32(d.length)));
588
+ assembly ("memory-safe") {
589
+ mcopy(add(r, 0x08), add(d, 0x20), mload(d))
590
+ }
482
591
  }
483
592
  }
484
593
 
594
+ /// @notice Write a block with a 64-byte head and nested BYTES payload.
595
+ /// @param dst Destination buffer; must have at least `i + Sizes.B64 + Sizes.Header + c.length` bytes.
596
+ /// @param i Write offset within `dst`.
597
+ /// @param key Block key.
598
+ /// @param a First head word.
599
+ /// @param b Second head word.
600
+ /// @param c Raw nested payload.
601
+ /// @return next Byte offset immediately after the written block.
602
+ function writeBlock64Bytes(
603
+ bytes memory dst,
604
+ uint i,
605
+ bytes4 key,
606
+ bytes32 a,
607
+ bytes32 b,
608
+ bytes memory c
609
+ ) internal pure returns (uint next) {
610
+ uint cLen = c.length;
611
+ uint len = 64 + Sizes.Header + cLen;
612
+ next = i + Sizes.Header + len;
613
+ if (next > dst.length) revert WriterOverflow();
614
+
615
+ {
616
+ uint p = writeHeader(dst, i, key, uint32(max32(len)));
617
+ assembly ("memory-safe") {
618
+ mstore(add(p, 0x08), a)
619
+ mstore(add(p, 0x28), b)
620
+ }
621
+ }
622
+
623
+ {
624
+ uint q = writeHeader(dst, i + Sizes.Header + 64, Keys.Bytes, uint32(max32(cLen)));
625
+ assembly ("memory-safe") {
626
+ mcopy(add(q, 0x08), add(c, 0x20), mload(c))
627
+ }
628
+ }
629
+ }
630
+
631
+ /// @notice Reserve physical write space and advance the logical writer position.
632
+ /// Fixed writers may use padded backing space but cannot advance past logical capacity;
633
+ /// growable writers expand when `touch` exceeds current capacity.
634
+ /// @return i Original write offset.
635
+ function reserve(Writer memory writer, uint next, uint touch) private pure returns (uint i) {
636
+ i = writer.i;
637
+ if (writer.growable) {
638
+ if (touch > writer.end) {
639
+ uint end = writer.end == 0 ? 64 : writer.end * 2;
640
+ while (end < touch) {
641
+ end *= 2;
642
+ }
643
+
644
+ uint padded = ((end + 31) & ~uint(31)) + 32;
645
+ bytes memory src = writer.dst;
646
+ bytes memory dst = new bytes(padded);
647
+ assembly ("memory-safe") {
648
+ mcopy(add(dst, 0x20), add(src, 0x20), i)
649
+ }
650
+ writer.end = end;
651
+ writer.dst = dst;
652
+ }
653
+ } else if (touch > writer.dst.length) revert WriterOverflow();
654
+
655
+ if (next > writer.end) revert WriterOverflow();
656
+ writer.i = next;
657
+ }
658
+
485
659
  // -------------------------------------------------------------------------
486
660
  // Append helpers
487
661
  // -------------------------------------------------------------------------
@@ -490,7 +664,9 @@ library Writers {
490
664
  /// @param writer Destination writer; `i` is advanced by `data.length`.
491
665
  /// @param data Bytes to append.
492
666
  function append(Writer memory writer, bytes memory data) internal pure {
493
- commit(writer, write(writer.dst, writer.i, data));
667
+ uint next = writer.i + data.length;
668
+ uint i = reserve(writer, next, next);
669
+ write(writer.dst, i, data);
494
670
  }
495
671
 
496
672
  /// @notice Append a raw 32-byte word without a block header.
@@ -498,7 +674,10 @@ library Writers {
498
674
  /// @param value Word to append.
499
675
  /// @param keep Number of bytes to keep from the word (1..32).
500
676
  function append32(Writer memory writer, bytes32 value, uint keep) internal pure {
501
- commit(writer, write32(writer.dst, writer.i, value, keep));
677
+ uint i = writer.i;
678
+ uint next = i + keep;
679
+ i = reserve(writer, next, i + 32);
680
+ write32(writer.dst, i, value, keep);
502
681
  }
503
682
 
504
683
  /// @notice Append two raw 32-byte words without a block header.
@@ -507,7 +686,10 @@ library Writers {
507
686
  /// @param b Second word to append.
508
687
  /// @param keep Number of bytes to keep from the final word (1..32).
509
688
  function append64(Writer memory writer, bytes32 a, bytes32 b, uint keep) internal pure {
510
- commit(writer, write64(writer.dst, writer.i, a, b, keep));
689
+ uint i = writer.i;
690
+ uint next = i + 32 + keep;
691
+ i = reserve(writer, next, i + 64);
692
+ write64(writer.dst, i, a, b, keep);
511
693
  }
512
694
 
513
695
  /// @notice Append three raw 32-byte words without a block header.
@@ -517,7 +699,10 @@ library Writers {
517
699
  /// @param c Third word to append.
518
700
  /// @param keep Number of bytes to keep from the final word (1..32).
519
701
  function append96(Writer memory writer, bytes32 a, bytes32 b, bytes32 c, uint keep) internal pure {
520
- commit(writer, write96(writer.dst, writer.i, a, b, c, keep));
702
+ uint i = writer.i;
703
+ uint next = i + 64 + keep;
704
+ i = reserve(writer, next, i + 96);
705
+ write96(writer.dst, i, a, b, c, keep);
521
706
  }
522
707
 
523
708
  /// @notice Append a dynamic block.
@@ -525,7 +710,9 @@ library Writers {
525
710
  /// @param key Block type key.
526
711
  /// @param data Dynamic payload bytes.
527
712
  function appendBlock(Writer memory writer, bytes4 key, bytes memory data) internal pure {
528
- commit(writer, writeBlock(writer.dst, writer.i, key, data));
713
+ uint next = writer.i + Sizes.Header + data.length;
714
+ uint i = reserve(writer, next, next);
715
+ writeBlock(writer.dst, i, key, data);
529
716
  }
530
717
 
531
718
  /// @notice Append a fixed-width 32-byte-payload block.
@@ -534,7 +721,10 @@ library Writers {
534
721
  /// @param a First payload word.
535
722
  /// @param keep Number of bytes to keep from the final payload word (1..32).
536
723
  function appendBlock32(Writer memory writer, bytes4 key, bytes32 a, uint keep) internal pure {
537
- commit(writer, writeBlock32(writer.dst, writer.i, key, a, keep));
724
+ uint i = writer.i;
725
+ uint next = i + Sizes.Header + keep;
726
+ i = reserve(writer, next, i + Sizes.B32);
727
+ writeBlock32(writer.dst, i, key, a, keep);
538
728
  }
539
729
 
540
730
  /// @notice Append a fixed-width 64-byte-payload block.
@@ -544,7 +734,10 @@ library Writers {
544
734
  /// @param b Second payload word.
545
735
  /// @param keep Number of bytes to keep from the final payload word (1..32).
546
736
  function appendBlock64(Writer memory writer, bytes4 key, bytes32 a, bytes32 b, uint keep) internal pure {
547
- commit(writer, writeBlock64(writer.dst, writer.i, key, a, b, keep));
737
+ uint i = writer.i;
738
+ uint next = i + Sizes.Header + 32 + keep;
739
+ i = reserve(writer, next, i + Sizes.B64);
740
+ writeBlock64(writer.dst, i, key, a, b, keep);
548
741
  }
549
742
 
550
743
  /// @notice Append a fixed-width 96-byte-payload block.
@@ -555,7 +748,10 @@ library Writers {
555
748
  /// @param c Third payload word.
556
749
  /// @param keep Number of bytes to keep from the final payload word (1..32).
557
750
  function appendBlock96(Writer memory writer, bytes4 key, bytes32 a, bytes32 b, bytes32 c, uint keep) internal pure {
558
- commit(writer, writeBlock96(writer.dst, writer.i, key, a, b, c, keep));
751
+ uint i = writer.i;
752
+ uint next = i + Sizes.Header + 64 + keep;
753
+ i = reserve(writer, next, i + Sizes.B96);
754
+ writeBlock96(writer.dst, i, key, a, b, c, keep);
559
755
  }
560
756
 
561
757
  /// @notice Append a fixed-width 128-byte-payload block.
@@ -575,7 +771,10 @@ library Writers {
575
771
  bytes32 d,
576
772
  uint keep
577
773
  ) internal pure {
578
- commit(writer, writeBlock128(writer.dst, writer.i, key, a, b, c, d, keep));
774
+ uint i = writer.i;
775
+ uint next = i + Sizes.Header + 96 + keep;
776
+ i = reserve(writer, next, i + Sizes.B128);
777
+ writeBlock128(writer.dst, i, key, a, b, c, d, keep);
579
778
  }
580
779
 
581
780
  /// @notice Append a fixed-width 160-byte-payload block.
@@ -597,39 +796,133 @@ library Writers {
597
796
  bytes32 e,
598
797
  uint keep
599
798
  ) internal pure {
600
- commit(writer, writeBlock160(writer.dst, writer.i, key, a, b, c, d, e, keep));
799
+ uint i = writer.i;
800
+ uint next = i + Sizes.Header + 128 + keep;
801
+ i = reserve(writer, next, i + Sizes.B160);
802
+ writeBlock160(writer.dst, i, key, a, b, c, d, e, keep);
601
803
  }
602
804
 
603
- /// @notice Append a dynamic block with a fixed 32-byte head word.
604
- /// @param writer Destination writer; `i` is advanced by `Sizes.B32 + tail.length`.
605
- /// @param key Block type key.
805
+ /// @notice Append a block with a 32-byte head and two nested BYTES payloads.
806
+ /// @param writer Destination writer; `i` is advanced by the encoded block length.
807
+ /// @param key Block key.
606
808
  /// @param a Fixed head word.
607
- /// @param tail Dynamic payload bytes appended after the head.
608
- function appendBlockHead32(Writer memory writer, bytes4 key, bytes32 a, bytes memory tail) internal pure {
609
- commit(writer, writeBlockHead32(writer.dst, writer.i, key, a, tail));
809
+ /// @param b First raw nested payload.
810
+ /// @param c Second raw nested payload.
811
+ function appendBlock32BytesBytes(
812
+ Writer memory writer,
813
+ bytes4 key,
814
+ bytes32 a,
815
+ bytes memory b,
816
+ bytes memory c
817
+ ) internal pure {
818
+ uint i = writer.i;
819
+ uint next = i + Sizes.B32 + 2 * Sizes.Header + b.length + c.length;
820
+ i = reserve(writer, next, next);
821
+ writeBlock32BytesBytes(writer.dst, i, key, a, b, c);
610
822
  }
611
823
 
612
- /// @notice Append a dynamic block with a fixed 64-byte head.
613
- /// @param writer Destination writer; `i` is advanced by `Sizes.B64 + tail.length`.
614
- /// @param key Block type key.
615
- /// @param a First fixed head word.
616
- /// @param b Second fixed head word.
617
- /// @param tail Dynamic payload bytes appended after the head.
618
- function appendBlockHead64(
824
+ /// @notice Append a block with a 64-byte head and two nested BYTES payloads.
825
+ /// @param writer Destination writer; `i` is advanced by the encoded block length.
826
+ /// @param key Block key.
827
+ /// @param a First head word.
828
+ /// @param b Second head word.
829
+ /// @param c First raw nested payload.
830
+ /// @param d Second raw nested payload.
831
+ function appendBlock64BytesBytes(
619
832
  Writer memory writer,
620
833
  bytes4 key,
621
834
  bytes32 a,
622
835
  bytes32 b,
623
- bytes memory tail
836
+ bytes memory c,
837
+ bytes memory d
838
+ ) internal pure {
839
+ uint i = writer.i;
840
+ uint next = i + Sizes.B64 + 2 * Sizes.Header + c.length + d.length;
841
+ i = reserve(writer, next, next);
842
+ writeBlock64BytesBytes(writer.dst, i, key, a, b, c, d);
843
+ }
844
+
845
+ /// @notice Append a block with a 64-byte head and nested BYTES payload.
846
+ /// @param writer Destination writer; `i` is advanced by the encoded block length.
847
+ /// @param key Block key.
848
+ /// @param a First head word.
849
+ /// @param b Second head word.
850
+ /// @param c Raw nested payload.
851
+ function appendBlock64Bytes(Writer memory writer, bytes4 key, bytes32 a, bytes32 b, bytes memory c) internal pure {
852
+ uint i = writer.i;
853
+ uint next = i + Sizes.B64 + Sizes.Header + c.length;
854
+ i = reserve(writer, next, next);
855
+ writeBlock64Bytes(writer.dst, i, key, a, b, c);
856
+ }
857
+
858
+ /// @notice Append a BYTES block.
859
+ /// @param writer Destination writer; `i` is advanced by the encoded BYTES block length.
860
+ /// @param data Raw bytes payload.
861
+ function appendBytes(Writer memory writer, bytes memory data) internal pure {
862
+ appendBlock(writer, Keys.Bytes, data);
863
+ }
864
+
865
+ /// @notice Append a STEP block with a nested request BYTES payload.
866
+ /// @param writer Destination writer; `i` is advanced by the encoded STEP block length.
867
+ /// @param target Command target identifier.
868
+ /// @param value Native value forwarded with the step.
869
+ /// @param request Raw nested request payload.
870
+ function appendStep(Writer memory writer, uint target, uint value, bytes memory request) internal pure {
871
+ appendBlock64Bytes(writer, Keys.Step, bytes32(target), bytes32(value), request);
872
+ }
873
+
874
+ /// @notice Append a CALL block with a nested payload BYTES block.
875
+ /// @param writer Destination writer; `i` is advanced by the encoded CALL block length.
876
+ /// @param target Call target identifier.
877
+ /// @param value Native value forwarded with the call.
878
+ /// @param data Raw nested call payload.
879
+ function appendCall(Writer memory writer, uint target, uint value, bytes memory data) internal pure {
880
+ appendBlock64Bytes(writer, Keys.Call, bytes32(target), bytes32(value), data);
881
+ }
882
+
883
+ /// @notice Append a CONTEXT block with nested state/request BYTES payloads.
884
+ /// @param writer Destination writer; `i` is advanced by the encoded CONTEXT block length.
885
+ /// @param account Command account identifier.
886
+ /// @param state Raw nested state payload.
887
+ /// @param request Raw nested request payload.
888
+ function appendContext(Writer memory writer, bytes32 account, bytes memory state, bytes memory request) internal pure {
889
+ appendBlock32BytesBytes(writer, Keys.Context, account, state, request);
890
+ }
891
+
892
+ /// @notice Append a RELAY block with a nested CONTEXT block.
893
+ /// @param writer Destination writer; `i` is advanced by the encoded RELAY block length.
894
+ /// @param target Command target identifier.
895
+ /// @param value Native value assigned to the relay.
896
+ /// @param account Command account identifier.
897
+ /// @param state Raw nested state payload.
898
+ /// @param request Raw nested request payload.
899
+ function appendRelay(
900
+ Writer memory writer,
901
+ uint target,
902
+ uint value,
903
+ bytes32 account,
904
+ bytes memory state,
905
+ bytes memory request
624
906
  ) internal pure {
625
- commit(writer, writeBlockHead64(writer.dst, writer.i, key, a, b, tail));
907
+ uint i = writer.i;
908
+ uint len = 96 + 3 * Sizes.Header + state.length + request.length;
909
+ uint next = i + Sizes.Header + len;
910
+ i = reserve(writer, next, next);
911
+
912
+ uint p = writeHeader(writer.dst, i, Keys.Relay, uint32(max32(len)));
913
+ assembly ("memory-safe") {
914
+ mstore(add(p, 0x08), target)
915
+ mstore(add(p, 0x28), value)
916
+ }
917
+
918
+ writeBlock32BytesBytes(writer.dst, i + Sizes.Header + 64, Keys.Context, account, state, request);
626
919
  }
627
920
 
628
921
  /// @notice Append a STATUS form block.
629
- /// @param writer Destination writer; `i` is advanced by `Sizes.B32`.
922
+ /// @param writer Destination writer; `i` is advanced by `Sizes.Status`.
630
923
  /// @param ok Status value to encode.
631
924
  function appendStatus(Writer memory writer, bool ok) internal pure {
632
- commit(writer, writeBlock32(writer.dst, writer.i, Keys.Status, ok ? bytes32(uint(1)) : bytes32(0), 32));
925
+ appendBlock32(writer, Keys.Status, ok ? bytes32(uint(1) << 248) : bytes32(0), 1);
633
926
  }
634
927
 
635
928
  /// @notice Append a BALANCE block using separate field values.
@@ -638,17 +931,14 @@ library Writers {
638
931
  /// @param meta Asset metadata slot.
639
932
  /// @param amount Token amount.
640
933
  function appendBalance(Writer memory writer, bytes32 asset, bytes32 meta, uint amount) internal pure {
641
- commit(writer, writeBlock96(writer.dst, writer.i, Keys.Balance, asset, meta, bytes32(amount), 32));
934
+ appendBlock96(writer, Keys.Balance, asset, meta, bytes32(amount), 32);
642
935
  }
643
936
 
644
937
  /// @notice Append a BALANCE block from a struct.
645
938
  /// @param writer Destination writer; `i` is advanced by `Sizes.Balance`.
646
939
  /// @param value Balance fields to encode.
647
940
  function appendBalance(Writer memory writer, AssetAmount memory value) internal pure {
648
- commit(
649
- writer,
650
- writeBlock96(writer.dst, writer.i, Keys.Balance, value.asset, value.meta, bytes32(value.amount), 32)
651
- );
941
+ appendBalance(writer, value.asset, value.meta, value.amount);
652
942
  }
653
943
 
654
944
  /// @notice Append an AMOUNT block using separate field values.
@@ -657,17 +947,14 @@ library Writers {
657
947
  /// @param meta Asset metadata slot.
658
948
  /// @param amount Token amount.
659
949
  function appendAmount(Writer memory writer, bytes32 asset, bytes32 meta, uint amount) internal pure {
660
- commit(writer, writeBlock96(writer.dst, writer.i, Keys.Amount, asset, meta, bytes32(amount), 32));
950
+ appendBlock96(writer, Keys.Amount, asset, meta, bytes32(amount), 32);
661
951
  }
662
952
 
663
953
  /// @notice Append an AMOUNT block from a struct.
664
954
  /// @param writer Destination writer; `i` is advanced by `Sizes.Balance`.
665
955
  /// @param value Amount fields to encode.
666
956
  function appendAmount(Writer memory writer, AssetAmount memory value) internal pure {
667
- commit(
668
- writer,
669
- writeBlock96(writer.dst, writer.i, Keys.Amount, value.asset, value.meta, bytes32(value.amount), 32)
670
- );
957
+ appendAmount(writer, value.asset, value.meta, value.amount);
671
958
  }
672
959
 
673
960
  /// @notice Append an ACCOUNT_AMOUNT form block using separate field values.
@@ -683,29 +970,14 @@ library Writers {
683
970
  bytes32 meta,
684
971
  uint amount
685
972
  ) internal pure {
686
- commit(
687
- writer,
688
- writeBlock128(writer.dst, writer.i, Keys.AccountAmount, account, asset, meta, bytes32(amount), 32)
689
- );
973
+ appendBlock128(writer, Keys.AccountAmount, account, asset, meta, bytes32(amount), 32);
690
974
  }
691
975
 
692
976
  /// @notice Append an ACCOUNT_AMOUNT form block from a struct.
693
977
  /// @param writer Destination writer; `i` is advanced by `Sizes.B128`.
694
978
  /// @param value Account amount fields to encode.
695
979
  function appendAccountAmount(Writer memory writer, AccountAmount memory value) internal pure {
696
- commit(
697
- writer,
698
- writeBlock128(
699
- writer.dst,
700
- writer.i,
701
- Keys.AccountAmount,
702
- value.account,
703
- value.asset,
704
- value.meta,
705
- bytes32(value.amount),
706
- 32
707
- )
708
- );
980
+ appendAccountAmount(writer, value.account, value.asset, value.meta, value.amount);
709
981
  }
710
982
 
711
983
  /// @notice Append an ASSET block.
@@ -713,7 +985,7 @@ library Writers {
713
985
  /// @param asset Asset identifier.
714
986
  /// @param meta Asset metadata slot.
715
987
  function appendAsset(Writer memory writer, bytes32 asset, bytes32 meta) internal pure {
716
- commit(writer, writeBlock64(writer.dst, writer.i, Keys.Asset, asset, meta, 32));
988
+ appendBlock64(writer, Keys.Asset, asset, meta, 32);
717
989
  }
718
990
 
719
991
  /// @notice Append a BOUNTY block to the writer.
@@ -721,7 +993,7 @@ library Writers {
721
993
  /// @param amount Relayer reward amount.
722
994
  /// @param relayer Relayer account identifier.
723
995
  function appendBounty(Writer memory writer, uint amount, bytes32 relayer) internal pure {
724
- commit(writer, writeBlock64(writer.dst, writer.i, Keys.Bounty, bytes32(amount), relayer, 32));
996
+ appendBlock64(writer, Keys.Bounty, bytes32(amount), relayer, 32);
725
997
  }
726
998
 
727
999
  /// @notice Append a CUSTODY block using separate field values.
@@ -731,10 +1003,7 @@ library Writers {
731
1003
  /// @param meta Asset metadata slot.
732
1004
  /// @param amount Token amount.
733
1005
  function appendCustody(Writer memory writer, uint host, bytes32 asset, bytes32 meta, uint amount) internal pure {
734
- commit(
735
- writer,
736
- writeBlock128(writer.dst, writer.i, Keys.Custody, bytes32(host), asset, meta, bytes32(amount), 32)
737
- );
1006
+ appendBlock128(writer, Keys.Custody, bytes32(host), asset, meta, bytes32(amount), 32);
738
1007
  }
739
1008
 
740
1009
  /// @notice Append a CUSTODY block from a host and asset amount.
@@ -742,57 +1011,29 @@ library Writers {
742
1011
  /// @param host Host node ID.
743
1012
  /// @param value Custody fields to encode.
744
1013
  function appendCustody(Writer memory writer, uint host, AssetAmount memory value) internal pure {
745
- commit(
746
- writer,
747
- writeBlock128(
748
- writer.dst,
749
- writer.i,
750
- Keys.Custody,
751
- bytes32(host),
752
- value.asset,
753
- value.meta,
754
- bytes32(value.amount),
755
- 32
756
- )
757
- );
1014
+ appendCustody(writer, host, value.asset, value.meta, value.amount);
758
1015
  }
759
1016
 
760
1017
  /// @notice Append a CUSTODY block from a host amount struct.
761
1018
  /// @param writer Destination writer; `i` is advanced by `Sizes.HostAmount`.
762
1019
  /// @param value Custody fields to encode.
763
1020
  function appendCustody(Writer memory writer, HostAmount memory value) internal pure {
764
- commit(
765
- writer,
766
- writeBlock128(
767
- writer.dst,
768
- writer.i,
769
- Keys.Custody,
770
- bytes32(value.host),
771
- value.asset,
772
- value.meta,
773
- bytes32(value.amount),
774
- 32
775
- )
776
- );
1021
+ appendCustody(writer, value.host, value.asset, value.meta, value.amount);
777
1022
  }
778
1023
 
779
1024
  /// @notice Append a TRANSACTION block from a struct.
780
1025
  /// @param writer Destination writer; `i` is advanced by `Sizes.Transaction`.
781
1026
  /// @param value Transfer record fields to encode.
782
1027
  function appendTransaction(Writer memory writer, Tx memory value) internal pure {
783
- commit(
1028
+ appendBlock160(
784
1029
  writer,
785
- writeBlock160(
786
- writer.dst,
787
- writer.i,
788
- Keys.Transaction,
789
- bytes32(value.from),
790
- bytes32(value.to),
791
- value.asset,
792
- value.meta,
793
- bytes32(value.amount),
794
- 32
795
- )
1030
+ Keys.Transaction,
1031
+ bytes32(value.from),
1032
+ bytes32(value.to),
1033
+ value.asset,
1034
+ value.meta,
1035
+ bytes32(value.amount),
1036
+ 32
796
1037
  );
797
1038
  }
798
1039