@rootzero/contracts 1.8.0 → 1.10.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 (55) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/Core.sol +2 -1
  3. package/Endpoints.sol +2 -2
  4. package/Events.sol +2 -1
  5. package/README.md +14 -13
  6. package/blocks/Cursors.sol +61 -61
  7. package/blocks/Keys.sol +4 -4
  8. package/blocks/Schema.sol +8 -7
  9. package/blocks/Writers.sol +2 -2
  10. package/commands/Burn.sol +1 -1
  11. package/commands/Credit.sol +1 -1
  12. package/commands/Debit.sol +1 -1
  13. package/commands/Deposit.sol +2 -2
  14. package/commands/Payout.sol +2 -2
  15. package/commands/Provision.sol +2 -2
  16. package/commands/Recover.sol +21 -20
  17. package/commands/Relay.sol +11 -11
  18. package/commands/Withdraw.sol +1 -1
  19. package/commands/admin/AllowAssets.sol +1 -1
  20. package/commands/admin/Allowance.sol +1 -1
  21. package/commands/admin/Appoint.sol +1 -1
  22. package/commands/admin/Authorize.sol +1 -1
  23. package/commands/admin/DenyAssets.sol +1 -1
  24. package/commands/admin/Destroy.sol +1 -0
  25. package/commands/admin/Dismiss.sol +1 -1
  26. package/commands/admin/Execute.sol +2 -2
  27. package/commands/admin/Init.sol +1 -0
  28. package/commands/admin/Label.sol +1 -1
  29. package/commands/admin/Unauthorize.sol +1 -1
  30. package/core/Access.sol +1 -0
  31. package/core/Calls.sol +12 -1
  32. package/core/Payable.sol +8 -1
  33. package/core/Pipeline.sol +1 -1
  34. package/core/Portal.sol +39 -0
  35. package/docs/Schema.md +15 -11
  36. package/events/Dispatch.sol +5 -5
  37. package/events/Recovered.sol +17 -0
  38. package/events/Route.sol +5 -5
  39. package/events/Undelivered.sol +18 -0
  40. package/guards/Revoke.sol +1 -1
  41. package/package.json +1 -1
  42. package/ports/AllowAssets.sol +1 -1
  43. package/ports/Allowance.sol +1 -1
  44. package/ports/Credit.sol +1 -1
  45. package/ports/Debit.sol +1 -1
  46. package/ports/DenyAssets.sol +1 -1
  47. package/ports/Dispatch.sol +8 -8
  48. package/ports/Pipe.sol +1 -1
  49. package/ports/Redeem.sol +1 -1
  50. package/ports/Settle.sol +1 -1
  51. package/queries/Assets.sol +1 -1
  52. package/queries/Balances.sol +1 -1
  53. package/queries/Positions.sol +2 -1
  54. package/core/Commitments.sol +0 -19
  55. package/events/Commitment.sol +0 -19
package/CHANGELOG.md CHANGED
@@ -3,6 +3,45 @@
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
+ ## Unreleased
7
+
8
+ ## 1.10.0
9
+
10
+ ### Breaking Changes
11
+
12
+ - Moved `RecoverHook` from `Portal.sol` to `commands/Recover.sol`.
13
+ - Moved `RoutePayableHook` from `Portal.sol` to `commands/Relay.sol`.
14
+ - Renamed Portal helpers to `forward` / `retry`; hosts now explicitly bridge
15
+ the `RecoverPayable` hook to Portal retry behavior.
16
+ - Renamed the generic `Resolved` event to `Recovered`.
17
+ - Portal no longer emits `Recovered` when retrying an undelivered witness.
18
+ - Renamed `Cursors.exit` to `ensureAt` and renamed its position argument to
19
+ `pos`.
20
+ - Removed the redundant `next` return value from both `Cursors.init` overloads;
21
+ callers should use the returned cursor's `len` as the run boundary.
22
+ - Changed `Cursors.list` to require the expected current cursor position as
23
+ `pos` before entering the LIST block.
24
+
25
+ ## 1.9.0
26
+
27
+ ### Breaking Changes
28
+
29
+ - Renamed relay and dispatch routing fields from `chain` to `portal` across
30
+ schemas, cursor helpers, dispatch hooks, and dispatch/route events.
31
+ - Replaced the context-specific `RecoverContextPayable` / `#contextRecovery`
32
+ surface with generic `RecoverPayable` / `#recover` using byte witnesses.
33
+ - Renamed the `Dispatch` event correlation field from `ref` to `key`.
34
+ - Replaced `DispatchPayableHook.dispatch` with `RoutePayableHook.route` in the
35
+ portal core layer.
36
+ - Added `status` to `Route(uint indexed host, uint portal, uint status)`
37
+ so routes can be removed by emitting zero status.
38
+ - Added `Undelivered(uint indexed host, bytes32 key, bytes32 digest)` for portal
39
+ messages that could not be delivered to their handler port.
40
+ - Added `Recovered(uint indexed host, bytes32 key)` as the
41
+ matching event for resolved undelivered digests.
42
+ - Removed the generic `Commitments` core mixin and `Commitment` event in favor
43
+ of domain-specific events such as `Undelivered` and `Recovered`.
44
+
6
45
  ## 1.8.0
