@rootzero/contracts 0.9.3 → 0.9.4

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.
package/blocks/Keys.sol CHANGED
@@ -1,88 +1,69 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {Forms} from "./Schema.sol";
5
-
6
4
  /// @title Keys
7
5
  /// @notice Block type selectors for the rootzero block stream protocol.
8
- /// Each key is the first 4 bytes of the keccak256 hash of its schema string,
9
- /// matching the ABI-selector convention used in `Schemas`.
6
+ /// Each key is the first 4 bytes of the keccak256 hash of its block name.
10
7
  library Keys {
11
8
  /// @dev Empty / unset key.
12
9
  bytes4 constant Empty = bytes4(0);
13
10
  /// @dev Input amount - (bytes32 asset, bytes32 meta, uint amount)
14
- bytes4 constant Amount = bytes4(keccak256("amount(bytes32 asset, bytes32 meta, uint amount)"));
11
+ bytes4 constant Amount = bytes4(keccak256("#amount"));
15
12
  /// @dev Ledger balance - (bytes32 asset, bytes32 meta, uint amount)
16
- bytes4 constant Balance = bytes4(keccak256("balance(bytes32 asset, bytes32 meta, uint amount)"));
13
+ bytes4 constant Balance = bytes4(keccak256("#balance"));
17
14
  /// @dev Host-scoped request amount - (uint host, bytes32 asset, bytes32 meta, uint amount)
18
- bytes4 constant Allocation = bytes4(keccak256("allocation(uint host, bytes32 asset, bytes32 meta, uint amount)"));
15
+ bytes4 constant Allocation = bytes4(keccak256("#allocation"));
19
16
  /// @dev Host-scoped allowance cap - (uint host, bytes32 asset, bytes32 meta, uint amount)
20
- bytes4 constant Allowance = bytes4(keccak256("allowance(uint host, bytes32 asset, bytes32 meta, uint amount)"));
17
+ bytes4 constant Allowance = bytes4(keccak256("#allowance"));
21
18
  /// @dev Cross-host custody state - (uint host, bytes32 asset, bytes32 meta, uint amount)
22
- bytes4 constant Custody = bytes4(keccak256("custody(uint host, bytes32 asset, bytes32 meta, uint amount)"));
19
+ bytes4 constant Custody = bytes4(keccak256("#custody"));
23
20
  /// @dev Minimum acceptable output - (bytes32 asset, bytes32 meta, uint amount)
24
- bytes4 constant Minimum = bytes4(keccak256("minimum(bytes32 asset, bytes32 meta, uint amount)"));
21
+ bytes4 constant Minimum = bytes4(keccak256("#minimum"));
25
22
  /// @dev Maximum allowable spend - (bytes32 asset, bytes32 meta, uint amount)
26
- bytes4 constant Maximum = bytes4(keccak256("maximum(bytes32 asset, bytes32 meta, uint amount)"));
27
- /// @dev Signed min/max bounds - (int min, int max)
28
- bytes4 constant Bounds = bytes4(keccak256("bounds(int min, int max)"));
23
+ bytes4 constant Maximum = bytes4(keccak256("#maximum"));
29
24
  /// @dev Fee amount - (uint amount)
30
- bytes4 constant Fee = bytes4(keccak256("fee(uint amount)"));
31
- /// @dev Hard stop / iteration sentinel - ()
32
- bytes4 constant Break = bytes4(keccak256("break()"));
33
- /// @dev Bundle wrapper - (bytes data); payload is an embedded block stream
34
- bytes4 constant Bundle = bytes4(keccak256("bundle(bytes data)"));
35
- /// @dev List wrapper - (bytes data); payload is an embedded repeated block stream
36
- bytes4 constant List = bytes4(keccak256("list(bytes data)"));
37
- /// @dev Frame wrapper - (bytes data); payload is schema-defined fields, optionally followed by block-stream items
38
- bytes4 constant Frame = bytes4(keccak256("frame(bytes data)"));
39
- /// @dev Extensible routing field - (bytes data); layout is command-defined
40
- bytes4 constant Route = bytes4(keccak256("route(bytes data)"));
41
- /// @dev Extensible list item field - (bytes data); layout is implementation-defined
42
- bytes4 constant Item = bytes4(keccak256("item(bytes data)"));
43
- /// @dev EVM-encoded payload field - (bytes data); layout follows standard ABI tuple encoding
44
- bytes4 constant Evm = bytes4(keccak256("evm(bytes data)"));
45
- /// @dev Extensible query field - (bytes data); layout is query-defined, key is always `Keys.Query`
46
- bytes4 constant Query = bytes4(keccak256("query(bytes data)"));
47
- /// @dev Extensible response field - (bytes data); layout is response-defined, key is always `Keys.Response`
48
- bytes4 constant Response = bytes4(keccak256("response(bytes data)"));
49
- /// @dev Plain scalar amount - (uint amount)
50
- bytes4 constant Quantity = bytes4(keccak256("quantity(uint amount)"));
51
- /// @dev Ratio or rate value - (uint value)
52
- bytes4 constant Rate = bytes4(keccak256("rate(uint value)"));
25
+ bytes4 constant Fee = bytes4(keccak256("#fee"));
26
+ /// @dev List wrapper; payload is an embedded repeated block stream
27
+ bytes4 constant List = bytes4(keccak256("#list"));
28
+ /// @dev Extensible data field; layout is schema-defined
29
+ bytes4 constant Data = bytes4(keccak256("#data"));
30
+ /// @dev EVM-encoded payload field; layout follows standard ABI tuple encoding
31
+ bytes4 constant Evm = bytes4(keccak256("#evm"));
32
+ /// @dev Reserved raw bytes child block.
33
+ bytes4 constant Bytes = bytes4(keccak256("#bytes"));
53
34
  /// @dev Account identifier - (bytes32 account)
54
- bytes4 constant Account = bytes4(keccak256("account(bytes32 account)"));
35
+ bytes4 constant Account = bytes4(keccak256("#account"));
55
36
  /// @dev Transfer payout request - (bytes32 account, bytes32 asset, bytes32 meta, uint amount)
56
- bytes4 constant Payout = bytes4(keccak256("payout(bytes32 account, bytes32 asset, bytes32 meta, uint amount)"));
37
+ bytes4 constant Payout = bytes4(keccak256("#payout"));
57
38
  /// @dev Transfer record passed through the pipeline - (bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)
58
- bytes4 constant Transaction = bytes4(
59
- keccak256("transaction(bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)")
60
- );
61
- /// @dev Sub-command invocation - (uint target, uint value, bytes request)
62
- bytes4 constant Step = bytes4(keccak256("step(uint target, uint value, bytes request)"));
63
- /// @dev Raw external call - (uint target, uint value, bytes data)
64
- bytes4 constant Call = bytes4(keccak256("call(uint target, uint value, bytes data)"));
65
- /// @dev Authentication proof - (uint cid, uint deadline, bytes proof); must appear last in its segment
66
- bytes4 constant Auth = bytes4(keccak256("auth(uint cid, uint deadline, bytes proof)"));
39
+ bytes4 constant Transaction = bytes4(keccak256("#transaction"));
40
+ /// @dev Sub-command invocation - (uint target, uint value, #bytes as request)
41
+ bytes4 constant Step = bytes4(keccak256("#step"));
42
+ /// @dev Raw external call - (uint target, uint value, #bytes as payload)
43
+ bytes4 constant Call = bytes4(keccak256("#call"));
44
+ /// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
45
+ bytes4 constant Context = bytes4(keccak256("#context"));
46
+ /// @dev Authentication proof - (uint cid, uint deadline, #bytes as proof); must appear last in its segment
47
+ bytes4 constant Auth = bytes4(keccak256("#auth"));
67
48
  /// @dev Asset descriptor without amount - (bytes32 asset, bytes32 meta)
68
- bytes4 constant Asset = bytes4(keccak256("asset(bytes32 asset, bytes32 meta)"));
49
+ bytes4 constant Asset = bytes4(keccak256("#asset"));
69
50
  /// @dev Node identifier - (uint id)
70
- bytes4 constant Node = bytes4(keccak256("node(uint id)"));
51
+ bytes4 constant Node = bytes4(keccak256("#node"));
71
52
  /// @dev Relayer bounty - (uint amount, bytes32 relayer)
72
- bytes4 constant Bounty = bytes4(keccak256("bounty(uint amount, bytes32 relayer)"));
53
+ bytes4 constant Bounty = bytes4(keccak256("#bounty"));
73
54
 
74
55
  /// @dev Structural status form - (bool ok)
75
- bytes4 constant Status = bytes4(keccak256(bytes(Forms.Status)));
56
+ bytes4 constant Status = bytes4(keccak256("#status"));
76
57
  /// @dev Structural asset amount form - (bytes32 asset, bytes32 meta, uint amount)
77
- bytes4 constant AssetAmount = bytes4(keccak256(bytes(Forms.AssetAmount)));
58
+ bytes4 constant AssetAmount = bytes4(keccak256("#assetAmount"));
78
59
  /// @dev Structural account asset form - (bytes32 account, bytes32 asset, bytes32 meta)
79
- bytes4 constant AccountAsset = bytes4(keccak256(bytes(Forms.AccountAsset)));
60
+ bytes4 constant AccountAsset = bytes4(keccak256("#accountAsset"));
80
61
  /// @dev Structural account amount form - (bytes32 account, bytes32 asset, bytes32 meta, uint amount)
81
- bytes4 constant AccountAmount = bytes4(keccak256(bytes(Forms.AccountAmount)));
62
+ bytes4 constant AccountAmount = bytes4(keccak256("#accountAmount"));
82
63
  /// @dev Structural host amount form - (uint host, bytes32 asset, bytes32 meta, uint amount)
83
- bytes4 constant HostAmount = bytes4(keccak256(bytes(Forms.HostAmount)));
64
+ bytes4 constant HostAmount = bytes4(keccak256("#hostAmount"));
84
65
  /// @dev Structural host account asset form - (uint host, bytes32 account, bytes32 asset, bytes32 meta)
85
- bytes4 constant HostAccountAsset = bytes4(keccak256(bytes(Forms.HostAccountAsset)));
66
+ bytes4 constant HostAccountAsset = bytes4(keccak256("#hostAccountAsset"));
86
67
  /// @dev Structural host account amount form - (uint host, bytes32 account, bytes32 asset, bytes32 meta, uint amount)
87
- bytes4 constant HostAccountAmount = bytes4(keccak256(bytes(Forms.HostAccountAmount)));
68
+ bytes4 constant HostAccountAmount = bytes4(keccak256("#hostAccountAmount"));
88
69
  }
