@rootzero/contracts 0.2.0 → 0.4.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 (161) hide show
  1. package/{contracts/Commands.sol → Commands.sol} +7 -2
  2. package/{contracts/Core.sol → Core.sol} +7 -1
  3. package/{contracts/Blocks.sol → Cursors.sol} +8 -1
  4. package/{contracts/Events.sol → Events.sol} +6 -0
  5. package/README.md +59 -59
  6. package/Utils.sol +18 -0
  7. package/blocks/Cursors.sol +800 -0
  8. package/blocks/Keys.sol +51 -0
  9. package/blocks/Mem.sol +188 -0
  10. package/blocks/Schema.sol +158 -0
  11. package/blocks/Writers.sol +304 -0
  12. package/commands/Base.sol +65 -0
  13. package/commands/Borrow.sol +88 -0
  14. package/commands/Burn.sol +45 -0
  15. package/commands/Create.sol +41 -0
  16. package/commands/Credit.sol +49 -0
  17. package/commands/Debit.sol +58 -0
  18. package/commands/Deposit.sol +57 -0
  19. package/commands/Liquidate.sol +98 -0
  20. package/commands/Liquidity.sol +179 -0
  21. package/commands/Mint.sol +53 -0
  22. package/{contracts/commands → commands}/Pipe.sol +28 -12
  23. package/commands/Provision.sol +84 -0
  24. package/commands/Reclaim.sol +54 -0
  25. package/commands/Redeem.sol +98 -0
  26. package/commands/Remove.sol +41 -0
  27. package/commands/Repay.sol +98 -0
  28. package/commands/Settle.sol +41 -0
  29. package/commands/Stake.sol +129 -0
  30. package/commands/Supply.sol +40 -0
  31. package/commands/Swap.sol +89 -0
  32. package/commands/Transfer.sol +55 -0
  33. package/commands/Unstake.sol +57 -0
  34. package/commands/Withdraw.sol +49 -0
  35. package/commands/admin/Allocate.sol +40 -0
  36. package/commands/admin/AllowAssets.sol +42 -0
  37. package/commands/admin/Authorize.sol +38 -0
  38. package/commands/admin/DenyAssets.sol +42 -0
  39. package/commands/admin/Destroy.sol +38 -0
  40. package/commands/admin/Init.sol +38 -0
  41. package/commands/admin/Relocate.sol +39 -0
  42. package/commands/admin/Unauthorize.sol +38 -0
  43. package/core/Access.sol +79 -0
  44. package/core/Balances.sol +40 -0
  45. package/core/Host.sol +44 -0
  46. package/core/Operation.sol +69 -0
  47. package/core/Validator.sol +46 -0
  48. package/docs/GETTING_STARTED.md +286 -0
  49. package/{contracts/events → events}/Access.sol +7 -0
  50. package/events/Asset.sol +21 -0
  51. package/{contracts/events → events}/Balance.sol +10 -0
  52. package/events/Collateral.sol +24 -0
  53. package/events/Command.sol +24 -0
  54. package/events/Debt.sol +25 -0
  55. package/{contracts/events → events}/Deposit.sol +9 -0
  56. package/events/Emitter.sol +14 -0
  57. package/{contracts/events → events}/Governed.sol +7 -0
  58. package/{contracts/events → events}/HostAnnounced.sol +8 -0
  59. package/{contracts/events → events}/Listing.sol +9 -0
  60. package/{contracts/events → events}/Peer.sol +8 -0
  61. package/{contracts/events → events}/Quote.sol +7 -0
  62. package/{contracts/events → events}/RootZero.sol +5 -0
  63. package/{contracts/events → events}/Withdraw.sol +9 -0
  64. package/interfaces/IHostDiscovery.sol +16 -0
  65. package/package.json +17 -33
  66. package/peer/AllowAssets.sol +44 -0
  67. package/peer/Base.sol +25 -0
  68. package/peer/DenyAssets.sol +44 -0
  69. package/peer/Pull.sol +42 -0
  70. package/peer/Push.sol +42 -0
  71. package/utils/Accounts.sol +90 -0
  72. package/utils/Assets.sol +138 -0
  73. package/utils/ECDSA.sol +58 -0
  74. package/utils/Ids.sol +129 -0
  75. package/utils/Layout.sol +66 -0
  76. package/utils/State.sol +22 -0
  77. package/utils/Utils.sol +194 -0
  78. package/utils/Value.sol +32 -0
  79. package/contracts/Utils.sol +0 -12
  80. package/contracts/blocks/Blocks.sol +0 -818
  81. package/contracts/blocks/Keys.sol +0 -24
  82. package/contracts/blocks/Mem.sol +0 -129
  83. package/contracts/blocks/Schema.sol +0 -105
  84. package/contracts/blocks/Writers.sol +0 -209
  85. package/contracts/combinators/AmountToBalance.sol +0 -25
  86. package/contracts/combinators/AmountToCustody.sol +0 -36
  87. package/contracts/combinators/CustodyToBalance.sol +0 -25
  88. package/contracts/combinators/EachRoute.sol +0 -18
  89. package/contracts/combinators/MapBalance.sol +0 -25
  90. package/contracts/combinators/MapCustody.sol +0 -25
  91. package/contracts/combinators/RouteToBalance.sol +0 -27
  92. package/contracts/commands/Base.sol +0 -40
  93. package/contracts/commands/Borrow.sol +0 -89
  94. package/contracts/commands/Burn.sol +0 -33
  95. package/contracts/commands/Create.sol +0 -32
  96. package/contracts/commands/Credit.sol +0 -36
  97. package/contracts/commands/Debit.sol +0 -46
  98. package/contracts/commands/Deposit.sol +0 -45
  99. package/contracts/commands/Liquidate.sol +0 -101
  100. package/contracts/commands/Liquidity.sol +0 -179
  101. package/contracts/commands/Mint.sol +0 -42
  102. package/contracts/commands/Provision.sol +0 -73
  103. package/contracts/commands/Reclaim.sol +0 -48
  104. package/contracts/commands/Redeem.sol +0 -101
  105. package/contracts/commands/Remove.sol +0 -32
  106. package/contracts/commands/Repay.sol +0 -101
  107. package/contracts/commands/Settle.sol +0 -32
  108. package/contracts/commands/Stake.sol +0 -121
  109. package/contracts/commands/Supply.sol +0 -33
  110. package/contracts/commands/Swap.sol +0 -88
  111. package/contracts/commands/Transfer.sol +0 -44
  112. package/contracts/commands/Unstake.sol +0 -49
  113. package/contracts/commands/Withdraw.sol +0 -37
  114. package/contracts/commands/admin/Allocate.sol +0 -32
  115. package/contracts/commands/admin/AllowAssets.sol +0 -34
  116. package/contracts/commands/admin/Authorize.sol +0 -30
  117. package/contracts/commands/admin/DenyAssets.sol +0 -34
  118. package/contracts/commands/admin/Destroy.sol +0 -27
  119. package/contracts/commands/admin/Init.sol +0 -26
  120. package/contracts/commands/admin/Relocate.sol +0 -30
  121. package/contracts/commands/admin/Unauthorize.sol +0 -30
  122. package/contracts/core/Access.sol +0 -50
  123. package/contracts/core/Balances.sol +0 -23
  124. package/contracts/core/Host.sol +0 -25
  125. package/contracts/core/Operation.sol +0 -32
  126. package/contracts/core/Validator.sol +0 -31
  127. package/contracts/events/Asset.sol +0 -14
  128. package/contracts/events/Collateral.sol +0 -15
  129. package/contracts/events/Command.sol +0 -14
  130. package/contracts/events/Debt.sol +0 -15
  131. package/contracts/events/Emitter.sol +0 -7
  132. package/contracts/interfaces/IHostDiscovery.sol +0 -6
  133. package/contracts/peer/AllowAssets.sol +0 -30
  134. package/contracts/peer/Base.sol +0 -17
  135. package/contracts/peer/DenyAssets.sol +0 -30
  136. package/contracts/peer/Pull.sol +0 -30
  137. package/contracts/peer/Push.sol +0 -30
  138. package/contracts/test/TestBlockHelper.sol +0 -261
  139. package/contracts/test/TestBorrowHost.sol +0 -47
  140. package/contracts/test/TestBurnHost.sol +0 -28
  141. package/contracts/test/TestCreateHost.sol +0 -26
  142. package/contracts/test/TestDiscovery.sol +0 -6
  143. package/contracts/test/TestECDSA.sol +0 -16
  144. package/contracts/test/TestHost.sol +0 -199
  145. package/contracts/test/TestLiquidityHost.sol +0 -145
  146. package/contracts/test/TestMintHost.sol +0 -40
  147. package/contracts/test/TestPeerHost.sol +0 -34
  148. package/contracts/test/TestReclaimHost.sol +0 -48
  149. package/contracts/test/TestRejectEther.sol +0 -8
  150. package/contracts/test/TestRemoveHost.sol +0 -26
  151. package/contracts/test/TestSwapHost.sol +0 -44
  152. package/contracts/test/TestUtils.sol +0 -169
  153. package/contracts/test/TestValidator.sol +0 -10
  154. package/contracts/utils/Accounts.sol +0 -40
  155. package/contracts/utils/Assets.sol +0 -76
  156. package/contracts/utils/Channels.sol +0 -11
  157. package/contracts/utils/ECDSA.sol +0 -36
  158. package/contracts/utils/Ids.sol +0 -75
  159. package/contracts/utils/Layout.sol +0 -22
  160. package/contracts/utils/Utils.sol +0 -126
  161. package/contracts/utils/Value.sol +0 -20
