@rootzero/contracts 1.21.0 → 1.23.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 (54) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/Endpoints.sol +2 -3
  3. package/Events.sol +1 -1
  4. package/README.md +25 -19
  5. package/annotations/Action.sol +1 -1
  6. package/annotations/Label.sol +1 -1
  7. package/annotations/Schema.sol +36 -3
  8. package/codec/Blocks.sol +100 -29
  9. package/codec/Decoders.sol +62 -8
  10. package/codec/Readers.sol +39 -0
  11. package/codec/Schema.sol +44 -35
  12. package/codec/Writers.sol +8 -0
  13. package/commands/Allocate.sol +5 -8
  14. package/commands/Base.sol +29 -13
  15. package/commands/Burn.sol +5 -7
  16. package/commands/Credit.sol +5 -7
  17. package/commands/Debit.sol +5 -7
  18. package/commands/Deposit.sol +10 -14
  19. package/commands/Payout.sol +5 -8
  20. package/commands/Provision.sol +10 -14
  21. package/commands/Recover.sol +4 -6
  22. package/commands/Relay.sol +16 -22
  23. package/commands/Repay.sol +10 -14
  24. package/commands/Settle.sol +10 -14
  25. package/commands/Withdraw.sol +5 -7
  26. package/commands/admin/AllowAssets.sol +5 -7
  27. package/commands/admin/Allowance.sol +5 -7
  28. package/commands/admin/Annotate.sol +5 -7
  29. package/commands/admin/Appoint.sol +5 -7
  30. package/commands/admin/Authorize.sol +5 -7
  31. package/commands/admin/Base.sol +12 -3
  32. package/commands/admin/DenyAssets.sol +5 -7
  33. package/commands/admin/Dismiss.sol +5 -7
  34. package/commands/admin/Execute.sol +5 -7
  35. package/commands/admin/Unauthorize.sol +5 -7
  36. package/core/Calls.sol +72 -3
  37. package/core/Host.sol +7 -10
  38. package/core/Portal.sol +2 -2
  39. package/events/Dispatch.sol +1 -1
  40. package/events/Positioned.sol +22 -0
  41. package/events/Relay.sol +1 -1
  42. package/events/Route.sol +1 -1
  43. package/execution/Execution.sol +124 -4
  44. package/package.json +2 -3
  45. package/ports/Allowance.sol +22 -12
  46. package/ports/Assets.sol +99 -0
  47. package/ports/Dispatch.sol +2 -1
  48. package/utils/Cursors.sol +3 -3
  49. package/utils/Nodes.sol +1 -1
  50. package/utils/Utils.sol +31 -31
  51. package/docs/Schema.md +0 -427
  52. package/events/Commander.sol +0 -19
  53. package/ports/AllowAssets.sol +0 -34
  54. package/ports/DenyAssets.sol +0 -34
package/CHANGELOG.md CHANGED
@@ -3,6 +3,131 @@
3
3
  Until the protocol reaches integration-stable status, minor versions may include
4
4
  breaking API changes. Breaking changes are called out explicitly.
5
5
 