7
46
 
8
47
  ### Breaking Changes
package/Core.sol CHANGED
@@ -6,13 +6,14 @@ pragma solidity ^0.8.33;
6
6
 
7
7
  import { AccessControl } from "./core/Access.sol";
8
8
  import { Balances, InsufficientFunds } from "./core/Balances.sol";
9
- import { Commitments } from "./core/Commitments.sol";
10
9
  import { Escrows, InsufficientEscrow } from "./core/Escrows.sol";
11
10
  import { NativeAsset, Runtime } from "./core/Runtime.sol";
12
11
  import { Host, IHostIntroduction } from "./core/Host.sol";
13
12
  import { CommandCalls, FailedCall, NodeCalls, PortCalls } from "./core/Calls.sol";
14
13
  import { Payable } from "./core/Payable.sol";
15
14
  import { Pipeline } from "./core/Pipeline.sol";
15
+ import { Portal } from "./core/Portal.sol";
16
+ import { RecoverHook } from "./commands/Recover.sol";
16
17
  import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
17
18
  import { Validator } from "./core/Validator.sol";
18
19
 
package/Endpoints.sol CHANGED
@@ -16,8 +16,8 @@ import { DebitAccount, DebitAccountHook } from "./commands/Debit.sol";
16
16
  import { Deposit, DepositHook, DepositPayable, DepositPayableHook } from "./commands/Deposit.sol";
17
17
  import { Payout, PayoutHook } from "./commands/Payout.sol";
18
18
  import { Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook } from "./commands/Provision.sol";
19
- import { RecoverContextPayable, RecoverContextPayableHook } from "./commands/Recover.sol";
20
- import { RelayPayable, DispatchPayableHook } from "./commands/Relay.sol";
19
+ import { RecoverHook, RecoverPayable } from "./commands/Recover.sol";
20
+ import { RelayPayable, RoutePayableHook } from "./commands/Relay.sol";
21
21
  import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
22
22
 
23
23
  // Admin commands
package/Events.sol CHANGED
@@ -10,10 +10,10 @@ import { Actions } from "./utils/Actions.sol";
10
10
  import { BalanceEvent } from "./events/Balance.sol";
11
11
  import { CommanderEvent } from "./events/Commander.sol";
12
12
  import { CommandEvent } from "./events/Command.sol";
13
- import { CommitmentEvent } from "./events/Commitment.sol";
14
13
  import { DispatchEvent } from "./events/Dispatch.sol";
15
14
  import { PositionEvent } from "./events/Position.sol";
16
15
  import { ReceivedEvent } from "./events/Received.sol";
16
+ import { RecoveredEvent } from "./events/Recovered.sol";
17
17
  import { EventEmitter } from "./events/Emitter.sol";
18
18
  import { GuardEvent } from "./events/Guard.sol";
19
19
  import { GuardianEvent } from "./events/Guardian.sol";
@@ -26,6 +26,7 @@ import { QueryEvent } from "./events/Query.sol";
26
26
  import { RootedEvent } from "./events/Rooted.sol";
27
27
  import { RouteEvent } from "./events/Route.sol";
28
28
  import { SpentEvent } from "./events/Spent.sol";
29
+ import { UndeliveredEvent } from "./events/Undelivered.sol";
29
30
  import { UnlockedEvent } from "./events/Unlocked.sol";
30
31
 
31
32
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  rootzero is a protocol for building **hosts**: contracts that expose a uniform
4
4
  set of endpoints over accounts and assets — commands that change state,
5
- queries that read it, and peer links that connect hosts to each other, on the
5
+ queries that read it, and port links that connect hosts to each other, on the
6
6
  same chain or across chains.
7
7
 
8
8
  This repository is `@rootzero/contracts`, the Solidity library for the EVM port
@@ -160,7 +160,7 @@ structured ID announces what it is (an account, an asset, a node) and which
160
160
  chain it lives on, and the payload usually embeds the underlying address. User
161
161
  accounts are chain-agnostic; admin and guardian accounts are chain-local.
162
162
  Assets are unique IDs in the same single-word form as accounts and nodes.
163
- Nodes are hosts, commands, peers, queries, and guards.
163
+ Nodes are hosts, commands, ports, queries, and guards.
164
164
 
165
165
  Opaque asset declarations use `Asset(host, asset, preimage)`. The preimage
166
166
  starts with a one-byte format/hash tag, letting offchain indexers or witnesses
