@rootzero/contracts 1.12.0 → 1.14.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 (76) hide show
  1. package/CHANGELOG.md +76 -8
  2. package/Codec.sol +21 -0
  3. package/Commands.sol +14 -0
  4. package/Core.sol +4 -4
  5. package/Endpoints.sol +5 -7
  6. package/README.md +62 -35
  7. package/Utils.sol +2 -4
  8. package/codec/Blocks.sol +1606 -0
  9. package/codec/Buffers.sol +165 -0
  10. package/codec/Decoders.sol +558 -0
  11. package/codec/Descriptors.sol +124 -0
  12. package/{blocks → codec}/Keys.sol +4 -28
  13. package/codec/Readers.sol +114 -0
  14. package/{blocks → codec}/Schema.sol +38 -80
  15. package/codec/Specs.sol +218 -0
  16. package/codec/Writers.sol +487 -0
  17. package/commands/Allocate.sol +50 -0
  18. package/commands/Base.sol +71 -37
  19. package/commands/Burn.sol +19 -13
  20. package/commands/Credit.sol +25 -31
  21. package/commands/Debit.sol +28 -38
  22. package/commands/Deposit.sol +39 -39
  23. package/commands/Payout.sol +22 -15
  24. package/commands/Provision.sol +40 -40
  25. package/commands/Recover.sol +21 -20
  26. package/commands/Relay.sol +25 -23
  27. package/commands/Withdraw.sol +18 -20
  28. package/commands/admin/AllowAssets.sol +20 -16
  29. package/commands/admin/Allowance.sol +19 -13
  30. package/commands/admin/Appoint.sol +18 -15
  31. package/commands/admin/Authorize.sol +24 -14
  32. package/commands/admin/Base.sol +1 -1
  33. package/commands/admin/DenyAssets.sol +20 -16
  34. package/commands/admin/Dismiss.sol +18 -15
  35. package/commands/admin/Execute.sol +20 -18
  36. package/commands/admin/Label.sol +18 -13
  37. package/commands/admin/Schemas.sol +19 -14
  38. package/commands/admin/Unauthorize.sol +24 -14
  39. package/core/Calls.sol +7 -14
  40. package/core/Endpoint.sol +43 -126
  41. package/core/Host.sol +10 -2
  42. package/core/Pipeline.sol +29 -25
  43. package/core/Settlement.sol +39 -0
  44. package/core/Types.sol +1 -1
  45. package/docs/Schema.md +38 -32
  46. package/events/Endpoint.sol +2 -2
  47. package/events/Introduction.sol +4 -3
  48. package/events/Schema.sol +5 -5
  49. package/execution/Budget.sol +40 -0
  50. package/execution/Execution.sol +1083 -0
  51. package/guards/Base.sol +8 -9
  52. package/guards/Revoke.sol +11 -9
  53. package/package.json +1 -1
  54. package/ports/AllowAssets.sol +12 -15
  55. package/ports/Allowance.sol +11 -9
  56. package/ports/Base.sol +18 -11
  57. package/ports/Credit.sol +11 -9
  58. package/ports/Debit.sol +11 -9
  59. package/ports/DenyAssets.sol +10 -13
  60. package/ports/Dispatch.sol +13 -15
  61. package/ports/Pipe.sol +14 -12
  62. package/ports/Redeem.sol +12 -9
  63. package/ports/Settle.sol +13 -13
  64. package/queries/Assets.sol +15 -15
  65. package/queries/Balances.sol +17 -17
  66. package/queries/Base.sol +11 -12
  67. package/utils/Actions.sol +1 -0
  68. package/utils/Cursors.sol +308 -0
  69. package/utils/Lanes.sol +14 -0
  70. package/utils/Selectors.sol +2 -2
  71. package/utils/Utils.sol +46 -0
  72. package/Cursors.sol +0 -16
  73. package/blocks/Cursors.sol +0 -1400
  74. package/blocks/Writers.sol +0 -1028
  75. package/core/Payable.sol +0 -53
  76. package/utils/Value.sol +0 -43