package/blocks/Schema.sol CHANGED
@@ -3,174 +3,26 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  // Block stream:
5
5
  // - encoding is [bytes4 key][bytes4 payloadLen][payload]
6
- // - `payloadLen` covers only the block payload
6
+ // - `payloadLen` is big-endian and covers only the block payload
7
7
  // - payload layout is block-specific
8
8
  //
9
- // Extensible payloads:
10
- // - self payload may be [head][dynamic tail]
11
- // - head layout is implied by the block key
12
- // - one dynamic field may consume the rest of self payload without its own length prefix
13
- // - reserved extensible forms keep one fixed key while their declared field list remains descriptive schema metadata
14
- // - chain-specific payload blocks are encoded using the local chain/runtime's native conventions
15
- // - on EVM-family chains, `evm(<fields...>)` payloads use standard ABI tuple encoding via `abi.encode(...)`
16
- // and can be decoded with `abi.decode`
17
- // - chain-specific payload blocks are request-only escape hatches and should never be used for pipeline state
18
- // - prefer ordinary protocol blocks whenever possible; chain-specific payload blocks should be a last resort
19
- // - prefer frames for typed custom payloads; reserved extensible blocks such as `route(...)` and `item(...)`
20
- // should be used only when a stable protocol-level key or opaque escape hatch is needed
21
- //
22
- // Schema DSL:
23
- // - `;` separates top-level items
24
- // - command, peer, and query schemas have the top-level form `prime`, `prime; global; global`,
25
- // `empty; global; global`, or `""` for no request items at all
26
- // - the first top-level item is the prime item unless it is the schema-only `empty` sentinel
27
- // - the prime item must have one runtime key; helpers consume the consecutive run of blocks with
28
- // that key as the per-operation batch, and `Command.shape` is defined over those prime runs
29
- // - `empty` emits no block, has no runtime key, and must only appear as the first top-level item
30
- // before global blocks; it means the schema has no prime item
31
- // - top-level items after the prime item or `empty` are global batch support blocks: they apply to
32
- // the whole batch, may be searched or consumed separately by the command, and are not counted as
33
- // per-operation prime blocks
34
- // - `&` bundles adjacent blocks into one bundle block
35
- // - `+` frames adjacent fixed-layout block payloads into one frame block
36
- // - `+&` appends adjacent blocks to a frame as full block-stream items, preserving their headers
37
- // - leading `&` is shorthand for an anonymous bundle
38
- // - leading `+&` is shorthand for an anonymous frame with only a block-stream tail
39
- // - `&`, `+`, and `+&` follow the same grouping and normalization rules, except they emit different payload forms
40
- // - `name = a & b` introduces a named bundle item with a local key derived from the raw input string
41
- // - `name = a + b` introduces a named frame item with a local key derived from the raw input string
42
- // - `alias: item` attaches a presentation alias to the following schema item for off-chain APIs,
43
- // docs, and UI labels
44
- // - `bundle = a & b` introduces an anonymous child bundle item
45
- // - `frame = a + b` introduces an anonymous child frame item, like `bundle = ...` and `list = ...`
46
- // - `(fields...)` in item position is shorthand for an anonymous frame with those fields
47
- // - `(fields...)` inside an existing frame introduces anonymous flattened frame fields without a nested frame key
48
- // - postfix `[]` marks a repeated list in the simple suffix form, e.g. `asset(...)[]`
49
- // - postfix `?` marks an optional item, e.g. `account(...)?`
50
- // - `name[] = a & b` introduces a named list with a local key derived from the raw input string
51
- // - `name? = a & b` introduces an optional named structural item
52
- // - `name[]? = a & b` introduces an optional named list; `?[]` is invalid
53
- // - `list = a & b` introduces an anonymous list whose repeated item is the bundled shape `a & b`
54
- // - `bundle? = a & b`, `frame? = a + b`, and `list? = a & b` introduce optional anonymous structural items
55
- // - empty entries are ignored, but structural markers are preserved after normalization
56
- // - aliases are presentation metadata: they do not add bytes, headers, fields, or wrappers,
57
- // and they do not change the payload layout of the item they label
58
- // - aliases are not stripped before on-chain local-key derivation; when a named structural item is keyed by
59
- // bytes4(keccak256(bytes(rawSchemaInput))), any alias text present in that raw string is part of identity
60
- // - off-chain presentation should use `alias:` when present, otherwise the schema item name when available
61
- // - if sibling presentation names collide, off-chain tools should append zero-based suffixes in encounter order,
62
- // e.g. `amount(...) + amount(...)` presents as `amount0` and `amount1`
63
- // - when possible, off-chain tools should preserve item grouping for repeated schemas, e.g. `amount0.asset`,
64
- // `amount0.meta`, `amount0.amount`, then `amount1.asset`, `amount1.meta`, `amount1.amount`
65
- // - if fields within one presentation group collide, off-chain tools should suffix those field names in
66
- // encounter order, e.g. `(uint amount, uint amount)` presents as `amount0` and `amount1`
67
- // - optionality is schema metadata only; when an optional item is present, it uses the same encoding as the
68
- // non-optional form, and when absent, no placeholder block is emitted
69
- // - optional children inside a present bundle, list item, or `+&` frame tail may be absent while the
70
- // parent structural block is still emitted; for example `& account(...)?` and `+& account(...)?`
71
- // can encode as an empty BUNDLE or empty FRAME when the account child is absent
72
- // - optional `?` is not allowed on flattened `+` frame members because frame fields have no child key or length;
73
- // use `(fields...)?` as an optional frame item, make the whole frame optional, or use `+&` for
74
- // optional block-stream tail items
75
- // - grouping parentheses are not part of the DSL; parentheses are only used in block field lists
76
- // and anonymous frame field groups
77
- // - anonymous frame field groups in item position are promoted to anonymous frame items, so `(fields...)[]`
78
- // means a list of anonymous frame items and `(fields...)?` means an optional anonymous frame item
79
- // - anonymous frame field groups inside an existing frame are flattened fields, not nested frame items, and
80
- // cannot be appended with `+&`
81
- // - `+` binds tighter than `&`, so `a & b + c` normalizes as `a & (b + c)`
82
- // - `+&` binds like `+`, so `a & b +& c` normalizes as `a & (b +& c)`
83
- // - if `&` appears, the result remains a bundle even when only one non-empty child remains
84
- // - if `+` appears, the result remains a frame even when only one non-empty child remains
85
- // - if `+&` appears, the result remains a frame even when only one non-empty child remains
86
- // - after ignoring empty entries, repeated adjacent separators collapse while preserving bundle/frame/list shape
87
- // - bundled blocks preserve member order, so `a & b` differs from `b & a`
88
- // - a bundle block's self payload is an embedded normal block stream of its bundled members
89
- // - bundled members keep their ordinary block encoding, so dynamic blocks are allowed inside bundles
90
- // - a list block's self payload is an embedded normal block stream representing the repeated items
91
- // - a frame block's self payload is the concatenated payload fields of its framed members
92
- // - framed members do not keep their ordinary block headers; the emitted schema defines the frame layout
93
- // - framed members must be fixed-layout block forms because frame payloads contain no child lengths or block keys
94
- // - anonymous frame field groups must also be fixed-layout and contribute only their fields, in order
95
- // - `+&` members keep their ordinary block encoding inside the frame payload, so dynamic blocks are allowed there
96
- // - `+&` starts a block-stream tail inside the frame; fixed-layout `+` members may not follow it
97
- // - frames may be bundled like ordinary block items, but bundles/lists cannot be framed
98
- // - prime blocks of the same type should be grouped together so the prime run is contiguous
99
- // - primary / driving blocks should be the prime item; auxiliary batch-wide blocks should follow
100
- // as global `;` siblings
101
- // - `route(<fields...>)`, `item(<fields...>)`, `evm(<fields...>)`, `query(<fields...>)`,
102
- // and `response(<fields...>)` are reserved extensible schema forms whose keys are always
103
- // `Keys.Route`, `Keys.Item`, `Keys.Evm`, `Keys.Query`, and `Keys.Response` respectively
104
- // - these extensible forms work like dynamic `bytes` blocks: they may carry arbitrary
105
- // payload bytes while keeping one fixed key per semantic block type
106
- // - prefer `frame = ...`, `(fields...)`, and `+&` tails over `route(...)` and `item(...)` when the payload
107
- // can be described by the schema DSL; frames give off-chain tools typed layouts and better generated APIs
108
- // - `evm(<fields...>)` differs from bundle/list payloads: its bytes are not an embedded block stream
109
- // - `evm(uint foo, uint bar)` is a schema declaration only; on-chain the block key is still `Keys.Evm`
110
- // and the payload can be decoded from `bytes data` using the local runtime's native decoder
111
- // - on EVM, `evm(bool flag)` occupies one full 32-byte ABI word, exactly like `abi.encode(flag)`
112
- // - anonymous `&` compiles to a `Keys.Bundle` block whose self payload is the bundled member block stream
113
- // - anonymous `[]` compiles to a `Keys.List` block whose self payload is the repeated item block stream
114
- // - anonymous `+` compiles to a `Keys.Frame` block whose self payload is the framed member payload fields
115
- // - anonymous `+&` compiles to a `Keys.Frame` block whose self payload is fixed framed fields
116
- // followed by an embedded normal block-stream tail
117
- // - bare `(fields...)` compiles to a `Keys.Frame` block whose self payload is those fields
118
- // - named lists, bundles, and frames use bytes4(keccak256(bytes(rawSchemaInput))) as their block key
119
- // - named structural keys are custom/local identifiers, not global protocol keys; formatting is part of identity
120
- // - `payment: frame = amount(...) +& fee(...)` means an anonymous frame whose runtime key is still `Keys.Frame`,
121
- // with `payment` as its off-chain presentation name
122
- // - `quote: payment = amount(...) + fee(...)` means a named frame with presentation alias `quote`;
123
- // its local runtime key is derived from the full raw schema string including `quote:`
124
- // - `frame = debit: amount(...) + credit: amount(...)` means the two flattened amount groups should be
125
- // presented off-chain as `debit` and `credit`, while encoding remains the same as without aliases
126
- // - `frame = amount(...) + amount(...)` has the same encoding as the aliased form above, but off-chain tools
127
- // should present the groups as `amount0` and `amount1`
128
- // - `asset(...)[]` means a list whose repeated item is the block `asset(...)`
129
- // - `account(...)?` means an optional account block
130
- // - `steps[] = asset(...) & account(...)` means a named list whose repeated item is the bundle
131
- // `asset(...) & account(...)`
132
- // - `steps[]? = asset(...) & account(...)` means that named list may be absent
133
- // - `memo? = evm(bytes data)` means an optional named local item whose payload, when present, is EVM-encoded
134
- // - `payment = amount(...) + fee(...)` means a named frame whose payload is
135
- // `asset | meta | amount | fee` and whose on-chain key is derived from that raw schema string
136
- // - `payment = amount(...) + (uint fee, uint rate)` means a named frame whose payload is
137
- // `asset | meta | amount | fee | rate`, without inventing a child block name for the extra fields
138
- // - `payment = (uint fee, uint rate)` means a named frame whose payload is `fee | rate`
139
- // - `payment = amount(...) +& fee(...)` means a named frame whose payload is
140
- // `asset | meta | amount | [fee key | fee len | fee amount]`
141
- // - `payment = amount(...) +& fee(...)?` means a named frame with an amount prefix and optional fee block tail
142
- // - `payment = amount(...) +& list? = fee(...)` means a named frame with an amount prefix and
143
- // an optional anonymous list block tail
144
- // - `payment = amount(...)? + fee(...)` is invalid because `amount(...)` would be an optional flattened frame member
145
- // - `(uint fee)` means an anonymous frame with one `fee` field
146
- // - `(uint fee)[]` means a list of anonymous frames whose repeated item has one `fee` field
147
- // - `(uint fee)?` means an optional anonymous frame with one `fee` field
148
- // - `amount(...) & (uint fee)` means a bundle containing an amount block and an anonymous fee frame
149
- // - `amount(...) +& (uint fee)` is invalid because `+&` appends existing block-stream items, not field groups
150
- // - `amount(...) & fee(...) + account(...)` means `amount(...) & (fee(...) + account(...))`;
151
- // it compiles to a bundle containing one amount block followed by one frame block
152
- // - `amount(...) & fee(...) +& account(...)` means `amount(...) & (fee(...) +& account(...))`;
153
- // it compiles to a bundle containing one amount block followed by one frame block with an account block tail
154
- // - `bundle = account(...) & evm(bytes routeData)` means an anonymous child bundle with those bundled members
155
- // - `bundle? = account(...) & auth(...)` means that anonymous bundle may be absent
156
- // - `frame = amount(...) + fee(...)` means an anonymous child frame with those framed payload fields
157
- // - `frame? = amount(...) + fee(...)` means that anonymous frame may be absent
158
- // - `frame = amount(...) +& fee(...)` means an anonymous child frame with amount fields plus a fee block tail
159
- // - `list = asset(...) & account(...)` means an anonymous child list whose repeated item is the
160
- // bundle `asset(...) & account(...)`
161
- // - `list? = fee(...)` means that anonymous list may be absent
162
- // - `"amount(...) &"` and `"& amount(...)"` both normalize to a bundle containing one `amount(...)` child
163
- // - `"& account(...)?"` normalizes to a bundle containing one optional `account(...)` child
164
- // - `"amount(...) +"` and `"+ amount(...)"` both normalize to a frame containing one `amount(...)` payload
165
- // - `"amount(...) +&"` and `"+& amount(...)"` both normalize to a frame containing one `amount(...)` block
166
- // - `"+& account(...)?"` normalizes to a frame containing an optional `account(...)` block-stream tail
167
- // - `"amount(...)?"` normalizes to an optional amount block; `"amount(...)?[]"` is invalid
168
- // - canonical blocks are `amount(...)` for request amounts, `balance(...)` for state balances,
169
- // `allocation(...)` for host-scoped provision requests, `allowance(...)` for host-scoped caps,
170
- // `custody(...)` for host-scoped state,
171
- // `minimum(...)` for result floors, `maximum(...)` for spend ceilings, and `quantity(...)`
172
- // for plain scalar amounts
173
- // - `auth(uint cid, uint deadline, bytes proof)` is a proof-separator block and must be emitted last
9
+ // Schema:
10
+ // - blocks are written as `#name { fields }`
11
+ // - a block without braces has no payload, e.g. `#unit`
12
+ // - commas separate siblings at every level
13
+ // - braces define parent-child boundaries
14
+ // - top-level item 0 is the prime item; later top-level items are globals
15
+ // - prime items may repeat at top level for batching
16
+ // - `maybe #x { ... }` marks an optional block item
17
+ // - `many #x { ... }` emits one generic list block containing repeated `#x` items
18
+ // - fixed fields are packed in declaration order
19
+ // - blocks have fixed fields followed by a dynamic child-block tail
20
+ // - child block tails are embedded directly, without an extra stream wrapper
21
+ // - `#bytes` is a reserved child block that stores raw bytes and has no body
22
+ // - generic `#data` uses the stable key derived from `#data`
23
+ // - generic lists use the stable key derived from `#list`
24
+ // - keys are derived from block names, e.g. bytes4(keccak256("#amount"))
25
+ // - see `docs/Schema.md` for the full working spec
174
26
  //