@@ -220,7 +220,7 @@ the batch, call the hook, write the output run:
220
220
 
221
221
  ```solidity
222
222
  function deposit(CommandContext calldata c) external onlyCommand returns (bytes memory) {
223
- (Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
223
+ (Cur memory request, uint groups) = Cursors.init(c.request, 1);
224
224
  Writer memory writer = Writers.allocBalances(groups);
225
225
 
226
226
  while (request.i < request.len) {
@@ -258,7 +258,7 @@ The standard commands cover the common ledger movements: `deposit` and
258
258
  `depositPayable` (external funds in), `withdraw` and `burn` (funds out),
259
259
  `debitAccount` and `creditAccount` (internal movements), `payout` (deliver
260
260
  state to other accounts), `provision` (allocate custody on another host), and
261
- `relayPayable` (hand a pipeline to another chain).
261
+ `relayPayable` (hand a pipeline to another portal).
262
262
 
263
263
  ## Pipelines
264
264
 
@@ -285,9 +285,9 @@ if (state.length != 0) revert UnexpectedState();
285
285
  A transfer, for instance, is a two-step pipeline: `debitAccount` turns an
286
286
  `#amount` request into `#balance` state, and `payout` consumes that state
287
287
  toward a recipient. Because a pipeline is just blocks, it is also the unit of
288
- command batching — and `resources` is a chain-typed word (on EVM, the low 128
289
- bits are native value in wei, drawn from a shared budget), so the same pipeline
290
- bytes are meaningful to every port.
288
+ command batching — and `resources` is a chain-specific word interpreted by the
289
+ portal adapter (on EVM, the low 128 bits are native value in wei, drawn from a
290
+ shared budget), so the same pipeline bytes are meaningful to every port.
291
291
 
292
292
  ## Queries
293
293
 
@@ -314,10 +314,11 @@ central ones are batches all the way down:
314
314
  block — how two hosts record settlement between their ledgers.
315
315
  - `portPipePayable` consumes `#context` blocks, each carrying an account, an
316
316
  initial state, and a run of steps — a complete pipeline delivered by another
317
- host, executed locally against the peer call's shared value budget.
317
+ host, executed locally against the port call's shared value budget.
318
318
 
319
- This is also the cross-chain mechanism. `relayPayable` (or `portDispatchPayable`)
320
- wraps a pipe and addresses it to a chain; a bridge adapter moves the **raw
319
+ This is also the cross-portal mechanism. `relayPayable` (or `portDispatchPayable`)
320
+ wraps a pipe and addresses it to a portal, commonly the destination host ID;
321
+ a bridge adapter moves the **raw
321
322
  bytes**; the destination host parses them with the same cursor rules and runs
322
323
  the same pipeline loop. Nothing in the payload is EVM-specific — step targets