package/CHANGELOG.md CHANGED
@@ -3,21 +3,89 @@
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.14.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - Replaced `CommandContext` and the separate payable value lifecycle with the
11
+ unified `Execution` context. Endpoint and command implementations now open an
12
+ execution directly from calldata, use its packed decoder and writer lanes,
13
+ and finish through the shared `close` helpers.
14
+ - Reworked the block codec around absolute-position `Blocks` primitives,
15
+ packed `Cursors`, cursor-backed `Decoders`, lazy `Buffers`, and thin
16
+ `Writers`. Several low-level cursor and writer APIs were renamed or removed.
17
+ - Redefined block specs and endpoint descriptors. Specs now encode key, minimum,
18
+ maximum, allocation hint, stride, and optional LIST container metadata;
19
+ descriptors use normalized lane specs and include a transaction stride.
20
+ - Replaced the `Cursors.sol` package entry point with `Codec.sol`, added the
21
+ command-authoring `Commands.sol` entry point, and reorganized exports across
22
+ the package barrels.
23
+ - Endpoint selectors are now derived from endpoint names. The configured name
24
+ must match the implementing function name, and descriptor values are
25
+ represented as `uint` throughout.
26
+ - Removed the AUTH and BOUNTY codec blocks, the obsolete `Payable`/`Values`
27
+ helpers, and superseded decoder, writer, schema, and descriptor overloads.
28
+
29
+ ### Added
30
+
31
+ - Added packed output and transaction writer lanes to `Execution`, including
32
+ semantic output helpers, queued credit/debit transactions, budget refunds,
33
+ and direct transaction finalization.
34
+ - Added detachable `Budget` values for pipeline-style consumers, shared lane
35
+ identifiers, spec-driven writer allocation, and optimized semantic block
36
+ readers, writers, and composite unpackers.
37
+ - Added a transaction-output example, command and codec barrel import examples,
38
+ and expanded coverage for packed cursors, buffers, descriptors, budgets,
39
+ execution output, and command flows.
40
+
41
+ ### Changed
42
+
43
+ - Standardized command, query, guard, and port implementations on the same
44
+ execution open/close lifecycle and renamed request terminology to input.
45
+ - Expanded NatSpec across the new execution and codec APIs and refreshed the
46
+ protocol, schema, indexing, and multi-chain documentation.
47
+
48
+ ## 1.13.0
49
+
50
+ ### Breaking Changes
51
+
52
+ - Replaced the virtual `Pipeline.settle(bytes transactions)` stream hook with
53
+ decoded settlement through `Settlement`. Pipeline implementations now provide
54
+ `debitAccount` and `creditAccount` hooks, while the pipeline decodes each
55
+ returned TRANSACTION block and settles it before dispatching the next step.
56
+ - Moved `DebitAccountHook` and `CreditAccountHook` from their command modules to
57
+ `core/Settlement.sol`. They remain available from the `Core.sol` and
58
+ `Endpoints.sol` package entry points.
59
+
60
+ ### Added
61
+
62
+ - Added the memory-backed `Reader` and `Readers` block-stream API with balance
63
+ and transaction unpackers, bounds and block validation, and positive
64
+ iteration through `more()`.
65
+ - Added the shared `Settlement` core mixin used by pipelines and `PortSettle` to
66
+ debit transaction sources and credit destinations.
67
+
68
+ ### Changed
69
+
70
+ - Unified pipeline and port transaction handling through `Settlement`,
71
+ including zero-account handling and zero-amount no-op settlement.
72
+
6
73
  ## 1.12.0
7
74
 
8
75
  ### Breaking Changes
9
76
 
10
- - Removed the generic `EndpointBase.schema(...)` helper. Use
11
- `localSchema(...)` for context-local endpoint schemas or emit `Schema`
12
- directly for custom/named keys.
77
+ - Removed `Keys.Local` and replaced `EndpointBase.localSchema(...)` with the
78
+ explicit `EndpointBase.schema(uint32 key, string body)` helper for
79
+ context-local endpoint schemas.
80
+ - Changed `Introduction` to emit the receiving `host` and introduced `peer`:
81
+ `Introduction(uint indexed host, uint peer, uint blocknum)`.
13
82
  - Replaced `isDebitAccount`, `isCreditAccount`, `isAuthorize`, and
14
83
  `isUnauthorize` helper predicates with internal command ID fields:
15
84
  `debitAccountId`, `creditAccountId`, `authorizeId`, and `unauthorizeId`.
16
85
 
17
86
  ### Added
18
87
 