175
27
  // Pipeline state:
176
28
  // - `balance(...)` and `custody(...)` are live, linear state in the active command pipeline
@@ -184,57 +36,52 @@ pragma solidity ^0.8.33;
184
36
  //
185
37
  // Signed blocks:
186
38
  // - an authenticated input segment ends with one trailing AUTH block
187
- // - auth is typically grouped with the signed payload in one bundle, with AUTH as the final member
188
39
  // - only the final AUTH is treated specially; earlier AUTH blocks remain ordinary signed bytes
189
40
  // - the signed slice runs from the segment start through the AUTH head, excluding only AUTH proof bytes
190
41
  // - `cid` binds the signature to one command; `deadline` acts as expiry and nonce
191
42
  // - current helpers assume proof layout `[bytes20 signer][bytes65 sig]`
192
43
 
193
44
  /// @title Schemas
194
- /// @notice Human-readable ABI-signature string constants for each block type.
195
- /// These strings are the canonical source from which `Keys` constants are derived
196
- /// and are used when emitting schema descriptors in command events.
45
+ /// @notice Human-readable schema string constants for each block type.
46
+ /// These strings describe payload layout for discovery events and docs; block
47
+ /// keys are derived only from block names.
197
48
  library Schemas {
198
- string constant Empty = "empty";
199
- string constant Node = "node(uint id)";
200
- string constant Account = "account(bytes32 account)";
201
- string constant Asset = "asset(bytes32 asset, bytes32 meta)";
202
- string constant Balance = "balance(bytes32 asset, bytes32 meta, uint amount)";
203
- string constant Amount = "amount(bytes32 asset, bytes32 meta, uint amount)";
204
- string constant Minimum = "minimum(bytes32 asset, bytes32 meta, uint amount)";
205
- string constant Maximum = "maximum(bytes32 asset, bytes32 meta, uint amount)";
206
- string constant Custody = "custody(uint host, bytes32 asset, bytes32 meta, uint amount)";
207
- string constant Payout = "payout(bytes32 account, bytes32 asset, bytes32 meta, uint amount)";
208
- string constant Allocation = "allocation(uint host, bytes32 asset, bytes32 meta, uint amount)";
209
- string constant Allowance = "allowance(uint host, bytes32 asset, bytes32 meta, uint amount)";
210
- string constant Transaction = "transaction(bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)";
211
- string constant Call = "call(uint target, uint value, bytes data)";
212
- string constant Step = "step(uint target, uint value, bytes request)";
213
- string constant Bounty = "bounty(uint amount, bytes32 relayer)";
214
- string constant Quantity = "quantity(uint amount)";
215
- string constant Fee = "fee(uint amount)";
216
- string constant Rate = "rate(uint value)";
217
- string constant Bounds = "bounds(int min, int max)";
218
- string constant Auth = "auth(uint cid, uint deadline, bytes proof)";
219
- string constant Route = "route(bytes data)";
220
- string constant Item = "item(bytes data)";
221
- string constant Evm = "evm(bytes data)";
222
- string constant Query = "query(bytes data)";
223
- string constant Response = "response(bytes data)";
224
- string constant Break = "break()";
49
+ string constant Unit = "#unit";
50
+ string constant Node = "#node { uint id }";
51
+ string constant Account = "#account { bytes32 account }";
52
+ string constant Asset = "#asset { bytes32 asset, bytes32 meta }";
53
+ string constant Balance = "#balance { bytes32 asset, bytes32 meta, uint amount }";
54
+ string constant Amount = "#amount { bytes32 asset, bytes32 meta, uint amount }";
55
+ string constant Minimum = "#minimum { bytes32 asset, bytes32 meta, uint amount }";
56
+ string constant Maximum = "#maximum { bytes32 asset, bytes32 meta, uint amount }";
57
+ string constant Custody = "#custody { uint host, bytes32 asset, bytes32 meta, uint amount }";
58
+ string constant Payout = "#payout { bytes32 account, bytes32 asset, bytes32 meta, uint amount }";
59
+ string constant Allocation = "#allocation { uint host, bytes32 asset, bytes32 meta, uint amount }";
60
+ string constant Allowance = "#allowance { uint host, bytes32 asset, bytes32 meta, uint amount }";
61
+ string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount }";
62
+ string constant Call = "#call { uint target, uint value, #bytes as payload }";
63
+ string constant Step = "#step { uint target, uint value, #bytes as request }";
64
+ string constant Context = "#context { bytes32 account, uint value, #bytes as state, #bytes as request }";
65
+ string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
66
+ string constant Fee = "#fee { uint amount }";
67
+ string constant Auth = "#auth { uint cid, uint deadline, #bytes as proof }";
68
+ string constant Bytes = "#bytes";
69
+ string constant Data = "#data";
70
+ string constant List = "#list";
71
+ string constant Evm = "#evm";
225
72
  }
