@rootzero/contracts 1.7.0 → 1.9.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,46 @@
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.9.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - Renamed relay and dispatch routing fields from `chain` to `portal` across
11
+ schemas, cursor helpers, dispatch hooks, and dispatch/route events.
12
+ - Replaced the context-specific `RecoverContextPayable` / `#contextRecovery`
13
+ surface with generic `RecoverPayable` / `#recover` using byte witnesses.
14
+ - Renamed the `Dispatch` event correlation field from `ref` to `key`.
15
+ - Replaced `DispatchPayableHook.dispatch` with `RoutePayableHook.route` in the
16
+ portal core layer.
17
+ - Added `status` to `Route(uint indexed host, uint portal, uint status)`
18
+ so routes can be removed by emitting zero status.
19
+ - Added `Undelivered(uint indexed host, bytes32 key, bytes32 digest)` for portal
20
+ messages that could not be delivered to their handler port.
21
+ - Added `Resolved(uint indexed host, bytes32 key)` as the
22
+ matching event for resolved undelivered digests.
23
+ - Removed the generic `Commitments` core mixin and `Commitment` event in favor
24
+ of domain-specific events such as `Undelivered` and `Resolved`.
25
+
26
+ ## 1.8.0
27
+
28
+ ### Breaking Changes
29
+
30
+ - Removed per-port `IPort*` interfaces. Port callers should use port node IDs,
31
+ discovery metadata, and `PortCalls.callPort`.
32
+ - Removed unused standalone ABI encoder helpers: `encodePortCall`,
33
+ `encodeGuardCall`, and `encodeQueryCall`.
34
+ - Reworked `NodeCalls` into a low-level node-call layer:
35
+ - `callAddr` and `queryAddr` were removed.
36
+ - `callTo` and `queryTo` were removed.
37
+ - Raw node calls now use `rawCall`, `tryRawCall`, and `rawQuery`.
38
+
39
+ ### Added
40
+
41
+ - Added `trustedCall`, `tryTrustedCall`, and `trustedQuery` as shared trusted
42
+ wrappers over the raw node-call helpers.
43
+ - Added `CommandCalls.callCommand` and `PortCalls.callPort` for selector-based
44
+ trusted calls to command and port nodes.
45
+
6
46
  ## 1.7.0
7
47
 
8
48
  ### Breaking Changes
package/Core.sol CHANGED
@@ -6,13 +6,13 @@ 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
- import { FailedCall, NodeCalls } from "./core/Calls.sol";
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, RecoverHook, RoutePayableHook } from "./core/Portal.sol";
16
16
  import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
17
17
  import { Validator } from "./core/Validator.sol";
18
18
 
package/Endpoints.sol CHANGED
@@ -16,8 +16,9 @@ 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 { RecoverPayable } from "./commands/Recover.sol";
20
+ import { RelayPayable } from "./commands/Relay.sol";
21
+ import { RecoverHook, RoutePayableHook } from "./core/Portal.sol";
21
22
  import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
22
23
 
23
24
  // Admin commands
@@ -35,23 +36,23 @@ import { Label } from "./commands/admin/Label.sol";
35
36
  import { Unauthorize } from "./commands/admin/Unauthorize.sol";
36
37
 
37
38
  // Port endpoints
38
- import { PortBase, encodePortCall } from "./ports/Base.sol";
39
- import { PortAllowAssets, IPortAllowAssets } from "./ports/AllowAssets.sol";
40
- import { PortAllowance, IPortAllowance } from "./ports/Allowance.sol";
41
- import { PortRedeemBalance, RedeemBalanceHook, IPortRedeemBalance } from "./ports/Redeem.sol";
42
- import { PortCreditAccount, IPortCreditAccount } from "./ports/Credit.sol";
43
- import { PortDebitAccount, IPortDebitAccount } from "./ports/Debit.sol";
44
- import { PortDenyAssets, IPortDenyAssets } from "./ports/DenyAssets.sol";
45
- import { PortPipePayable, IPortPipePayable } from "./ports/Pipe.sol";
46
- import { PortDispatchPayable, IPortDispatchPayable } from "./ports/Dispatch.sol";
47
- import { PortSettle, IPortSettle } from "./ports/Settle.sol";
39
+ import { PortBase } from "./ports/Base.sol";
40
+ import { PortAllowAssets } from "./ports/AllowAssets.sol";
41
+ import { PortAllowance } from "./ports/Allowance.sol";
42
+ import { PortRedeemBalance, RedeemBalanceHook } from "./ports/Redeem.sol";
43
+ import { PortCreditAccount } from "./ports/Credit.sol";
44
+ import { PortDebitAccount } from "./ports/Debit.sol";
45
+ import { PortDenyAssets } from "./ports/DenyAssets.sol";
46
+ import { PortPipePayable } from "./ports/Pipe.sol";
47
+ import { PortDispatchPayable } from "./ports/Dispatch.sol";
48
+ import { PortSettle } from "./ports/Settle.sol";
48
49
 