19
- - Added `Keys.Local` as the default context-local block key and added
20
- `EndpointBase.localSchema(...)` helpers for publishing local endpoint
88
+ - Added the `EndpointBase.schema(...)` helper for publishing local endpoint
21
89
  schemas.
22
90
  - Added the standard `#schema` block, `unpackSchema`, and an opt-in
23
91
  `publishSchema` admin command for emitting schema claims from `#schema`
@@ -62,7 +130,7 @@ breaking API changes. Breaking changes are called out explicitly.
62
130
  - Portal no longer emits `Recovered` when retrying an undelivered witness.
63
131
  - Renamed `Cursors.exit` to `ensureAt` and renamed its position argument to
64
132
  `pos`.
65
- - Removed the redundant `next` return value from both `Cursors.init` overloads;
133
+ - Removed the redundant `next` return value from both `Decoders.init` overloads;
66
134
  callers should use the returned cursor's `len` as the run boundary.
67
135
  - Changed `Cursors.list` to require the expected current cursor position as
68
136
  `pos` before entering the LIST block.
@@ -137,7 +205,7 @@ breaking API changes. Breaking changes are called out explicitly.
137
205
  as the discovery/event surface for dispatch tracking.
138
206
  - Added `ContextRecovery` schema/cursor support and context schema aliases for
139
207
  reusable nested block schemas.
140
- - Added `Values.drain`, `Payable.openValue`, and `Payable.closeValue` to make
208
+ - Added `Values.drain`, `Payable.openValue`, and `Payable.end` to make
141
209
  payable command budget lifecycles explicit.
142
210
 
143
211
  ## 1.6.0
@@ -197,7 +265,7 @@ breaking API changes. Breaking changes are called out explicitly.
197
265
 
198
266
  ### Breaking Changes
199
267
 
200
- - Simplified `Cursors.init` to parse a single run from the start of a calldata slice. Callers that previously passed an offset must slice first or use `Cursors.open(source, i)`.
268
+ - Simplified `Decoders.init` to parse a single run from the start of a calldata slice. Callers that previously passed an offset must slice first or use `Decoders.open(source, i)`.
201
269
  - Tightened command, query, and peer request parsing around the single-run convention used by current protocol endpoints.
202
270
 
203
271
  ### Added
package/Codec.sol ADDED
@@ -0,0 +1,21 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ // Aggregator: re-exports the complete block encoding and decoding surface.
5
+ // Import this file for low-level codec extensions and direct stream processing.
6
+
7
+ import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
8
+ import { Keys } from "./codec/Keys.sol";
9
+ import { Sizes, Specs } from "./codec/Specs.sol";
10
+ import { Descriptors } from "./codec/Descriptors.sol";
11
+ import { Schemas } from "./codec/Schema.sol";
12
+ import { Decoders } from "./codec/Decoders.sol";
13
+ import { Cursors, Cur } from "./utils/Cursors.sol";
14
+ import { Readers, Reader } from "./codec/Readers.sol";
15
+ import { Blocks } from "./codec/Blocks.sol";
16
+ import { Buffers } from "./codec/Buffers.sol";
17
+ import { Writer, Writers } from "./codec/Writers.sol";
18
+
19
+
20
+
21
+
package/Commands.sol ADDED
@@ -0,0 +1,14 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ // Aggregator: re-exports the types and helpers needed to author commands.
5
+ // Import this file for both standard Execution-based commands and custom decoders.
6
+
7
+ import {CommandBase} from "./commands/Base.sol";
8
+ import {Execution, Executions} from "./execution/Execution.sol";
9
+ import {Lanes} from "./utils/Lanes.sol";
10
+ import {Blocks} from "./codec/Blocks.sol";
11
+ import {Sizes, Specs} from "./codec/Specs.sol";
12
+ import {Decoders} from "./codec/Decoders.sol";
13
+ import {Cursors, Cur} from "./utils/Cursors.sol";
14
+ import {AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx} from "./core/Types.sol";
package/Core.sol CHANGED
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- // Aggregator: re-exports the core host, runtime, access, ledger, node-call, and validation layer.
4
+ // Aggregator: re-exports the core host, runtime, access, ledger, settlement, pipeline, node-call, and validation layer.
5
5
  // Import this file to bring the full rootzero host base layer into scope.
6
6
 
7
7
  import { AccessControl } from "./core/Access.sol";