323
324
  are destination-local node IDs, and only the adapter boundary (native
@@ -350,8 +351,8 @@ names, access sets, balances — from logs alone, with no artifact files.
350
351
  Import from the package entry points rather than deep paths:
351
352
 
352
353
  - `@rootzero/contracts/Core.sol` — `Host`, access control, `Balances`,
353
- `Pipeline`, validator
354
- - `@rootzero/contracts/Endpoints.sol` — command, admin, peer, guard, and query
354
+ `Pipeline`, `Portal`, validator
355
+ - `@rootzero/contracts/Endpoints.sol` — command, admin, port, guard, and query
355
356
  mixins and their hooks
356
357
  - `@rootzero/contracts/Cursors.sol` — `Cur` cursor reader, `Writers`, `Schemas`,
357
358
  `Keys`
@@ -363,7 +364,7 @@ Repo layout:
363
364
 
364
365
  - `contracts/core` — host, access control, balances, pipeline, validation
365
366
  - `contracts/commands` — standard commands and admin commands
366
- - `contracts/ports` — peer surfaces for inter-host and cross-chain flows
367
+ - `contracts/ports` — port surfaces for inter-host and cross-portal flows
367
368
  - `contracts/guards` — guardian direct actions
368
369
  - `contracts/queries` — read-only query endpoints
369
370
  - `contracts/blocks` — block schema, cursor parsing, writers
@@ -76,16 +76,14 @@ library Cursors {
76
76
  /// @param group Expected block group size (e.g. 1 for single, 2 for paired).
77
77
  /// @return cur Cursor with `len` truncated to the end of the first run in `source`.
78
78
  /// @return groups Number of block groups in the run (`block count / group`).
79
- /// @return next Byte offset immediately after the run, relative to `source`.
80
79
  function init(
81
80
  bytes calldata source,
82
81
  uint group
83
- ) internal pure returns (Cur memory cur, uint groups, uint next) {
82
+ ) internal pure returns (Cur memory cur, uint groups) {
84
83
  cur = open(source);
85
84
  if (cur.i == cur.len) revert ZeroCursor();
86
85
  (bytes4 key, ) = cur.peek(cur.i);
87
86
  groups = cur.run(key, group);
88
- next = cur.len;
89
87
  }
90
88
 
91
89
  /// @notice Create a cursor over `source`, restrict it to its first grouped run, and require an exact group count.
@@ -93,14 +91,13 @@ library Cursors {
93
91
  /// @param group Expected block group size (e.g. 1 for single, 2 for paired).
94
92
  /// @param expectedGroups Required number of groups in the run.
95
93
  /// @return cur Cursor with `len` truncated to the end of the first run in `source`.
96
- /// @return next Byte offset immediately after the run, relative to `source`.
97
94
  function init(
98
95
  bytes calldata source,
99
96
  uint group,
100
97
  uint expectedGroups
101
- ) internal pure returns (Cur memory cur, uint next) {
98
+ ) internal pure returns (Cur memory cur) {
102
99
  uint groups;
103
- (cur, groups, next) = init(source, group);
100
+ (cur, groups) = init(source, group);
104
101
  if (groups != expectedGroups) revert BadRatio();
105
102
  }
106
103
 
@@ -333,13 +330,16 @@ library Cursors {
333
330
  return find(cur, cur.i, key);
334
331
  }
335
332
 
336
- /// @notice Enter a List block at the current position and return the next offset.
333
+ /// @notice Enter a LIST block at the expected current position and return its next offset.
334
+ /// Reverts with `IncompleteCursor` if `cur.i` is not exactly `pos`.
337
335
  /// Advances `cur.i` past the list header so the list members can be parsed
338
336
  /// directly from the same cursor. The returned `next` is the byte offset
339
337
  /// immediately after the list payload, relative to the current cursor region.
340
- /// @param cur Cursor positioned at a list block; advanced past the 8-byte header.
338
+ /// @param cur Cursor expected to be positioned at a list block; advanced past the 8-byte header.
339
+ /// @param pos Expected current cursor position, relative to the cursor region.
341
340
  /// @return next Byte offset immediately after the list payload.
342
- function list(Cur memory cur) internal pure returns (uint next) {
341
+ function list(Cur memory cur, uint pos) internal pure returns (uint next) {
342
+ cur.ensureAt(pos);
343
343
  next = enter(cur, Keys.List, 0, 0);
344
344
  }
345
345
 
@@ -387,13 +387,13 @@ library Cursors {
387
387
  return maybeTake(cur, Keys.Data);
388
388
  }
389
389
 
390
- /// @notice Exit a nested region at an exact boundary.
391
- /// Reverts with `IncompleteCursor` if `end` exceeds the cursor region length
392
- /// or `cur.i != end`.
390
+ /// @notice Ensure the cursor is at an exact position.
391
+ /// Reverts with `IncompleteCursor` if `pos` exceeds the cursor region length
392
+ /// or `cur.i != pos`.
393
393
  /// @param cur Cursor to check.
394
- /// @param end Relative end offset of the nested region.
395
- function exit(Cur memory cur, uint end) internal pure {
396
- if (end > cur.len || cur.i != end) revert IncompleteCursor();
394
+ /// @param pos Relative byte offset the cursor must be positioned at.
395
+ function ensureAt(Cur memory cur, uint pos) internal pure {
396
+ if (pos > cur.len || cur.i != pos) revert IncompleteCursor();
397
397
  }
398
398
 
399
399
  /// @notice Assert that the cursor has consumed its entire source region.
@@ -519,7 +519,7 @@ library Cursors {
519
519
 
520
520
  /// @notice Encode a STEP block.
521
521
  /// @param target Command target identifier.
522
- /// @param resources Chain resources assigned to the step.
522
+ /// @param resources Packed resources assigned to the step.
523
523
  /// @param request Raw nested request payload.
524
524
  /// @return Encoded STEP block bytes.
525
525
  function toStepBlock(uint target, uint resources, bytes memory request) internal pure returns (bytes memory) {
@@ -528,7 +528,7 @@ library Cursors {
528
528
 
529
529
  /// @notice Encode a CALL block.
530
530
  /// @param target Target node identifier.
531
- /// @param resources Chain resources assigned to the call.
531
+ /// @param resources Packed resources assigned to the call.
532
532
  /// @param data Raw calldata payload for the target.
533
533
  /// @return Encoded CALL block bytes.
534
534
  function toCallBlock(uint target, uint resources, bytes memory data) internal pure returns (bytes memory) {
@@ -549,21 +549,21 @@ library Cursors {
549
549
  }
550
550
 
551
551
  /// @notice Encode a RELAY block.
552
- /// @param chain Destination chain node ID.
553
- /// @param resources Chain-adapter-specific resources for the destination context.
552
+ /// @param portal Destination portal identifier, often the destination host ID.
553
+ /// @param resources Chain-specific resources for the destination context.
554
554
  /// @param request Nested request block stream.
555
555
  /// @return Encoded RELAY block bytes.
556
- function toRelayBlock(uint chain, uint resources, bytes memory request) internal pure returns (bytes memory) {
557
- return createBlock(Keys.Relay, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(request)));
556
+ function toRelayBlock(uint portal, uint resources, bytes memory request) internal pure returns (bytes memory) {
557
+ return createBlock(Keys.Relay, bytes.concat(bytes32(portal), bytes32(resources), toBytesBlock(request)));
558
558
  }
559
559
 
560
560
  /// @notice Encode a DISPATCH block.
561
- /// @param chain Destination chain node ID.
562
- /// @param resources Chain-adapter-specific resources for the destination dispatch.
563
- /// @param payload Encoded cross-chain payload.
561
+ /// @param portal Destination portal identifier, often the destination host ID.
562
+ /// @param resources Chain-specific resources for the destination dispatch.
563
+ /// @param payload Encoded payload.
564
564
  /// @return Encoded DISPATCH block bytes.
565
- function toDispatchBlock(uint chain, uint resources, bytes memory payload) internal pure returns (bytes memory) {
566
- return createBlock(Keys.Dispatch, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(payload)));
565
+ function toDispatchBlock(uint portal, uint resources, bytes memory payload) internal pure returns (bytes memory) {
566
+ return createBlock(Keys.Dispatch, bytes.concat(bytes32(portal), bytes32(resources), toBytesBlock(payload)));
567
567
  }
568
568
 
569
569
  // -------------------------------------------------------------------------
@@ -747,7 +747,7 @@ library Cursors {
747
747
  id = cur.readUint();
748
748
  namespace = cur.read32();
749
749
  name = cur.unpackString();
750
- cur.exit(end);
750
+ cur.ensureAt(end);
751
751
  }
752
752
 
753
753
  /// @notice Consume a dynamic block with a single bytes32 payload.
@@ -1100,28 +1100,28 @@ library Cursors {
1100
1100
  /// The `req` slice is the raw payload of the block's required BYTES child.
1101
1101
  /// @param cur Cursor; advanced past the block.
1102
1102
  /// @return target Destination node ID for the sub-command.
1103
- /// @return resources Chain resources assigned to the step.
1103
+ /// @return resources Packed resources assigned to the step.
1104
1104
  /// @return req Embedded request bytes for the sub-command.
1105
1105
  function unpackStep(Cur memory cur) internal pure returns (uint target, uint resources, bytes calldata req) {
1106
1106
  uint end = cur.enter(Keys.Step, 64 + Sizes.Header, 0);
1107
1107
  target = uint(cur.read32());
1108
1108
  resources = uint(cur.read32());
1109
1109
  req = cur.unpackBytes();
1110
- cur.exit(end);
1110
+ cur.ensureAt(end);
1111
1111
  }
1112
1112
 
1113
1113
  /// @notice Consume a CALL block and return its target invocation fields.
1114
1114
  /// The `data` slice is the raw payload of the block's required BYTES child.
1115
1115
  /// @param cur Cursor; advanced past the block.
1116
1116
  /// @return target Target node ID to call.
1117
- /// @return resources Chain resources assigned to the call.
1117
+ /// @return resources Packed resources assigned to the call.
1118
1118
  /// @return data Raw calldata payload for the target.
1119
1119
  function unpackCall(Cur memory cur) internal pure returns (uint target, uint resources, bytes calldata data) {
1120
1120
  uint end = cur.enter(Keys.Call, 64 + Sizes.Header, 0);
1121
1121
  target = uint(cur.read32());
1122
1122
  resources = uint(cur.read32());
1123
1123
  data = cur.unpackBytes();
1124
- cur.exit(end);
1124
+ cur.ensureAt(end);
1125
1125
  }
1126
1126
 
1127
1127
  /// @notice Consume a CONTEXT block and return its command context fields.
@@ -1137,54 +1137,54 @@ library Cursors {
1137
1137
  account = cur.read32();
1138
1138
  state = cur.unpackBytes();
1139
1139
  request = cur.unpackBytes();
1140
- cur.exit(end);
1140
+ cur.ensureAt(end);
1141
1141
  }
1142
1142
 
1143
- /// @notice Consume a RELAY block and return its destination chain, resources, and request stream.
1143
+ /// @notice Consume a RELAY block and return its destination portal, resources, and request stream.
1144
1144
  /// @param cur Cursor; advanced past the block.
1145
- /// @return chain Destination chain node ID.
1146
- /// @return resources Chain-adapter-specific resources for the destination context.
1145
+ /// @return portal Destination portal identifier, often the destination host ID.
1146
+ /// @return resources Chain-specific resources for the destination context.
1147
1147
  /// @return request Embedded request block stream.
1148
1148
  function unpackRelay(
1149
1149
  Cur memory cur
1150
- ) internal pure returns (uint chain, uint resources, bytes calldata request) {
1150
+ ) internal pure returns (uint portal, uint resources, bytes calldata request) {
1151
1151
  uint end = cur.enter(Keys.Relay, 64 + Sizes.Header, 0);
1152
- chain = cur.readUint();
1152
+ portal = cur.readUint();
1153
1153
  resources = cur.readUint();
1154
1154
  request = cur.unpackBytes();
1155
- cur.exit(end);
1155
+ cur.ensureAt(end);
1156
1156
  }
1157
1157
 
1158
- /// @notice Consume a DISPATCH block and return its destination chain, resources, and payload.
1158
+ /// @notice Consume a DISPATCH block and return its destination portal, resources, and payload.
1159
1159
  /// @param cur Cursor; advanced past the block.
1160
- /// @return chain Destination chain node ID.
1161
- /// @return resources Chain-adapter-specific resources for the destination dispatch.
1162
- /// @return payload Encoded cross-chain payload.
1160
+ /// @return portal Destination portal identifier, often the destination host ID.
1161
+ /// @return resources Chain-specific resources for the destination dispatch.
1162
+ /// @return payload Encoded payload.
1163
1163
  function unpackDispatch(
1164
1164
  Cur memory cur
1165
- ) internal pure returns (uint chain, uint resources, bytes calldata payload) {
1165
+ ) internal pure returns (uint portal, uint resources, bytes calldata payload) {
1166
1166
  uint end = cur.enter(Keys.Dispatch, 64 + Sizes.Header, 0);
1167
- chain = cur.readUint();
1167
+ portal = cur.readUint();
1168
1168
  resources = cur.readUint();
1169
1169
  payload = cur.unpackBytes();
1170
- cur.exit(end);
1170
+ cur.ensureAt(end);
1171
1171
  }
1172
1172
 
1173
- /// @notice Consume a CONTEXT_RECOVERY block and return its port, key, resources, and embedded context cursor.
1173
+ /// @notice Consume a RECOVER block and return its handler, resources, key, and witness bytes.
1174
1174
  /// @param cur Cursor; advanced past the block.
1175
- /// @return port Recovery handler port node ID.
1176
- /// @return key Commitment or recovery lookup key.
1177
- /// @return resources Chain resources assigned to the recovery attempt.
1178
- /// @return context Cursor scoped to the embedded CONTEXT witness block.
1179
- function unpackContextRecovery(
1175
+ /// @return handler Recovery handler port node ID.
1176
+ /// @return resources Packed resources assigned to the recovery attempt.
1177
+ /// @return key Recovery lookup key.
1178
+ /// @return witness Witness bytes used by the recovery handler.
1179
+ function unpackRecover(
1180
1180
  Cur memory cur
1181
- ) internal pure returns (uint port, bytes32 key, uint resources, Cur memory context) {
1182
- uint end = cur.enter(Keys.ContextRecovery, 96 + Sizes.Header, 0);
1183
- port = cur.readUint();
1184
- key = cur.read32();
1181
+ ) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness) {
1182
+ uint end = cur.enter(Keys.Recover, 96 + Sizes.Header, 0);
1183
+ handler = cur.readUint();
1185
1184
  resources = cur.readUint();
1186
- context = cur.take(Keys.Context);
1187
- cur.exit(end);
1185
+ key = cur.read32();
1186
+ witness = cur.unpackBytes();
1187
+ cur.ensureAt(end);
1188
1188
  }
1189
1189
 
1190
1190
  // Type-specific validators
@@ -1379,16 +1379,16 @@ library Cursors {
1379
1379
  /// @param cur Cursor; advanced past the RELAY block.
1380
1380
  /// @param account Account identifier to embed in the destination context.
1381
1381
  /// @param state State block stream to embed in the destination context.
1382
- /// @return chain Destination chain node ID.
1383
- /// @return resources Chain resources assigned to the destination context.
1382
+ /// @return portal Destination portal identifier, often the destination host ID.
1383
+ /// @return resources Chain-specific resources assigned to the destination context.
1384
1384
  /// @return context Encoded CONTEXT block containing `account`, `state`, and relay request.
1385
1385
  function relayToContext(
1386
1386
  Cur memory cur,
1387
1387
  bytes32 account,
1388
1388
  bytes calldata state
1389
- ) internal pure returns (uint chain, uint resources, bytes memory context) {
1389
+ ) internal pure returns (uint portal, uint resources, bytes memory context) {
1390
1390
  bytes calldata request;
1391
- (chain, resources, request) = cur.unpackRelay();
1391
+ (portal, resources, request) = cur.unpackRelay();
1392
1392
  context = toContextBlock(account, bytes(state), bytes(request));
1393
1393
  }
1394
1394
 
package/blocks/Keys.sol CHANGED
@@ -41,13 +41,13 @@ library Keys {
41
41
  bytes4 constant Transaction = bytes4(keccak256("#transaction"));
42
42
  /// @dev Sub-command invocation - (uint target, uint resources, #bytes as request)
43
43
  bytes4 constant Step = bytes4(keccak256("#step"));
44
- /// @dev Cross-chain relay request - (uint chain, uint resources, #bytes as request)
44
+ /// @dev Portal relay request - (uint portal, uint resources, #bytes as request)
45
45
  bytes4 constant Relay = bytes4(keccak256("#relay"));
46
46
  /// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
47
47
  bytes4 constant Context = bytes4(keccak256("#context"));
48
- /// @dev Recoverable context witness - (uint port, bytes32 key, uint resources, #context)
49
- bytes4 constant ContextRecovery = bytes4(keccak256("#contextRecovery"));
50
- /// @dev Cross-chain encoded payload dispatch - (uint chain, uint resources, #bytes as payload)
48
+ /// @dev Recoverable witness - (uint handler, uint resources, bytes32 key, #bytes as witness)
49
+ bytes4 constant Recover = bytes4(keccak256("#recover"));
50
+ /// @dev Portal encoded payload dispatch - (uint portal, uint resources, #bytes as payload)
51
51
  bytes4 constant Dispatch = bytes4(keccak256("#dispatch"));
52
52
  /// @dev Raw external call - (uint target, uint resources, #bytes as payload)
53
53
  bytes4 constant Call = bytes4(keccak256("#call"));
package/blocks/Schema.sol CHANGED
@@ -16,10 +16,11 @@ pragma solidity ^0.8.33;
16
16
  // - run items may repeat at top level for batching
17
17
  // - `maybe #x { ... }` marks an optional block item
18
18
  // - `many #x { ... }` emits one generic list block containing repeated `#x` items
19
- // - `resources` fields are chain-specific resource words; one chain type may
20
- // pack them differently from another, but a given chain type must use one
21
- // stable format everywhere. EVM resources use the low 128 bits as native value.
22
- // - dotted field names and aliases, e.g. `dst.chain` or `#bytes as dst.payload`,
19
+ // - `portal` fields are routing identifiers, often destination host IDs
20
+ // - `resources` fields are chain-specific resource words. A portal adapter
21
+ // interprets them for the destination runtime. EVM resources use the low
22
+ // 128 bits as native value.
23
+ // - dotted field names and aliases, e.g. `dst.portal` or `#bytes as dst.payload`,
23
24
  // are offchain projection metadata only and do not change runtime encoding
24
25
  // - a child block without an inline body, e.g. `#context as witness`, may resolve
25
26
  // to a known schema in the active schema context; unresolved aliases are invalid
@@ -71,11 +72,11 @@ library Schemas {
71
72
  string constant Allowance = "#allowance { uint host, bytes32 asset, uint amount }";
72
73
  string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, uint amount }";
73
74
  string constant Context = "#context { bytes32 account, #bytes as state, #bytes as request }";
74
- string constant ContextRecovery = "#contextRecovery { uint port, bytes32 key, uint resources, #context as witness }";
75
+ string constant Recover = "#recover { uint handler, uint resources, bytes32 key, #bytes as witness }";
75
76
  string constant Call = "#call { uint target, uint resources, #bytes as payload }";
76
77
  string constant Step = "#step { uint target, uint resources, #bytes as request }";
77
- string constant Relay = "#relay { uint chain, uint resources, #bytes as request }";
78
- string constant Dispatch = "#dispatch { uint chain, uint resources, #bytes as payload }";
78
+ string constant Relay = "#relay { uint portal, uint resources, #bytes as request }";
79
+ string constant Dispatch = "#dispatch { uint portal, uint resources, #bytes as payload }";
79
80
  string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
80
81
  string constant Fee = "#fee { uint amount }";
81
82
  string constant Auth = "#auth { uint cid, uint deadline, #bytes as proof }";
@@ -872,7 +872,7 @@ library Writers {
872
872
  /// @notice Append a STEP block with a nested request BYTES payload.
873
873
  /// @param writer Destination writer; `i` is advanced by the encoded STEP block length.
874
874
  /// @param target Command target identifier.
875
- /// @param resources Chain resources assigned to the step.
875
+ /// @param resources Packed resources assigned to the step.
876
876
  /// @param request Raw nested request payload.
877
877
  function appendStep(Writer memory writer, uint target, uint resources, bytes memory request) internal pure {
878
878
  appendBlock64Bytes(writer, Keys.Step, bytes32(target), bytes32(resources), request);
@@ -881,7 +881,7 @@ library Writers {
881
881
  /// @notice Append a CALL block with a nested payload BYTES block.
882
882
  /// @param writer Destination writer; `i` is advanced by the encoded CALL block length.
883
883
  /// @param target Call target identifier.
884
- /// @param resources Chain resources assigned to the call.
884
+ /// @param resources Packed resources assigned to the call.
885
885
  /// @param data Raw nested call payload.
886
886
  function appendCall(Writer memory writer, uint target, uint resources, bytes memory data) internal pure {
887
887
  appendBlock64Bytes(writer, Keys.Call, bytes32(target), bytes32(resources), data);
package/commands/Burn.sol CHANGED
@@ -30,7 +30,7 @@ abstract contract Burn is CommandBase, BurnHook {
30
30
  /// @param c Command context; `c.state` must contain BALANCE blocks.
31
31
  /// @return Empty output state.
32
32
  function burn(CommandContext calldata c) external onlyCommand returns (bytes memory) {
33
- (Cur memory state, , ) = Cursors.init(c.state, 1);
33
+ (Cur memory state, ) = Cursors.init(c.state, 1);
34
34
 
35
35
  while (state.i < state.len) {
36
36
  (bytes32 asset, uint amount) = state.unpackBalance();
@@ -32,7 +32,7 @@ abstract contract CreditAccount is CommandBase, CreditAccountHook {
32
32
  function creditAccount(
33
33
  CommandContext calldata c
34
34
  ) external onlyCommand returns (bytes memory) {
35
- (Cur memory state, , ) = Cursors.init(c.state, 1);
35
+ (Cur memory state, ) = Cursors.init(c.state, 1);
36
36
 
37
37
  while (state.i < state.len) {
38
38
  (bytes32 asset, uint amount) = state.unpackBalance();
@@ -32,7 +32,7 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
32
32
  /// The default implementation iterates AMOUNT blocks, calls
33
33
  /// `debitAccount`, and emits matching BALANCE blocks.
34
34
  function debitAccount(bytes32 account, bytes calldata request) internal virtual returns (bytes memory) {
35
- (Cur memory input, uint groups, ) = Cursors.init(request, 1);
35
+ (Cur memory input, uint groups) = Cursors.init(request, 1);
36
36
  Writer memory writer = Writers.allocBalances(groups);
37
37
 
38
38
  while (input.i < input.len) {
@@ -48,7 +48,7 @@ abstract contract Deposit is CommandBase, DepositHook {
48
48
  function deposit(
49
49
  CommandContext calldata c
50
50
  ) external onlyCommand returns (bytes memory) {
51
- (Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
51
+ (Cur memory request, uint groups) = Cursors.init(c.request, 1);
52
52
  Writer memory writer = Writers.allocBalances(groups);
53
53
 
54
54
  while (request.i < request.len) {
@@ -79,7 +79,7 @@ abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
79
79
  function depositPayable(
80
80
  CommandContext calldata c
81
81
  ) external payable onlyCommand returns (bytes memory) {
82
- (Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
82
+ (Cur memory request, uint groups) = Cursors.init(c.request, 1);
83
83
  Writer memory writer = Writers.allocBalances(groups);
84
84
  Budget memory budget = openValue();
85
85
 
@@ -31,8 +31,8 @@ abstract contract Payout is CommandBase, PayoutHook {
31
31
  /// @param c Command context; `c.state` must contain BALANCE blocks and `c.request` matching ACCOUNT blocks.
32
32
  /// @return Empty output state.
33
33
  function payout(CommandContext calldata c) external onlyCommand returns (bytes memory) {
34
- (Cur memory state, uint groups, ) = Cursors.init(c.state, 1);
35
- (Cur memory request, ) = Cursors.init(c.request, 1, groups);
34
+ (Cur memory state, uint groups) = Cursors.init(c.state, 1);
35
+ Cur memory request = Cursors.init(c.request, 1, groups);
36
36
 
37
37
  while (state.i < state.len) {
38
38
  (bytes32 asset, uint amount) = state.unpackBalance();
@@ -44,7 +44,7 @@ abstract contract Provision is CommandBase, ProvisionHook {
44
44
  /// @param c Command context; `c.request` must contain ALLOCATION blocks.
45
45
  /// @return CUSTODY block stream matching the provisioned allocations.
46
46
  function provision(CommandContext calldata c) external onlyCommand returns (bytes memory) {
47
- (Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
47
+ (Cur memory request, uint groups) = Cursors.init(c.request, 1);
48
48
  Writer memory writer = Writers.allocCustodies(groups);
49
49
 
50
50
  while (request.i < request.len) {
@@ -76,7 +76,7 @@ abstract contract ProvisionPayable is CommandBase, Payable, ProvisionPayableHook
76
76
  function provisionPayable(
77
77
  CommandContext calldata c
78
78
  ) external payable onlyCommand returns (bytes memory) {
79
- (Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
79
+ (Cur memory request, uint groups) = Cursors.init(c.request, 1);
80
80
  Writer memory writer = Writers.allocCustodies(groups);
81
81
  Budget memory budget = openValue();
82
82