49
50
  // Guard endpoints
50
- import { GuardBase, encodeGuardCall } from "./guards/Base.sol";
51
+ import { GuardBase } from "./guards/Base.sol";
51
52
  import { Revoke } from "./guards/Revoke.sol";
52
53
 
53
54
  // Query endpoints
54
- import { QueryBase, encodeQueryCall } from "./queries/Base.sol";
55
+ import { QueryBase } from "./queries/Base.sol";
55
56
  import { AssetStatus, AssetStatusHook } from "./queries/Assets.sol";
56
57
  import { GetBalances, GetBalancesHook } from "./queries/Balances.sol";
57
58
  import { GetPosition, GetPositionHook } from "./queries/Positions.sol";
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 { ResolvedEvent } from "./events/Resolved.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
@@ -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
@@ -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
  // -------------------------------------------------------------------------
@@ -1100,7 +1100,7 @@ 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);
@@ -1114,7 +1114,7 @@ library Cursors {
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);
@@ -1140,50 +1140,50 @@ library Cursors {
1140
1140
  cur.exit(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
1155
  cur.exit(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
1170
  cur.exit(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);
1185
+ key = cur.read32();
1186
+ witness = cur.unpackBytes();
1187
1187
  cur.exit(end);
1188
1188
  }
1189
1189
 
@@ -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);
@@ -3,42 +3,35 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import {CommandBase, CommandContext, Keys} from "./Base.sol";
5
5
  import {Payable} from "../core/Payable.sol";
6
+ import {RecoverHook} from "../core/Portal.sol";
6
7
  import {Cursors, Cur, Schemas} from "../Cursors.sol";
7
8
  import {Budget} from "../utils/Value.sol";
8
9
 
9
10
  using Cursors for Cur;
10
11
 
11
- abstract contract RecoverContextPayableHook {
12
- /// @notice Override to recover one committed context witness.
13
- /// @param port Recovery handler port node ID.
14
- /// @param key Commitment or recovery lookup key.
15
- /// @param resources Chain resources assigned to the recovery attempt.
16
- /// @param context Cursor scoped to the embedded CONTEXT witness block.
17
- /// @param budget Mutable native-value budget available to the recovery attempt.
18
- function recoverContext(uint port, bytes32 key, uint resources, Cur memory context, Budget memory budget) internal virtual;
19
- }
20
-
21
- /// @title RecoverContextPayable
22
- /// @notice Command that forwards ContextRecovery request blocks to a virtual hook.
12
+ /// @title RecoverPayable
13
+ /// @notice Command that forwards recover request blocks to a virtual hook.
14
+ /// Recovery is witness-driven: the command account pays and receives leftover
15
+ /// value settlement, but the recovered subject is defined by each witness.
23
16
  /// Produces no output state.
24
- abstract contract RecoverContextPayable is CommandBase, Payable, RecoverContextPayableHook {
25
- uint internal immutable recoverContextPayableId = commandId(this.recoverContextPayable.selector);
17
+ abstract contract RecoverPayable is CommandBase, Payable, RecoverHook {
18
+ uint internal immutable recoverPayableId = commandId(this.recoverPayable.selector);
26
19
 
27
20
  constructor() {
28
- emit Command(host, recoverContextPayableId, "1:0:0", Schemas.ContextRecovery, Keys.Empty, Keys.Empty, true);
29
- emit Labeled(recoverContextPayableId, bytes32(0), "recoverContextPayable");
21
+ emit Command(host, recoverPayableId, "1:0:0", Schemas.Recover, Keys.Empty, Keys.Empty, true);
22
+ emit Labeled(recoverPayableId, bytes32(0), "recoverPayable");
30
23
  }
31
24
 
32
- /// @notice Recover each ContextRecovery block in the command request.
33
- /// @param c Command context; `c.request` must contain ContextRecovery blocks.
25
+ /// @notice Recover each recover block in the command request.
26
+ /// @param c Command context; `c.request` must contain Recover blocks.
34
27
  /// @return Empty output state.
35
- function recoverContextPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory) {
28
+ function recoverPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory) {
36
29
  (Cur memory request, , ) = Cursors.init(c.request, 1);
37
30
  Budget memory budget = openValue();
38
31
 
39
32
  while (request.i < request.len) {
40
- (uint port, bytes32 key, uint resources, Cur memory context) = request.unpackContextRecovery();
41
- recoverContext(port, key, resources, context, budget);
33
+ (uint handler, uint resources, bytes32 key, bytes calldata witness) = request.unpackRecover();
34
+ recover(handler, key, witness, useValue(budget, resources));
42
35
  }
43
36
 
44
37
  closeValue(c.account, budget);
@@ -3,28 +3,18 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import {CommandBase, CommandContext, Keys} from "./Base.sol";
5
5
  import {Payable} from "../core/Payable.sol";
6
+ import {RoutePayableHook} from "../core/Portal.sol";
6
7
  import {Cursors, Cur, Schemas} from "../Cursors.sol";
7
8
  import {Budget} from "../utils/Value.sol";
8
9
 
9
10
  using Cursors for Cur;
10
11
 
11
- abstract contract DispatchPayableHook {
12
- /// @notice Override to dispatch an encoded payload to `chain`.
13
- /// @param chain Destination chain node ID.
14
- /// @param resources Chain-adapter-specific destination resources. EVM adapters
15
- /// may interpret this as packed execution gas and destination value.
16
- /// @param payload Encoded payload ready for the transport layer.
17
- /// @param budget Source-chain native-value budget available for transport
18
- /// fees and destination resource funding.
19
- function dispatch(uint chain, uint resources, bytes memory payload, Budget memory budget) internal virtual;
20
- }
21
-
22
12
  /// @title RelayPayable
23
13
  /// @notice Command that forwards one RELAY block to a host-defined relay hook.
24
14
  /// Reverts unless the request contains exactly one RELAY block, preventing
25
15
  /// the same state from being duplicated across multiple relays.
26
16
  /// Produces no output state.
27
- abstract contract RelayPayable is CommandBase, Payable, DispatchPayableHook {
17
+ abstract contract RelayPayable is CommandBase, Payable, RoutePayableHook {
28
18
  uint internal immutable relayPayableId = commandId(this.relayPayable.selector);
29
19
 
30
20
  constructor() {
@@ -39,9 +29,9 @@ abstract contract RelayPayable is CommandBase, Payable, DispatchPayableHook {
39
29
  (Cur memory request, ) = Cursors.init(c.request, 1, 1);
40
30
  Budget memory budget = openValue();
41
31
 
42
- (uint chain, uint resources, bytes memory context) = request.relayToContext(c.account, c.state);
43
- dispatch(chain, resources, context, budget);
44
-
32
+ (uint portal, uint resources, bytes memory context) = request.relayToContext(c.account, c.state);
33
+ route(portal, resources, context, budget);
34
+
45
35
  closeValue(c.account, budget);
46
36
  request.complete();
47
37
  return "";
@@ -18,6 +18,7 @@ abstract contract DestroyHook {
18
18
  abstract contract Destroy is AdminBase, DestroyHook {
19
19
  uint internal immutable destroyId = commandId(this.destroy.selector);
20
20
 
21
+ /// @param input Request schema advertised for destruction input.
21
22
  constructor(string memory input) {
22
23
  emit Admin(host, destroyId, "1:0:0", input, Keys.Empty, Keys.Empty, false);
23
24
  emit Labeled(destroyId, bytes32(0), "destroy");
@@ -5,13 +5,12 @@ import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
5
  import {Payable} from "../../core/Payable.sol";
6
6
  import {Cursors, Cur, Schemas} from "../../Cursors.sol";
7
7
  import {Budget} from "../../utils/Value.sol";
8
- import {Nodes} from "../../utils/Nodes.sol";
9
8
 
10
9
  using Cursors for Cur;
11
10
 
12
11
  /// @title ExecutePayable
13
12
  /// @notice Admin command that forwards raw calldata to one or more target nodes.
14
- /// Each CALL block specifies a target node ID, chain resources, and raw calldata payload.
13
+ /// Each CALL block specifies a target node ID, packed resources, and raw calldata payload.
15
14
  /// Only callable by the admin account.
16
15
  /// Unspent top-level `msg.value` remains on this host.
17
16
  abstract contract ExecutePayable is AdminBase, Payable {
@@ -31,8 +30,7 @@ abstract contract ExecutePayable is AdminBase, Payable {
31
30
 
32
31
  while (request.i < request.len) {
33
32
  (uint target, uint resources, bytes calldata data) = request.unpackCall();
34
- address addr = Nodes.addr(target);
35
- callAddr(addr, useValue(budget, resources), data);
33
+ rawCall(target, useValue(budget, resources), data);
36
34
  }
37
35
 
38
36
  request.complete();
@@ -18,6 +18,7 @@ abstract contract InitHook {
18
18
  abstract contract Init is AdminBase, InitHook {
19
19
  uint internal immutable initId = commandId(this.init.selector);
20
20
 
21
+ /// @param input Request schema advertised for initialization input.
21
22
  constructor(string memory input) {
22
23
  emit Admin(host, initId, "1:0:0", input, Keys.Empty, Keys.Empty, false);
23
24
  emit Labeled(initId, bytes32(0), "init");
package/core/Access.sol CHANGED
@@ -30,6 +30,7 @@ abstract contract AccessControl is Runtime, NodeEvent, GuardianEvent {
30
30
  /// @dev Thrown when a caller, account, or node lacks required access.
31
31
  error AccessDenied();
32
32
 
33
+ /// @param cmdr Commander address, or zero to make this contract self-managed.
33
34
  constructor(address cmdr) {
34
35
  commander = addrOr(cmdr, address(this));
35
36
  admin = Accounts.toAdmin(commander);