6
+ ## 1.23.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - Changed every command entrypoint from
11
+ `(bytes32 account, bytes state, bytes input)` to one `bytes context` argument
12
+ containing exactly one encoded `CONTEXT` block. Canonical command selectors
13
+ now use `(bytes)`, so every command node ID changes. Existing command callers,
14
+ cached IDs, and deployed host graphs are not compatible with this release.
15
+ - Added the acting account to `Execution`. `CommandBase.openCommand` and
16
+ `AdminBase.openAdminCommand` now accept the encoded context and return only
17
+ the initialized execution, and command implementations close with
18
+ `closeCommand(exec)` instead of `close(exec, account)`.
19
+ - Removed the separate state argument from `RelayPayableHook.relay`. Relay
20
+ implementations can obtain the complete validated state with
21
+ `exec.rawState()` while the explicit account and nested relay input arguments
22
+ remain unchanged.
23
+ - Consolidated `AllowAssetsPort` and `DenyAssetsPort` into
24
+ `ports/Assets.sol`; update direct source imports to the new path.
25
+ - Renamed the peer `AllowancePort` and `portAllowance` selector to
26
+ `RequestAllowancePort` and `portRequestAllowance`. The peer port now uses a
27
+ distinct `RequestAllowanceHook.requestAllowance` hook; the admin `Allowance`
28
+ command and its authoritative `AllowanceHook.allowance` hook are unchanged.
29
+ - Removed the `Commander` event declaration. Commander addresses and chain
30
+ context are off-chain configuration; host, native-asset, and admin IDs are
31
+ deterministic from that information.
32
+ - Prefixed every typed `Blocks` factory with `create`, including calldata-copy
33
+ variants; for example, use `createBalance`, `createStepCopy`, `createBytes`,
34
+ and `createString` instead of `balance`, `stepCopy`, `data`, and `text`.
35
+ - Changed the `max8`, `max16`, `max24`, `max32`, `max40`, `max64`, `max96`,
36
+ `max128`, and `max160` bounds helpers to return their corresponding narrowed
37
+ integer types instead of `uint`.
38
+
39
+ ### Added
40
+
41
+ - Added `PositionedEvent`, which publishes asset and liability sides together
42
+ with the semantic action that produced the observed position.
43
+ - Added `RequestAssetPort`, which passes trusted peers' batched asset and amount
44
+ requests to a host hook for validation and fulfillment.
45
+ - Added `Executions.takeBlock`, which validates and consumes a block from a
46
+ selected decoder lane and returns its complete calldata encoding.
47
+ - Added `Executions.rawState` and `Executions.rawInput` for retrieving complete
48
+ validated calldata lanes independently of current cursor progress.
49
+ - Added `Blocks.createAmount` for constructing canonical `AMOUNT` blocks.
50
+
51
+ ### Changed
52
+
53
+ - Command pipeline hops now construct `command(bytes)` calldata and the nested
54
+ `CONTEXT` block directly in one allocation, copying memory state and calldata
55
+ input into the final call buffer.
56
+ - Added memory `callPort`/`tryCallPort` helpers and calldata-copy
57
+ `callPortCopy`/`tryCallPortCopy` counterparts, matching the block factory
58
+ naming convention. Portal forwarding and recovery use the copy variants.
59
+
60
+ ### Upgrade Compatibility
61
+
62
+ - Rebuild command IDs from the new `(bytes)` selectors, redeploy command hosts,
63
+ and update pipeline builders and other callers to pass one encoded `CONTEXT`
64
+ block. Do not mix 1.22 command IDs or callers with 1.23 deployments.
65
+ - Update custom commands to read the acting account from `exec.account`, use
66
+ `openCommand(context, descriptor, batches)`, and return
67
+ `closeCommand(exec)`.
68
+ - Update relay hook implementations to remove the state parameter and use
69
+ `exec.rawState()` when the forwarded state is required.
70
+ - Update direct port imports, renamed request-allowance endpoints and hooks,
71
+ typed `Blocks` factory calls, and any assignments that relied on `max*`
72
+ returning `uint`.
73
+
74
+ ## 1.22.0
75
+
76
+ ### Breaking Changes
77
+
78
+ - Declared child blocks are now structurally present whenever their parent is
79
+ non-empty. A child without a value uses its zero-payload block form instead
80
+ of being omitted. The `maybe` modifier now hints that onchain code accepts
81
+ that empty form; it no longer describes an absent item. Lists likewise keep
82
+ their header and represent no items with an empty payload.
83
+ - Removed `Schemas.Unit`. Use the empty form of the block key that carries the
84
+ relevant semantic meaning instead of a generic unit marker.
85
+ - Renamed `Decoders.take(cur, key)` to `takeBlock(cur, key)`. The `take` name is
86
+ now used by raw cursor navigation and returns the absolute start of a
87
+ bounds-checked byte range while advancing the cursor.
88
+ - Normalized standard schema bodies by removing their presentation-only outer
89
+ braces, and renamed the standard node field from `id` to `node`. Published
90
+ schema annotation bytes therefore change even though their wire layouts do
91
+ not.
92
+
93
+ ### Added
94
+
95
+ - Added empty-block inspection, conditional consumption, encoding, writing,
96
+ and execution-output helpers across `Blocks`, `Decoders`, `Readers`,
97
+ `Writers`, and `Executions`.
98
+ - Added `absolute`, `advance`, and raw `take` cursor helpers, plus `enter`
99
+ overloads that advance over a validated fixed payload prefix in one cursor
100
+ update.
101
+ - Added unnamed `schema` overloads for context-local specifications and an
102
+ unnamed `Blocks.schema` factory overload.
103
+ - Added the offchain-only `at N` schema projection hint. Explicit positions are
104
+ reserved first, then unannotated siblings fill the remaining positions in
105
+ declaration order; wire encoding and onchain decoding remain unchanged.
106
+
107
+ ### Changed
108
+
109
+ - Clarified that one optional pair of outer braces is presentation-only for all
110
+ non-empty schema bodies, including custom top-level `many` schemas.
111
+ - Updated custom input examples to group fixed-width fields for direct calldata
112
+ reads, demonstrate empty child blocks, and separate top-level and nested swap
113
+ decoding.
114
+ - Excluded repository documentation and examples from the prepared npm package;
115
+ the package continues to contain Solidity sources, the README, changelog, and
116
+ license.
117
+
118
+ ### Upgrade Compatibility
119
+
120
+ - Emit every declared child header in schema order. When a `maybe` child has no
121
+ value, emit that child's key with a zero payload length and call
122
+ `tryConsumeEmpty` before its strict semantic unpacker.
123
+ - Replace `Schemas.Unit` markers with an empty block carrying the key expected
124
+ by the receiving schema.
125
+ - Replace `cur.take(key)` with `cur.takeBlock(key)`. Use `cur.take(amount)` only
126
+ for raw fixed-width ranges.
127
+ - Indexers should accept braced and unbraced schema bodies, treat `maybe` as an
128
+ empty-value hint, and apply `at N` only after decoding declaration-order wire
129
+ data.
130
+
6
131
  ## 1.21.0