@@ -10,11 +10,11 @@ import { Escrows, InsufficientEscrow } from "./core/Escrows.sol";
10
10
  import { NativeAsset, Runtime } from "./core/Runtime.sol";
11
11
  import { Host, IHostIntroduction } from "./core/Host.sol";
12
12
  import { CommandCalls, FailedCall, NodeCalls, PortCalls } from "./core/Calls.sol";
13
- import { EndpointBase, Lane } from "./core/Endpoint.sol";
14
- import { Payable } from "./core/Payable.sol";
13
+ import { EndpointBase } from "./core/Endpoint.sol";
15
14
  import { Pipeline } from "./core/Pipeline.sol";
15
+ import { Budget, Budgets } from "./execution/Budget.sol";
16
+ import { CreditAccountHook, DebitAccountHook, Settlement } from "./core/Settlement.sol";
16
17
  import { Portal } from "./core/Portal.sol";
17
- import { RecoverHook } from "./commands/Recover.sol";
18
18
  import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
19
19
  import { Validator } from "./core/Validator.sol";
20
20
 
package/Endpoints.sol CHANGED
@@ -4,16 +4,14 @@ pragma solidity ^0.8.33;
4
4
  // Aggregator: re-exports command, admin, port, guard, and query endpoint abstractions.
5
5
  // Import this file to inherit from the full rootzero callable host surface without managing individual paths.
6
6
 
7
- // Shared helpers
8
- import { Keys } from "./blocks/Keys.sol";
9
- import { CommandBase, CommandContext } from "./commands/Base.sol";
10
- import { EndpointBase, Lane } from "./core/Endpoint.sol";
11
- import { Payable } from "./core/Payable.sol";
7
+ // Shared endpoint hooks
8
+ import { CreditAccountHook, DebitAccountHook } from "./core/Settlement.sol";
12
9
 
13
10
  // Commands
11
+ import { Allocate, AllocateHook } from "./commands/Allocate.sol";
14
12
  import { Burn, BurnHook } from "./commands/Burn.sol";
15
- import { CreditAccount, CreditAccountHook } from "./commands/Credit.sol";
16
- import { DebitAccount, DebitAccountHook } from "./commands/Debit.sol";
13
+ import { CreditAccount } from "./commands/Credit.sol";
14
+ import { DebitAccount } from "./commands/Debit.sol";
17
15
  import { Deposit, DepositHook, DepositPayable, DepositPayableHook } from "./commands/Deposit.sol";
18
16
  import { Payout, PayoutHook } from "./commands/Payout.sol";
19
17
  import { Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook } from "./commands/Provision.sol";
package/README.md CHANGED
@@ -10,7 +10,7 @@ of the protocol: the base contracts, block codecs, and helpers that rootzero
10
10
  applications compose.
11
11
 
12
12
  Two decisions shape everything below. First, all data that crosses a host
13
- boundary is encoded in one binary block format, so a request means the same
13
+ boundary is encoded in one binary block format, so a input means the same
14
14
  bytes on every chain. Second, every surface operates on *runs* of blocks rather
15
15
  than single values, so batching is the default, not a feature added later. This
16
16
  guide introduces the protocol bottom-up: blocks, then identities, then hosts
@@ -48,7 +48,7 @@ contract ExampleHost is Host, Balances, Deposit {
48
48
  ```
49
49
 
50
50
  Deploy it with your own address as commander and you can call its commands
51
- directly. A request is a run of binary blocks — here, a single `#amount` block
51
+ directly. A input is a run of binary blocks — here, a single `#amount` block
52
52
  asking to deposit an asset (the encoders are a few lines each; see
53
53
  [`test/helpers/blocks.ts`](test/helpers/blocks.ts) for reference
54
54
  implementations):
@@ -57,8 +57,8 @@ implementations):
57
57
  const host = await ethers.deployContract("ExampleHost", [deployer.address]);
58
58
 
59
59
  const account = encodeUserAccount(user.address); // receiving account