226
73
 
227
74
  /// @title Forms
228
75
  /// @notice Reusable structural block schemas for core tuple shapes.
229
76
  /// These describe payload form without assigning command or query semantics.
230
77
  library Forms {
231
- string constant Status = "status(bool ok)";
232
- string constant AssetAmount = "assetAmount(bytes32 asset, bytes32 meta, uint amount)";
233
- string constant AccountAsset = "accountAsset(bytes32 account, bytes32 asset, bytes32 meta)";
234
- string constant AccountAmount = "accountAmount(bytes32 account, bytes32 asset, bytes32 meta, uint amount)";
235
- string constant HostAmount = "hostAmount(uint host, bytes32 asset, bytes32 meta, uint amount)";
236
- string constant HostAccountAsset = "hostAccountAsset(uint host, bytes32 account, bytes32 asset, bytes32 meta)";
237
- string constant HostAccountAmount = "hostAccountAmount(uint host, bytes32 account, bytes32 asset, bytes32 meta, uint amount)";
78
+ string constant Status = "#status { bool ok }";
79
+ string constant AssetAmount = "#assetAmount { bytes32 asset, bytes32 meta, uint amount }";
80
+ string constant AccountAsset = "#accountAsset { bytes32 account, bytes32 asset, bytes32 meta }";
81
+ string constant AccountAmount = "#accountAmount { bytes32 account, bytes32 asset, bytes32 meta, uint amount }";
82
+ string constant HostAmount = "#hostAmount { uint host, bytes32 asset, bytes32 meta, uint amount }";
83
+ string constant HostAccountAsset = "#hostAccountAsset { uint host, bytes32 account, bytes32 asset, bytes32 meta }";
84
+ string constant HostAccountAmount = "#hostAccountAmount { uint host, bytes32 account, bytes32 asset, bytes32 meta, uint amount }";
238
85
  }