7
132
 
8
133
  ### Breaking Changes
package/Endpoints.sol CHANGED
@@ -37,12 +37,11 @@ import {Unauthorize} from "./commands/admin/Unauthorize.sol";
37
37
 
38
38
  // Port endpoints
39
39
  import {PortBase} from "./ports/Base.sol";
40
- import {AllowAssetsPort} from "./ports/AllowAssets.sol";
41
- import {AllowancePort} from "./ports/Allowance.sol";
40
+ import {AllowAssetsPort, DenyAssetsPort, RequestAssetPort, RequestAssetHook} from "./ports/Assets.sol";
41
+ import {RequestAllowancePort, RequestAllowanceHook} from "./ports/Allowance.sol";
42
42
  import {RedeemBalancePort, RedeemBalanceHook} from "./ports/Redeem.sol";
43
43
  import {CreditAccountPort} from "./ports/Credit.sol";
44
44
  import {DebitAccountPort} from "./ports/Debit.sol";
45
- import {DenyAssetsPort} from "./ports/DenyAssets.sol";
46
45
  import {PipePayablePort} from "./ports/Pipe.sol";
47
46
  import {DispatchPayablePort, DispatchPayableHook} from "./ports/Dispatch.sol";
48
47
  import {PostPort} from "./ports/Post.sol";
package/Events.sol CHANGED
@@ -8,7 +8,6 @@ import { AnnotationEvent } from "./events/Annotation.sol";
8
8
  import { AssetEvent, AssetStatusEvent } from "./events/Asset.sol";
9
9
  import { Actions } from "./utils/Actions.sol";
10
10
  import { BalanceEvent } from "./events/Balance.sol";
11
- import { CommanderEvent } from "./events/Commander.sol";
12
11
  import { DispatchEvent } from "./events/Dispatch.sol";
13
12
  import { EndpointEvent } from "./events/Endpoint.sol";
14
13
  import { ReceivedEvent } from "./events/Received.sol";
@@ -19,6 +18,7 @@ import { GuardianEvent } from "./events/Guardian.sol";
19
18
  import { IntroductionEvent } from "./events/Introduction.sol";
20
19
  import { LockedEvent } from "./events/Locked.sol";
21
20
  import { NodeEvent } from "./events/Node.sol";
21
+ import { PositionedEvent } from "./events/Positioned.sol";
22
22
  import { RootedEvent } from "./events/Rooted.sol";
23
23
  import { RouteEvent } from "./events/Route.sol";
24
24
  import { SpentEvent } from "./events/Spent.sol";
package/README.md CHANGED
@@ -114,16 +114,20 @@ identifiers inside, never how the bytes are laid out.
114
114
 
115
115
  Schemas can express more than flat fields: a block may contain any number of
116
116
  nested child blocks (`#bytes as payload` names raw dynamic bytes), items can be