60
- const request = encodeAmountBlock(asset, 100n); // what to deposit
61
- await host.deposit({ account, state: "0x", input: request }); // emits Balance
60
+ const input = encodeAmountBlock(asset, 100n); // what to deposit
61
+ await host.deposit({ account, state: "0x", input: input }); // emits Balance
62
62
  ```
63
63
 
64
64
  The rest of this guide explains the ideas this example leans on — blocks, IDs,
@@ -66,7 +66,7 @@ hosts, commands — and the surfaces built on top of them.
66
66
 
67
67
  ## Blocks
68
68
 
69
- Every request, response, and piece of in-flight state is a stream of typed
69
+ Every input, response, and piece of in-flight state is a stream of typed
70
70
  blocks. A block is a four-byte key, a four-byte big-endian length, and a
71
71
  payload:
72
72
 
@@ -85,7 +85,7 @@ amount { bytes32 asset, uint amount }
85
85
  is 72 bytes on the wire: an 8-byte header followed by two big-endian 32-byte
86
86
  fields. There is no ABI encoding and no chain-specific type anywhere in the
87
87
  format — field types are chain-neutral integers, bytes, and booleans. A deposit
88
- request built for an EVM host is byte-for-byte the request a CosmWasm or Solana
88
+ input built for an EVM host is byte-for-byte the input a CosmWasm or Solana
89
89
  port would parse; what differs per chain is how a host *resolves* the
90
90
  identifiers inside, never how the bytes are laid out.
91
91
 
@@ -96,11 +96,11 @@ paths give off-chain tooling presentation names without changing a single byte
96
96
  on the wire. The full schema language is specified in
97
97
  [`docs/Schema.md`](docs/Schema.md). The standard block schemas live in
98
98
  `Schemas` and their runtime keys in `Keys` (both via
99
- `@rootzero/contracts/Cursors.sol`).
99
+ `@rootzero/contracts/Codec.sol`).
100
100
 
101
101
  ## Batches
102
102
 
103
- A request is not a single struct; it is a run of blocks. One `#amount` block
103
+ A input is not a single struct; it is a run of blocks. One `#amount` block
104
104
  asks for one deposit, five blocks ask for five, and the code path is identical
105
105
  — every endpoint parses with a cursor and loops until the stream is exhausted.
106
106
  The descriptor lane key is the prime item: it is the block type that may repeat
@@ -117,14 +117,15 @@ Off-chain, building a batch is concatenation. Using the reference encoders from
117
117
  import { concat } from "ethers";
118
118
  import { encodeAmountBlock } from "./helpers/blocks";
119
119
 