@@ -0,0 +1,51 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ /// @title Keys
5
+ /// @notice Block type selectors for the rootzero block stream protocol.
6
+ /// Each key is the first 4 bytes of the keccak256 hash of its schema string,
7
+ /// matching the ABI-selector convention used in `Schemas`.
8
+ library Keys {
9
+ /// @dev Input amount — (bytes32 asset, bytes32 meta, uint amount)
10
+ bytes4 constant Amount = bytes4(keccak256("amount(bytes32 asset, bytes32 meta, uint amount)"));
11
+ /// @dev Ledger balance — (bytes32 asset, bytes32 meta, uint amount)
12
+ bytes4 constant Balance = bytes4(keccak256("balance(bytes32 asset, bytes32 meta, uint amount)"));
13
+ /// @dev Cross-host custody position — (uint host, bytes32 asset, bytes32 meta, uint amount)
14
+ bytes4 constant Custody = bytes4(keccak256("custody(uint host, bytes32 asset, bytes32 meta, uint amount)"));
15
+ /// @dev Minimum acceptable output — (bytes32 asset, bytes32 meta, uint amount)
16
+ bytes4 constant Minimum = bytes4(keccak256("minimum(bytes32 asset, bytes32 meta, uint amount)"));
17
+ /// @dev Maximum allowable spend — (bytes32 asset, bytes32 meta, uint amount)
18
+ bytes4 constant Maximum = bytes4(keccak256("maximum(bytes32 asset, bytes32 meta, uint amount)"));
19
+ /// @dev Hard stop / iteration sentinel — ()
20
+ bytes4 constant Break = bytes4(keccak256("break()"));
21
+ /// @dev Bundle wrapper — (bytes data); payload is an embedded block stream
22
+ bytes4 constant Bundle = bytes4(keccak256("bundle(bytes data)"));
23
+ /// @dev Extensible routing field — (bytes data); layout is command-defined
24
+ bytes4 constant Route = bytes4(keccak256("route(bytes data)"));
25
+ /// @dev Plain scalar amount — (uint amount)
26
+ bytes4 constant Quantity = bytes4(keccak256("quantity(uint amount)"));
27
+ /// @dev Ratio or rate value — (uint value)
28
+ bytes4 constant Rate = bytes4(keccak256("rate(uint value)"));
29
+ /// @dev Counter-party account — (bytes32 account)
30
+ bytes4 constant Party = bytes4(keccak256("party(bytes32 account)"));
31
+ /// @dev Destination account — (bytes32 account)
32
+ bytes4 constant Recipient = bytes4(keccak256("recipient(bytes32 account)"));
33
+ /// @dev Settled transfer record — (bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)
34
+ bytes4 constant Transaction = bytes4(keccak256("tx(bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)"));
35
+ /// @dev Sub-command invocation — (uint target, uint value, bytes request)
36
+ bytes4 constant Step = bytes4(keccak256("step(uint target, uint value, bytes request)"));
37
+ /// @dev Authentication proof — (uint cid, uint deadline, bytes proof); must appear last in its segment
38
+ bytes4 constant Auth = bytes4(keccak256("auth(uint cid, uint deadline, bytes proof)"));
39
+ /// @dev Asset descriptor without amount — (bytes32 asset, bytes32 meta)
40
+ bytes4 constant Asset = bytes4(keccak256("asset(bytes32 asset, bytes32 meta)"));
41
+ /// @dev Node identifier — (uint id)
42
+ bytes4 constant Node = bytes4(keccak256("node(uint id)"));
43
+ /// @dev Cross-host asset listing — (uint host, bytes32 asset, bytes32 meta)
44
+ bytes4 constant Listing = bytes4(keccak256("listing(uint host, bytes32 asset, bytes32 meta)"));
45
+ /// @dev Liquidity funding entry — (uint host, uint amount)
46
+ bytes4 constant Funding = bytes4(keccak256("funding(uint host, uint amount)"));
47
+ /// @dev Cross-host allocation — (uint host, bytes32 asset, bytes32 meta, uint amount)
48
+ bytes4 constant Allocation = bytes4(keccak256("allocation(uint host, bytes32 asset, bytes32 meta, uint amount)"));
49
+ /// @dev Relayer bounty — (uint amount, bytes32 relayer)
50
+ bytes4 constant Bounty = bytes4(keccak256("bounty(uint amount, bytes32 relayer)"));
51
+ }
package/blocks/Mem.sol ADDED
@@ -0,0 +1,188 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { HostAmount, Tx, Keys } from "./Schema.sol";
5
+ import { Cursors } from "./Cursors.sol";
6
+
7
+ /// @notice Reference to a single block inside a `bytes memory` buffer.
8
+ /// Positions are byte offsets within the buffer (not absolute memory addresses).
9
+ struct MemRef {
10
+ /// @dev Block type identifier read from the 4-byte header key.
11
+ bytes4 key;
12
+ /// @dev Payload start offset (byte immediately after the 8-byte header).
13
+ uint i;
14
+ /// @dev Payload end offset (equals `i + payloadLen`).
15
+ uint end;
16
+ }
17
+
18
+ /// @title Mem
19
+ /// @notice Memory block stream parser for the rootzero protocol.
20
+ /// Mirrors the calldata-oriented `Cursors` API but operates on `bytes memory`
21
+ /// buffers, using `mcopy`/`mload` assembly instead of `msg.data` slices.
22
+ library Mem {
23
+ /// @notice Parse a block header at offset `i` within `source`.
24
+ /// Returns an empty sentinel `MemRef` (all zeros) when `i` is at end-of-data.
25
+ /// @param source In-memory block stream buffer.
26
+ /// @param i Byte offset of the block header within `source`.
27
+ /// @return ref Parsed block reference with key, payload start, and payload end.
28
+ function from(bytes memory source, uint i) internal pure returns (MemRef memory ref) {
29
+ uint eod = source.length;
30
+ if (i == eod) return MemRef(bytes4(0), i, i);
31
+ if (i > eod) revert Cursors.MalformedBlocks();
32
+
33
+ unchecked {
34
+ ref.i = i + 8;
35
+ }
36
+ if (ref.i > eod) revert Cursors.MalformedBlocks();
37
+
38
+ // Read the 8-byte block header (key + payloadLen) in one mload.
39
+ bytes32 w;
40
+ assembly ("memory-safe") {
41
+ w := mload(add(add(source, 0x20), i))
42
+ }
43
+
44
+ ref.key = bytes4(w);
45
+ ref.end = ref.i + uint32(bytes4(w << 32));
46
+ if (ref.end > eod) revert Cursors.MalformedBlocks();
47
+ }
48
+
49
+ /// @notice Extract a byte range `[start, end)` from `source` into a new buffer.
50
+ /// @param source Source buffer.
51
+ /// @param start Inclusive start offset.
52
+ /// @param end Exclusive end offset.
53
+ /// @return out Copied slice as a new `bytes` value.
54
+ function slice(bytes memory source, uint start, uint end) internal pure returns (bytes memory out) {
55
+ if (end < start || end > source.length) revert Cursors.MalformedBlocks();
56
+ uint len = end - start;
57
+ out = new bytes(len);
58
+ if (len == 0) return out;
59
+
60
+ assembly ("memory-safe") {
61
+ mcopy(add(out, 0x20), add(add(source, 0x20), start), len)
62
+ }
63
+ }
64
+
65
+ /// @notice Count consecutive blocks of `key` starting at offset `i`.
66
+ /// @param source Source buffer.
67
+ /// @param i Starting byte offset.
68
+ /// @param key Block type to count.
69
+ /// @return total Number of consecutive matching blocks.
70
+ /// @return cursor Byte offset immediately after the last counted block.
71
+ function count(bytes memory source, uint i, bytes4 key) internal pure returns (uint total, uint cursor) {
72
+ cursor = i;
73
+ while (cursor < source.length) {
74
+ MemRef memory ref = from(source, cursor);
75
+ if (ref.key != key) break;
76
+ unchecked {
77
+ ++total;
78
+ }
79
+ cursor = ref.end;
80
+ }
81
+ }
82
+
83
+ /// @notice Scan forward from `i` up to `limit` for the first block matching `key`.
84
+ /// Returns an empty sentinel `MemRef` (key == 0, i == end == limit) if not found.
85
+ /// @param source Source buffer.
86
+ /// @param i Starting byte offset.
87
+ /// @param limit Exclusive upper bound for the search (must be ≤ `source.length`).
88
+ /// @param key Block type to find.
89
+ /// @return ref Reference to the first matching block, or the sentinel if absent.
90
+ function find(bytes memory source, uint i, uint limit, bytes4 key) internal pure returns (MemRef memory ref) {
91
+ if (limit > source.length) revert Cursors.MalformedBlocks();
92
+ while (i < limit) {
93
+ ref = from(source, i);
94
+ if (ref.end > limit) revert Cursors.MalformedBlocks();
95
+ if (ref.key == key) return ref;
96
+ i = ref.end;
97
+ }
98
+
99
+ return MemRef(bytes4(0), limit, limit);
100
+ }
101
+
102
+ /// @notice Assert that `ref` points to a block of the expected type.
103
+ /// @param ref Block reference to validate.
104
+ /// @param key Expected block type key.
105
+ function ensure(MemRef memory ref, bytes4 key) internal pure {
106
+ if (key == 0 || key != ref.key) revert Cursors.InvalidBlock();
107
+ }
108
+
109
+ /// @notice Assert that `ref` points to a block of the expected type with exact payload length.
110
+ /// @param ref Block reference to validate.
111
+ /// @param key Expected block type key.
112
+ /// @param len Expected payload byte length.
113
+ function ensure(MemRef memory ref, bytes4 key, uint len) internal pure {
114
+ if (key == 0 || key != ref.key || len != (ref.end - ref.i)) revert Cursors.InvalidBlock();
115
+ }
116
+
117
+ /// @notice Assert that `ref` points to a block of the expected type within a length range.
118
+ /// @param ref Block reference to validate.
119
+ /// @param key Expected block type key.
120
+ /// @param min Minimum payload length (inclusive).
121
+ /// @param max Maximum payload length (inclusive); 0 means unbounded.
122
+ function ensure(MemRef memory ref, bytes4 key, uint min, uint max) internal pure {
123
+ uint len = ref.end - ref.i;
124
+ if (key == 0 || key != ref.key || len < min || (max != 0 && len > max)) revert Cursors.InvalidBlock();
125
+ }
126
+
127
+ /// @notice Decode a BALANCE block payload from `source` using the given reference.
128
+ /// @param ref Block reference; must point to a BALANCE block with exactly 96 payload bytes.
129
+ /// @param source Buffer containing the block.
130
+ /// @return asset Asset identifier.
131
+ /// @return meta Asset metadata slot.
132
+ /// @return amount Token amount.
133
+ function unpackBalance(
134
+ MemRef memory ref,
135
+ bytes memory source
136
+ ) internal pure returns (bytes32 asset, bytes32 meta, uint amount) {
137
+ ensure(ref, Keys.Balance, 96);
138
+ uint i = ref.i;
139
+
140
+ // Read three contiguous 32-byte words from the payload.
141
+ assembly ("memory-safe") {
142
+ let p := add(add(source, 0x20), i)
143
+ asset := mload(p)
144
+ meta := mload(add(p, 0x20))
145
+ amount := mload(add(p, 0x40))
146
+ }
147
+ }
148
+
149
+ /// @notice Decode a CUSTODY block payload from `source` into a `HostAmount` struct.
150
+ /// @param ref Block reference; must point to a CUSTODY block with exactly 128 payload bytes.
151
+ /// @param source Buffer containing the block.
152
+ /// @return value Decoded host, asset, meta, and amount.
153
+ function toCustodyValue(
154
+ MemRef memory ref,
155
+ bytes memory source
156
+ ) internal pure returns (HostAmount memory value) {
157
+ ensure(ref, Keys.Custody, 128);
158
+ uint i = ref.i;
159
+
160
+ // Copy four 32-byte payload words directly into the struct memory slots.
161
+ assembly ("memory-safe") {
162
+ let p := add(add(source, 0x20), i)
163
+ mstore(value, mload(p))
164
+ mstore(add(value, 0x20), mload(add(p, 0x20)))
165
+ mstore(add(value, 0x40), mload(add(p, 0x40)))
166
+ mstore(add(value, 0x60), mload(add(p, 0x60)))
167
+ }
168
+ }
169
+
170
+ /// @notice Decode a TRANSACTION block payload from `source` into a `Tx` struct.
171
+ /// @param ref Block reference; must point to a TRANSACTION block with exactly 160 payload bytes.
172
+ /// @param source Buffer containing the block.
173
+ /// @return value Decoded from, to, asset, meta, and amount.
174
+ function toTxValue(MemRef memory ref, bytes memory source) internal pure returns (Tx memory value) {
175
+ ensure(ref, Keys.Transaction, 160);
176
+ uint i = ref.i;
177
+
178
+ // Copy five 32-byte payload words directly into the struct memory slots.
179
+ assembly ("memory-safe") {
180
+ let p := add(add(source, 0x20), i)
181
+ mstore(value, mload(p))
182
+ mstore(add(value, 0x20), mload(add(p, 0x20)))
183
+ mstore(add(value, 0x40), mload(add(p, 0x40)))
184
+ mstore(add(value, 0x60), mload(add(p, 0x60)))
185
+ mstore(add(value, 0x80), mload(add(p, 0x80)))
186
+ }
187
+ }
188
+ }
@@ -0,0 +1,158 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { Keys } from "./Keys.sol";
5
+
6
+ /// @title Schemas
7
+ /// @notice Human-readable ABI-signature string constants for each block type.
8
+ /// These strings are the canonical source from which `Keys` constants are derived
9
+ /// and are used when emitting schema descriptors in command events.
10
+ library Schemas {
11
+ string constant Amount = "amount(bytes32 asset, bytes32 meta, uint amount)";
12
+ string constant Balance = "balance(bytes32 asset, bytes32 meta, uint amount)";
13
+ string constant Custody = "custody(uint host, bytes32 asset, bytes32 meta, uint amount)";
14
+ string constant Minimum = "minimum(bytes32 asset, bytes32 meta, uint amount)";
15
+ string constant Maximum = "maximum(bytes32 asset, bytes32 meta, uint amount)";
16
+ string constant Break = "break()";
17
+ string constant Route = "route(bytes data)";
18
+ string constant RouteEmpty = "route()";
19
+ string constant Quantity = "quantity(uint amount)";
20
+ string constant Rate = "rate(uint value)";
21
+ string constant Party = "party(bytes32 account)";
22
+ string constant Recipient = "recipient(bytes32 account)";
23
+ string constant Transaction = "tx(bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)";
24
+ string constant Step = "step(uint target, uint value, bytes request)";
25
+ string constant Auth = "auth(uint cid, uint deadline, bytes proof)";
26
+ string constant Asset = "asset(bytes32 asset, bytes32 meta)";
27
+ string constant Node = "node(uint id)";
28
+ string constant Listing = "listing(uint host, bytes32 asset, bytes32 meta)";
29
+ string constant Funding = "funding(uint host, uint amount)";
30
+ string constant Allocation = "allocation(uint host, bytes32 asset, bytes32 meta, uint amount)";
31
+ string constant Bounty = "bounty(uint amount, bytes32 relayer)";
32
+
33
+ /// @notice Compose a route schema with one additional field.
34
+ /// @param maybeRoute Existing route schema string, or empty string to start a fresh `route()`.
35
+ /// @param a Schema string for the field to append.
36
+ /// @return Composed schema string: `"route(...) & a"`.
37
+ function route1(string memory maybeRoute, string memory a) internal pure returns (string memory) {
38
+ return string.concat(bytes(maybeRoute).length == 0 ? RouteEmpty : maybeRoute, "&", a);
39
+ }
40
+
41
+ /// @notice Compose a route schema with two additional fields.
42
+ /// @param maybeRoute Existing route schema string, or empty string to start a fresh `route()`.
43
+ /// @param a Schema string for the first field to append.
44
+ /// @param b Schema string for the second field to append.
45
+ /// @return Composed schema string: `"route(...) & a & b"`.
46
+ function route2(string memory maybeRoute, string memory a, string memory b) internal pure returns (string memory) {
47
+ return string.concat(bytes(maybeRoute).length == 0 ? RouteEmpty : maybeRoute, "&", a, "&", b);
48
+ }
49
+ }
50
+
51
+ // Block stream:
52
+ // - encoding is [bytes4 key][bytes4 payloadLen][payload]
53
+ // - `payloadLen` covers only the block payload
54
+ // - payload layout is block-specific
55
+ //
56
+ // Extensible payloads:
57
+ // - self payload may be [head][dynamic tail]
58
+ // - head layout is implied by the block key
59
+ // - one dynamic field may consume the rest of self payload without its own length prefix
60
+ //
61
+ // Schema DSL:
62
+ // - `;` separates top-level sibling blocks
63
+ // - `&` bundles adjacent blocks into one bundle block
64
+ // - bundled blocks preserve member order, so `a & b` differs from `b & a`
65
+ // - a bundle block's self payload is an embedded normal block stream of its bundled members
66
+ // - bundled members keep their ordinary block encoding, so dynamic blocks are allowed inside bundles
67
+ // - `->` separates request and response shapes, appears at most once, and is omitted when no output is modeled
68
+ // - top-level blocks of the same type should be grouped together
69
+ // - primary / driving blocks should appear before auxiliary blocks
70
+ // - `route(<fields...>)` is a reserved extensible schema form whose key is always `Keys.Route`
71
+ // - `&` compiles to a `Keys.Bundle` block whose self payload is the bundled member block stream
72
+ // - canonical blocks are `amount(...)` for request amounts, `balance(...)` for state balances,
73
+ // `minimum(...)` for result floors, `maximum(...)` for spend ceilings, and `quantity(...)`
74
+ // for plain scalar amounts
75
+ // - `auth(uint cid, uint deadline, bytes proof)` is a proof-separator block and must be emitted last
76
+ //
77
+ // Signed blocks:
78
+ // - an authenticated input segment ends with one trailing AUTH block
79
+ // - auth is typically grouped with the signed payload in one bundle, with AUTH as the final member
80
+ // - only the final AUTH is treated specially; earlier AUTH blocks remain ordinary signed bytes
81
+ // - the signed slice runs from the segment start through the AUTH head, excluding only AUTH proof bytes
82
+ // - `cid` binds the signature to one command; `deadline` acts as expiry and nonce
83
+ // - current helpers assume proof layout `[bytes20 signer][bytes65 sig]`
84
+
85
+ /// @title Sizes
86
+ /// @notice Total byte sizes for fixed-width block types, including the 8-byte header (4-byte key + 4-byte payloadLen).
87
+ library Sizes {
88
+ /// @dev AUTH proof segment only: 20-byte signer + 65-byte signature = 85 bytes
89
+ uint constant Proof = 85;
90
+ /// @dev AUTH block: 8 header + 32 cid + 32 deadline + 85 proof = 157 bytes
91
+ uint constant Auth = 157;
92
+ /// @dev BALANCE block: 8 header + 32 asset + 32 meta + 32 amount = 104 bytes
93
+ uint constant Balance = 104;
94
+ /// @dev BOUNTY block: 8 header + 32 amount + 32 relayer = 72 bytes
95
+ uint constant Bounty = 72;
96
+ /// @dev CUSTODY block: 8 header + 32 host + 32 asset + 32 meta + 32 amount = 136 bytes
97
+ uint constant Custody = 136;
98
+ /// @dev TRANSACTION block: 8 header + 32 from + 32 to + 32 asset + 32 meta + 32 amount = 168 bytes
99
+ uint constant Transaction = 168;
100
+ }
101
+
102
+ /// @notice Asset and amount pair; used for balance and amount blocks.
103
+ struct AssetAmount {
104
+ /// @dev Asset identifier (encoding depends on asset type — see `Assets` library).
105
+ bytes32 asset;
106
+ /// @dev Asset metadata slot (e.g. token contract address or ERC-721 token ID context).
107
+ bytes32 meta;
108
+ /// @dev Token amount in the asset's native units.
109
+ uint amount;
110
+ }
111
+
112
+ /// @notice Cross-host custody value; used for custody and allocation blocks.
113
+ struct HostAmount {
114
+ /// @dev Host node ID that holds the custody position.
115
+ uint host;
116
+ /// @dev Asset identifier.
117
+ bytes32 asset;
118
+ /// @dev Asset metadata slot.
119
+ bytes32 meta;
120
+ /// @dev Token amount in the asset's native units.
121
+ uint amount;
122
+ }
123
+
124
+ /// @notice User-scoped amount; associates an account with an asset amount.
125
+ struct UserAmount {
126
+ /// @dev User account identifier.
127
+ bytes32 account;
128
+ /// @dev Asset identifier.
129
+ bytes32 asset;
130
+ /// @dev Asset metadata slot.
131
+ bytes32 meta;
132
+ /// @dev Token amount in the asset's native units.
133
+ uint amount;
134
+ }
135
+
136
+ /// @notice Cross-host asset descriptor without an amount.
137
+ struct HostAsset {
138
+ /// @dev Host node ID.
139
+ uint host;
140
+ /// @dev Asset identifier.
141
+ bytes32 asset;
142
+ /// @dev Asset metadata slot.
143
+ bytes32 meta;
144
+ }
145
+
146
+ /// @notice Settled transfer record written to transaction state.
147
+ struct Tx {
148
+ /// @dev Sender account identifier.
149
+ bytes32 from;
150
+ /// @dev Recipient account identifier.
151
+ bytes32 to;
152
+ /// @dev Asset identifier.
153
+ bytes32 asset;
154
+ /// @dev Asset metadata slot.
155
+ bytes32 meta;
156
+ /// @dev Transfer amount in the asset's native units.
157
+ uint amount;
158
+ }