239
86
 
240
87
  /// @title Sizes
@@ -256,14 +103,14 @@ library Sizes {
256
103
  uint constant B160 = Header + 5 * Word;
257
104
  /// @dev AUTH proof segment only: 20-byte signer + 65-byte signature = 85 bytes
258
105
  uint constant Proof = 85;
259
- /// @dev AUTH block: 8 header + 32 cid + 32 deadline + 85 proof = 157 bytes
260
- uint constant Auth = B64 + Proof;
106
+ /// @dev AUTH block: 8 header + 32 cid + 32 deadline + nested BYTES block with 85-byte proof = 165 bytes
107
+ uint constant Auth = B64 + Header + Proof;
108
+ /// @dev STATUS block: 8 header + 1 bool byte = 9 bytes
109
+ uint constant Status = Header + 1;
261
110
  /// @dev AMOUNT block: 8 header + 32 asset + 32 meta + 32 amount = 104 bytes
262
111
  uint constant Amount = B96;
263
112
  /// @dev BALANCE block: 8 header + 32 asset + 32 meta + 32 amount = 104 bytes
264
113
  uint constant Balance = B96;
265
- /// @dev BOUNDS block: 8 header + 32 min + 32 max = 72 bytes
266
- uint constant Bounds = B64;
267
114
  /// @dev FEE block: 8 header + 32 amount = 40 bytes
268
115
  uint constant Fee = B32;
269
116
  /// @dev BOUNTY block: 8 header + 32 amount + 32 relayer = 72 bytes