120
- const request = concat([
120
+ const input = concat([
121
121
  encodeAmountBlock(usdc, 250_000_000n),
122
122
  encodeAmountBlock(dai, 250n * 10n ** 18n),
123
123
  ]);
124
- // deposit(request) returns two #balance blocks, one per #amount
124
+ // deposit(input) returns two #balance blocks in its state output and an
125
+ // empty transaction output
125
126
  ```
126
127
 
127
- Everything downstream keeps this shape: commands loop over request blocks,
128
+ Everything downstream keeps this shape: commands loop over input blocks,
128
129
  settlement loops over transactions, pipelines loop over steps. Batching is
129
130
  never a special case.
130
131
 
@@ -216,6 +217,11 @@ struct CommandContext {
216
217
  }
217
218
  ```
218
219
 
220
+ Every command returns two block streams: `state`, which is threaded into the
221
+ next pipeline step, and `transactions`, which contains `#transaction` blocks
222
+ for the pipeline host to settle outside the state lane. Either stream may be
223
+ empty.
224
+
219
225
  The input carries instructions; the state carries live value. While a
220
226
  sequence of commands executes, `#balance` and `#custody` blocks in the state
221
227
  are the funds being moved — produced by one command, consumed by the next.
@@ -224,7 +230,9 @@ The standard `Deposit` mixin shows the canonical shape — open the input,
224
230
  loop the batch, call the hook, write the output run:
225
231
 
226
232
  ```solidity
227
- function deposit(CommandContext calldata c) external onlyCommand returns (bytes memory) {
233
+ function deposit(
234
+ CommandContext calldata c
235
+ ) external onlyCommand returns (bytes memory, bytes memory) {
228
236
  (Cur memory input, uint outputs) = openInput(c.input, descriptor);
229
237
  Writer memory output = Writers.allocBalances(outputs);
230
238
 
@@ -234,7 +242,7 @@ function deposit(CommandContext calldata c) external onlyCommand returns (bytes
234
242
  output.appendBalance(asset, amount);
235
243
  }
236
244
 
237
- return output.finish();
245
+ return (end(output), "");
238
246
  }
239
247
  ```
240
248
 
@@ -244,14 +252,18 @@ lanes, derived group sizes, and flags, plus a human-readable label:
244
252
 
245
253
  ```solidity
246
254
  abstract contract MyCommand is CommandBase {
247
- bytes32 private immutable descriptor;
255
+ uint private immutable descriptor;
248
256
 
249
257
  constructor() {
250
- (, descriptor) = command("myCommand", Keys.Empty, Keys.Amount, Keys.Balance, 0, false, false);
258
+ (, descriptor) = command("myCommand", Specs.Empty, Specs.Amount, Specs.Balance, 0, false, false);
251
259
  }
252
260
 
253
- function myCommand(CommandContext calldata c) external onlyCommand returns (bytes memory) {
254
- // parse c.input, loop, return the output state run
261
+ function myCommand(
262
+ bytes32 account,
263
+ bytes calldata state,
264
+ bytes calldata input
265
+ ) external onlyCommand returns (bytes memory, bytes memory) {
266
+ // parse input, loop, return the output state run and any transactions
255
267
  }
256
268
  }
257
269
  ```
@@ -259,8 +271,9 @@ abstract contract MyCommand is CommandBase {
259
271
  The standard commands cover the common ledger movements: `deposit` and
260
272
  `depositPayable` (external funds in), `withdraw` and `burn` (funds out),
261
273
  `debitAccount` and `creditAccount` (internal movements), `payout` (deliver
262
- state to other accounts), `provision` (allocate custody on another host), and
263
- `relayPayable` (hand a pipeline to another portal).
274
+ state to other accounts), `allocate` (turn balance state into custody),
275
+ `provision` (provision custody from an external allocation), and `relayPayable`
276
+ (hand a pipeline to another portal).
264
277
 
265
278
  ## Pipelines
266
279
 
@@ -268,24 +281,36 @@ A single command is rarely the whole story. A pipeline is a run of `#step`
268
281
  blocks executed in order within one transaction:
269
282
 
270
283
  ```txt
271
- step { uint target, uint resources, #bytes as request }
284
+ step { uint cmd, uint resources, #bytes as input }
272
285
  ```
273
286
 
274
- Each step names a target command, the resources it may spend, and its request.
275
- The state threads through: whatever one command returns becomes the input
276
- state of the next, and the final state must be empty. This is the core of
277
- `Pipeline.pipe`:
287
+ Each step names a command, the resources it may spend, and its input.
288
+ The returned state threads into the next command and the final state must be
289
+ empty. Returned transactions do not enter the state lane; the pipeline passes
290
+ each decoded transaction to the shared settlement implementation before
291
+ running the next step. This is the core of `Pipeline.pipe`:
278
292
 
279
293
  ```solidity
280
- while (input.i < input.len) {
281
- (uint target, uint resources, bytes calldata request) = input.unpackStep();
282
- state = dispatch(target, account, state, request, useValue(budget, resources));
294
+ while (cur.more()) {
295
+ (uint cmd, uint resources, bytes calldata input) = cur.unpackStep();
296
+ Reader memory transactions;
297
+ (state, transactions.source) = dispatch(
298
+ cmd,
299
+ account,
300
+ state,
301
+ input,
302
+ budget.use(resources)
303
+ );
304
+ while (transactions.more()) {
305
+ (bytes32 from, bytes32 to, bytes32 asset, uint amount) = transactions.unpackTransaction();
306
+ settle(from, to, asset, amount);
307
+ }
283
308
  }
284
309
  if (state.length != 0) revert UnexpectedState();
285
310
  ```
286
311
 
287
312
  A transfer, for instance, is a two-step pipeline: `debitAccount` turns an
288
- `#amount` request into `#balance` state, and `payout` consumes that state
313
+ `#amount` input into `#balance` state, and `payout` consumes that state
289
314
  toward a recipient. Because a pipeline is just blocks, it is also the unit of
290
315
  command batching — and `resources` is a chain-specific word interpreted by the
291
316
  portal adapter (on EVM, the low 128 bits are native value in wei, drawn from a
@@ -293,13 +318,13 @@ shared budget), so the same pipeline bytes are meaningful to every port.
293
318
 
294
319
  ## Queries
295
320
 
296
- Queries are the read endpoints: view functions that take a block-stream request
321
+ Queries are the read endpoints: view functions that take a block-stream input
297
322
  and return a block-stream response, with the same batch shape as commands. The
298
323
  standard `getBalances` query takes a run of positions and answers each one in
299
324
  order:
300
325
 
301
326
  ```txt
302
- request: accountAsset { bytes32 account, bytes32 asset }
327
+ input: accountAsset { bytes32 account, bytes32 asset }
303
328
  response: accountAmount { bytes32 account, bytes32 asset, uint amount }
304
329
  ```
305
330
 
@@ -322,8 +347,8 @@ This is also the cross-portal mechanism. `relayPayable` (or `portDispatchPayable
322
347
  wraps a pipe and addresses it to a portal, commonly the destination host ID;
323
348
  a bridge adapter moves the **raw
324
349
  bytes**; the destination host parses them with the same cursor rules and runs
325
- the same pipeline loop. Nothing in the payload is EVM-specific — step targets
326
- are destination-local node IDs, and only the adapter boundary (native
350
+ the same pipeline loop. Nothing in the payload is EVM-specific — step commands
351
+ are destination-local command IDs, and only the adapter boundary (native
327
352
  transfers, address resolution, signatures) is chain-specific. The parity rule
328
353
  for ports is strict: every chain's implementation must parse the same input
329
354
  bytes and produce the same output bytes for every endpoint.
@@ -353,11 +378,13 @@ names, access sets, balances — from logs alone, with no artifact files.
353
378
  Import from the package entry points rather than deep paths:
354
379
 
355
380
  - `@rootzero/contracts/Core.sol` — `Host`, access control, `Balances`,
356
- `Pipeline`, `Portal`, validator
381
+ `Settlement`, `Pipeline`, `Portal`, validator
382
+ - `@rootzero/contracts/Commands.sol` — `CommandBase`, `Execution`, codec
383
+ helpers, and shared value types for authoring custom commands
357
384
  - `@rootzero/contracts/Endpoints.sol` — command, admin, port, guard, and query
358
385
  mixins and their hooks
359
- - `@rootzero/contracts/Cursors.sol` — `Cur` cursor reader, `Writers`, `Schemas`,
360
- `Keys`
386
+ - `@rootzero/contracts/Codec.sol` — `Blocks`, calldata `Cur`/`Cursors`, memory
387
+ `Reader`/`Readers`, `Writers`, `Schemas`, `Keys`, and `Specs`
361
388
  - `@rootzero/contracts/Utils.sol` — `Ids`, `Nodes`, `Assets`, `Accounts`,
362
389
  layout and value helpers
363
390
  - `@rootzero/contracts/Events.sol` — protocol event contracts
package/Utils.sol CHANGED
@@ -1,10 +1,10 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- // Aggregator: re-exports all utility libraries (Keys, Accounts, Actions, Assets, ECDSA, Ids, Nodes, Selectors, Layout, Utils, Value).
4
+ // Aggregator: re-exports protocol identifier, asset, account, cryptographic,
5
+ // layout, and general-purpose utility helpers.
5
6
  // Import this file to access the full utility surface without managing individual paths.
6
7
 
7
- import { Keys } from "./blocks/Keys.sol";
8
8
  import { Accounts } from "./utils/Accounts.sol";
9
9
  import { Actions } from "./utils/Actions.sol";
10
10
  import { Amounts, Assets } from "./utils/Assets.sol";
@@ -13,9 +13,7 @@ import { Ids } from "./utils/Ids.sol";
13
13
  import { Nodes } from "./utils/Nodes.sol";
14
14
  import { Selectors } from "./utils/Selectors.sol";
15
15
  import { Layout } from "./utils/Layout.sol";
16
- import { Schemas } from "./blocks/Schema.sol";
17
16
  import { addrOr, applyBps, beforeBps, bytes32ToInt, bytes32ToString, divisible, hash32, intToBytes32, isFamily, matchesBase, MAX_BPS, max8, max16, max24, max32, max40, max64, max96, max128, max160, NotDivisible, retryTicket, toLocalBase, toUnspecifiedBase, ValueOverflow } from "./utils/Utils.sol";
18
- import { Budget, Values } from "./utils/Value.sol";
19
17
 
20
18
 
21
19