117
- marked `maybe` (optional) or `many` (a list), and aliases and dotted field
118
- paths give off-chain tooling presentation names without changing a single byte
119
- on the wire. The full schema language is specified in
120
- [`docs/Schema.md`](docs/Schema.md). The standard block schemas live in
117
+ marked `maybe` when their empty form is accepted or `many` when they form a
118
+ list, and aliases and dotted field paths give off-chain tooling presentation
119
+ names without changing a single byte on the wire. Declared child headers are
120
+ always present; a zero payload length represents an empty block. An `at N` hint
121
+ can reposition one field in off-chain presentation without changing its wire
122
+ position. The full schema language is specified in
123
+ [`docs/Schema.md`](https://github.com/lastqubit/rootzero-evm/blob/main/docs/Schema.md). The standard block schemas live in
121
124
  `Schemas` and their runtime keys in `Keys` (both via
122
125
  `@rootzero/contracts/Codec.sol`).
123
126
 
124
- A rare top-level list is published as a custom schema such as `many #asset`.
125
- Its context-local schema key becomes the outer block key accepted by the
126
- endpoint; nested lists continue to use the generic `#list` key.
127
+ A rare top-level list is published as a custom schema consisting of one item,
128
+ such as `many #asset` or `{ many #asset }`. Its context-local schema key becomes
129
+ the outer block key accepted by the endpoint; a list alongside sibling items
130
+ continues to use the generic `#list` key.
127
131
 
128
132
  ## Batches
129
133
 
@@ -284,19 +288,17 @@ command lanes, loop the batch, call the hook, and write the output run:
284
288
 
285
289
  ```solidity
286
290
  function deposit(
287
- bytes32 account,
288
- bytes calldata state,
289
- bytes calldata input
291
+ bytes calldata context
290
292
  ) external onlyCommand returns (bytes memory, bytes memory) {
291
- Execution memory exec = openCommand(state, input, descriptor, 0);
293
+ Execution memory exec = openCommand(context, descriptor, 0);
292
294
 
293
295
  while (exec.more()) {
294
296
  (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
295
- deposit(account, asset, amount); // host policy hook
297
+ deposit(exec.account, asset, amount); // host policy hook
296
298
  exec.outputBalance(asset, amount);
297
299
  }
298
300
 
299
- return close(exec, account);
301
+ return closeCommand(exec);
300
302
  }
301
303
  ```
302
304
 
@@ -313,17 +315,15 @@ abstract contract MyCommand is CommandBase {
313
315
  }
314
316
 
315
317
  function myCommand(
316
- bytes32 account,
317
- bytes calldata state,
318
- bytes calldata input
318
+ bytes calldata context
319
319
  ) external onlyCommand returns (bytes memory, bytes memory) {
320
- Execution memory exec = openCommand(state, input, descriptor, 0);
320
+ Execution memory exec = openCommand(context, descriptor, 0);
321
321
  while (exec.more()) {
322
322
  (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
323
323
  // Apply command-specific behavior for this group.
324
324
  exec.outputBalance(asset, amount);
325
325
  }
326
- return close(exec, account);
326
+ return closeCommand(exec);
327
327
  }
328
328
  }
329
329
  ```
@@ -431,6 +431,12 @@ central ones are batches all the way down:
431
431
  - `portPost` consumes `transaction { bytes32 from, bytes32 to, bytes32 asset,
432
432
  uint amount }` blocks, debiting `from` and crediting `to` per
433
433
  block — how two hosts post transactions between their ledgers.
434
+ - `portRequestAsset` consumes `amount { bytes32 asset, uint amount }` blocks and
435
+ passes the authenticated peer, asset, and amount to a host hook. The hook
436
+ validates asset support and applies the host's request and transfer policy.
437
+ - `portRequestAllowance` consumes the same amount blocks and lets the
438
+ authenticated peer request an asset allowance. The hook decides what
439
+ allowance, if any, to grant.
434
440
  - `portPipePayable` consumes `context` blocks, each carrying an account, an
435
441
  initial state, and a run of steps — a complete pipeline delivered by another
436
442
  host, executed locally against the port call's shared value budget.
@@ -492,7 +498,7 @@ Repo layout:
492
498
  - `contracts/blocks` — block schema, cursor parsing, writers
493
499
  - `contracts/utils` — ids, nodes, assets, accounts, layout, ECDSA
494
500
  - `contracts/events` — event contracts and emitters
495
- - `docs` — [`Schema.md`](docs/Schema.md) (wire format and schema DSL)
501
+ - `docs` — [`Schema.md`](https://github.com/lastqubit/rootzero-evm/blob/main/docs/Schema.md) (wire format and schema DSL)
496
502
 
497
503
  Use this library to create a new rootzero host, implement a command, or reuse
498
504
  the protocol's block format in tooling. It is the shared protocol foundation,
@@ -12,6 +12,6 @@ abstract contract Action is AnnotationEvent {
12
12
  /// @param entity Entity receiving the action annotation.
13
13
  /// @param value Canonical action identifier, such as a value from `Actions`.
14
14
  function action(uint entity, uint value) internal virtual {
15
- emit Annotation(entity, Blocks.action(value));
15
+ emit Annotation(entity, Blocks.createAction(value));
16
16
  }
17
17
  }
@@ -14,6 +14,6 @@ abstract contract Label is AnnotationEvent {
14
14
  /// @param namespace Label namespace.
15
15
  /// @param name Human-readable name within the namespace.
16
16
  function label(uint entity, bytes32 namespace, string memory name) internal virtual {
17
- emit Annotation(entity, Blocks.label(namespace, name));
17
+ emit Annotation(entity, Blocks.createLabel(namespace, name));
18
18
  }
19
19
  }
@@ -11,6 +11,23 @@ import {Runtime} from "../core/Runtime.sol";
11
11
  /// @dev Schema annotations accumulate for distinct block keys. For a trusted
12
12
  /// emitter, the latest schema for the same block key replaces the earlier claim.
13
13
  abstract contract Schema is Runtime, AnnotationEvent {
14
+ /// @notice Construct and publish an unnamed context-local block specification.
15
+ /// @param key Context-local key value.
16
+ /// @param min Minimum accepted payload length.
17
+ /// @param max Maximum accepted payload length; zero means unbounded.
18
+ /// @param hint Initial per-block payload capacity.
19
+ /// @param body Schema DSL string describing the block payload body.
20
+ /// @return spec The context-local block specification.
21
+ function schema(
22
+ uint32 key,
23
+ uint32 min,
24
+ uint32 max,
25
+ uint32 hint,
26
+ string memory body
27
+ ) internal returns (uint spec) {
28
+ return schema(key, min, max, hint, body, bytes32(0));
29
+ }
30
+
14
31
  /// @notice Construct and publish a context-local block specification.
15
32
  /// @param key Context-local key value.
16
33
  /// @param min Minimum accepted payload length.
@@ -27,8 +44,16 @@ abstract contract Schema is Runtime, AnnotationEvent {
27
44
  string memory body,
28
45
  bytes32 name
29
46
  ) internal returns (uint spec) {
30
- spec = Specs.create(key, min, max, hint);
31
- return schema(spec, body, name);
47
+ return schema(Specs.create(key, min, max, hint), body, name);
48
+ }
49
+
50
+ /// @notice Construct and publish an unnamed exact-size context-local block specification.
51
+ /// @param key Context-local key value.
52
+ /// @param size Exact payload length and initial per-block payload capacity.
53
+ /// @param body Schema DSL string describing the block payload body.
54
+ /// @return spec The context-local block specification.
55
+ function schema(uint32 key, uint32 size, string memory body) internal returns (uint spec) {
56
+ return schema(key, size, body, bytes32(0));
32
57
  }
33
58
 
34
59
  /// @notice Construct and publish an exact-size context-local block specification.
@@ -41,13 +66,21 @@ abstract contract Schema is Runtime, AnnotationEvent {
41
66
  return schema(Specs.create(key, size), body, name);
42
67
  }
43
68
 
69
+ /// @notice Publish an unnamed, already constructed block specification for the current host.
70
+ /// @param spec Packed block specification.
71
+ /// @param body Schema DSL string describing the block payload body.
72
+ /// @return The published block specification.
73
+ function schema(uint spec, string memory body) internal returns (uint) {
74
+ return schema(spec, body, bytes32(0));
75
+ }
76
+
44
77
  /// @notice Publish an already constructed block specification for the current host.
45
78
  /// @param spec Packed block specification.
46
79
  /// @param body Schema DSL string describing the block payload body.
47
80
  /// @param name Schema alias name, or zero for unnamed schemas.
48
81
  /// @return The published block specification.
49
82
  function schema(uint spec, string memory body, bytes32 name) internal returns (uint) {
50
- emit Annotation(host, Blocks.schema(spec, body, name));
83
+ emit Annotation(host, Blocks.createSchema(spec, body, name));
51
84
  return spec;
52
85
  }
53
86
  }