@rootzero/contracts 1.5.0 → 1.7.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 (58) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/Core.sol +4 -2
  3. package/Endpoints.sol +14 -13
  4. package/Events.sol +3 -1
  5. package/README.md +9 -9
  6. package/blocks/Cursors.sol +60 -49
  7. package/blocks/Keys.sol +5 -5
  8. package/blocks/Schema.sol +4 -2
  9. package/blocks/Writers.sol +0 -35
  10. package/commands/Deposit.sol +2 -2
  11. package/commands/Provision.sol +2 -2
  12. package/commands/Recover.sol +48 -0
  13. package/commands/Relay.sol +4 -4
  14. package/commands/admin/AllowAssets.sol +2 -3
  15. package/commands/admin/Allowance.sol +2 -3
  16. package/commands/admin/Appoint.sol +2 -3
  17. package/commands/admin/Authorize.sol +2 -3
  18. package/commands/admin/Base.sol +9 -0
  19. package/commands/admin/DenyAssets.sol +2 -3
  20. package/commands/admin/Destroy.sol +2 -3
  21. package/commands/admin/Dismiss.sol +2 -3
  22. package/commands/admin/Execute.sol +3 -4
  23. package/commands/admin/Init.sol +2 -3
  24. package/commands/admin/Label.sol +2 -3
  25. package/commands/admin/Unauthorize.sol +2 -3
  26. package/core/Commitments.sol +19 -0
  27. package/core/Escrows.sol +34 -0
  28. package/core/Payable.sol +15 -28
  29. package/core/Pipeline.sol +1 -1
  30. package/core/Runtime.sol +8 -3
  31. package/docs/Schema.md +13 -2
  32. package/events/Commitment.sol +19 -0
  33. package/events/Dispatch.sol +20 -0
  34. package/events/Port.sol +22 -0
  35. package/package.json +1 -1
  36. package/ports/AllowAssets.sol +44 -0
  37. package/ports/Allowance.sol +41 -0
  38. package/ports/Base.sol +41 -0
  39. package/ports/Credit.sol +39 -0
  40. package/ports/Debit.sol +39 -0
  41. package/ports/DenyAssets.sol +44 -0
  42. package/{peer → ports}/Dispatch.sol +13 -13
  43. package/ports/Pipe.sol +43 -0
  44. package/{peer → ports}/Redeem.sol +13 -13
  45. package/ports/Settle.sol +41 -0
  46. package/utils/Layout.sol +3 -3
  47. package/utils/Nodes.sol +21 -21
  48. package/utils/Value.sol +12 -5
  49. package/events/Peer.sol +0 -22
  50. package/peer/AllowAssets.sol +0 -44
  51. package/peer/Allowance.sol +0 -41
  52. package/peer/Base.sol +0 -41
  53. package/peer/Credit.sol +0 -39
  54. package/peer/Debit.sol +0 -39
  55. package/peer/DenyAssets.sol +0 -44
  56. package/peer/Pipe.sol +0 -44
  57. package/peer/Recover.sol +0 -51
  58. package/peer/Settle.sol +0 -41
package/CHANGELOG.md CHANGED
@@ -3,6 +3,55 @@
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.7.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - Renamed peer callable surfaces to ports:
11
+ - `contracts/peer` moved to `contracts/ports`.
12
+ - `PeerEvent` / `event Peer` became `PortEvent` / `event Port`.
13
+ - `PeerBase`, `IPeer*`, and `Peer*` endpoint contracts became `PortBase`,
14
+ `IPort*`, and `Port*`.
15
+ - Peer endpoint functions and labels now use `port*` names, such as
16
+ `portPipePayable`, `portDispatchPayable`, and `portSettle`.
17
+ - Node helpers and layout tags now use `Port` terminology:
18
+ `Nodes.toPort`, `Nodes.isPort`, `Nodes.port`, and
19
+ `Nodes.portSelector`.
20
+ - Removed the generic `PortRecoverContextPayable`; recovery is now routed by
21
+ the command-level `recoverContextPayable` to concrete ports such as
22
+ `portPipePayable`.
23
+ - Renamed the `#contextRecovery` handler field from `target` to `port`.
24
+ - Changed port entrypoint calldata parameter naming to `data` to avoid
25
+ clashing with nested context `request` fields.
26
+
27
+ ### Added
28
+
29
+ - Added `RecoverContextPayable` and `#contextRecovery` for command-level
30
+ recovery routing with a commitment key, resources, handler port, and context
31
+ witness.
32
+ - Added `Dispatch(uint indexed host, uint chain, uint resources, bytes32 digest, bytes32 ref)`
33
+ as the discovery/event surface for dispatch tracking.
34
+ - Added `ContextRecovery` schema/cursor support and context schema aliases for
35
+ reusable nested block schemas.
36
+ - Added `Values.drain`, `Payable.openValue`, and `Payable.closeValue` to make
37
+ payable command budget lifecycles explicit.
38
+
39
+ ## 1.6.0
40
+
41
+ ### Added
42
+
43
+ - Added `AdminBase` as the shared base for admin commands and exported it from
44
+ `Endpoints.sol`.
45
+ - Added `Cursors.read1` and `Cursors.read2` for unchecked byte-sized calldata
46
+ reads.
47
+ - Added `NativeAsset` as a reusable base for helpers that need the local native
48
+ asset ID without the full host runtime.
49
+ - Added `Escrows` as a keyed ledger for amounts reserved outside normal
50
+ balances.
51
+ - Added `Commitment(uint indexed host, bytes32 key, bytes32 digest, uint status)`
52
+ and the `Commitments` core mixin for digest commitments and witness/recovery
53
+ flows.
54
+
6
55
  ## 1.5.0
7
56
 
8
57
  ### Breaking Changes
package/Core.sol CHANGED
@@ -1,12 +1,14 @@
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, node-call, and validation layer.
4
+ // Aggregator: re-exports the core host, runtime, access, ledger, 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";
8
8
  import { Balances, InsufficientFunds } from "./core/Balances.sol";
9
- import { Runtime } from "./core/Runtime.sol";
9
+ import { Commitments } from "./core/Commitments.sol";
10
+ import { Escrows, InsufficientEscrow } from "./core/Escrows.sol";
11
+ import { NativeAsset, Runtime } from "./core/Runtime.sol";
10
12
  import { Host, IHostIntroduction } from "./core/Host.sol";
11
13
  import { FailedCall, NodeCalls } from "./core/Calls.sol";
12
14
  import { Payable } from "./core/Payable.sol";
package/Endpoints.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 command, admin, peer, guard, and query endpoint abstractions.
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
7
  // Shared helpers
@@ -16,10 +16,12 @@ 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";
19
20
  import { RelayPayable, DispatchPayableHook } from "./commands/Relay.sol";
20
21
  import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
21
22
 
22
23
  // Admin commands
24
+ import { AdminBase } from "./commands/admin/Base.sol";
23
25
  import { AllowAssets, AllowAssetsHook } from "./commands/admin/AllowAssets.sol";
24
26
  import { Allowance, AllowanceHook } from "./commands/admin/Allowance.sol";
25
27
  import { Appoint } from "./commands/admin/Appoint.sol";
@@ -32,18 +34,17 @@ import { Init, InitHook } from "./commands/admin/Init.sol";
32
34
  import { Label } from "./commands/admin/Label.sol";
33
35
  import { Unauthorize } from "./commands/admin/Unauthorize.sol";
34
36
 
35
- // Peer endpoints
36
- import { PeerBase, encodePeerCall } from "./peer/Base.sol";
37
- import { PeerAllowAssets, IPeerAllowAssets } from "./peer/AllowAssets.sol";
38
- import { PeerAllowance, IPeerAllowance } from "./peer/Allowance.sol";
39
- import { PeerRedeemBalance, RedeemBalanceHook, IPeerRedeemBalance } from "./peer/Redeem.sol";
40
- import { PeerCreditAccount, IPeerCreditAccount } from "./peer/Credit.sol";
41
- import { PeerDebitAccount, IPeerDebitAccount } from "./peer/Debit.sol";
42
- import { PeerDenyAssets, IPeerDenyAssets } from "./peer/DenyAssets.sol";
43
- import { PeerPipePayable, IPeerPipePayable } from "./peer/Pipe.sol";
44
- import { PeerRecover, RecoverHook, IPeerRecover } from "./peer/Recover.sol";
45
- import { PeerDispatchPayable, IPeerDispatchPayable } from "./peer/Dispatch.sol";
46
- import { PeerSettle, IPeerSettle } from "./peer/Settle.sol";
37
+ // 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";
47
48
 
48
49
  // Guard endpoints
49
50
  import { GuardBase, encodeGuardCall } from "./guards/Base.sol";
package/Events.sol CHANGED
@@ -10,6 +10,8 @@ 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
+ import { DispatchEvent } from "./events/Dispatch.sol";
13
15
  import { PositionEvent } from "./events/Position.sol";
14
16
  import { ReceivedEvent } from "./events/Received.sol";
15
17
  import { EventEmitter } from "./events/Emitter.sol";
@@ -19,7 +21,7 @@ import { IntroductionEvent } from "./events/Introduction.sol";
19
21
  import { LabeledEvent } from "./events/Labeled.sol";
20
22
  import { LockedEvent } from "./events/Locked.sol";
21
23
  import { NodeEvent } from "./events/Node.sol";
22
- import { PeerEvent } from "./events/Peer.sol";
24
+ import { PortEvent } from "./events/Port.sol";
23
25
  import { QueryEvent } from "./events/Query.sol";
24
26
  import { RootedEvent } from "./events/Rooted.sol";
25
27
  import { RouteEvent } from "./events/Route.sol";
package/README.md CHANGED
@@ -271,8 +271,8 @@ blocks executed in order within one transaction:
271
271
 
272
272
  Each step names a target command, the resources it may spend, and its request.
273
273
  The state threads through: whatever one command returns becomes the input
274
- state of the next, and the final state must be empty value cannot be left
275
- dangling at the end of a pipeline. This is the core of `Pipeline.pipe`:
274
+ state of the next, and the final state must be empty. This is the core of
275
+ `Pipeline.pipe`:
276
276
 
277
277
  ```solidity
278
278
  while (input.i < input.len) {
@@ -304,19 +304,19 @@ response: #accountAmount { bytes32 account, bytes32 asset, uint amount }
304
304
  Like commands, every query announces its request and response schemas at
305
305
  deployment, so tooling knows how to call it without artifacts.
306
306
 
307
- ## Peers
307
+ ## Ports
308
308
 
309
- Peers are the host-to-host surfaces, callable only by trusted hosts. The two
309
+ Ports are the host-to-host surfaces, callable only by trusted peer hosts. The two
310
310
  central ones are batches all the way down:
311
311
 
312
- - `peerSettle` consumes `#transaction { bytes32 from, bytes32 to, bytes32 asset,
312
+ - `portSettle` consumes `#transaction { bytes32 from, bytes32 to, bytes32 asset,
313
313
  uint amount }` blocks, debiting `from` and crediting `to` per
314
314
  block — how two hosts record settlement between their ledgers.
315
- - `peerPipePayable` consumes `#pipe` blocks, each carrying an account, an
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 with its own resource budget.
317
+ host, executed locally against the peer call's shared value budget.
318
318
 
319
- This is also the cross-chain mechanism. `relayPayable` (or `peerDispatchPayable`)
319
+ This is also the cross-chain mechanism. `relayPayable` (or `portDispatchPayable`)
320
320
  wraps a pipe and addresses it to a chain; a bridge adapter moves the **raw
321
321
  bytes**; the destination host parses them with the same cursor rules and runs
322
322
  the same pipeline loop. Nothing in the payload is EVM-specific — step targets
@@ -363,7 +363,7 @@ Repo layout:
363
363
 
364
364
  - `contracts/core` — host, access control, balances, pipeline, validation
365
365
  - `contracts/commands` — standard commands and admin commands
366
- - `contracts/peer` — peer surfaces for inter-host and cross-chain flows
366
+ - `contracts/ports` — peer surfaces for inter-host and cross-chain flows
367
367
  - `contracts/guards` — guardian direct actions
368
368
  - `contracts/queries` — read-only query endpoints
369
369
  - `contracts/blocks` — block schema, cursor parsing, writers
@@ -548,28 +548,13 @@ library Cursors {
548
548
  return createBlock(Keys.Context, bytes.concat(account, toBytesBlock(state), toBytesBlock(request)));
549
549
  }
550
550
 
551
- /// @notice Encode a PIPE block.
552
- /// @param resources Chain resources assigned to the pipe.
553
- /// @param account Command account identifier.
554
- /// @param state Embedded state block stream.
555
- /// @param steps Embedded step block stream.
556
- /// @return Encoded PIPE block bytes.
557
- function toPipeBlock(
558
- uint resources,
559
- bytes32 account,
560
- bytes memory state,
561
- bytes memory steps
562
- ) internal pure returns (bytes memory) {
563
- return createBlock(Keys.Pipe, bytes.concat(bytes32(resources), toContextBlock(account, state, steps)));
564
- }
565
-
566
551
  /// @notice Encode a RELAY block.
567
552
  /// @param chain Destination chain node ID.
568
- /// @param resources Chain-adapter-specific resources for the destination pipe.
569
- /// @param steps Nested step block stream.
553
+ /// @param resources Chain-adapter-specific resources for the destination context.
554
+ /// @param request Nested request block stream.
570
555
  /// @return Encoded RELAY block bytes.
571
- function toRelayBlock(uint chain, uint resources, bytes memory steps) internal pure returns (bytes memory) {
572
- return createBlock(Keys.Relay, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(steps)));
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)));
573
558
  }
574
559
 
575
560
  /// @notice Encode a DISPATCH block.
@@ -599,6 +584,30 @@ library Cursors {
599
584
  cur.i += n;
600
585
  }
601
586
 
587
+ /// @notice Read the next byte from the cursor and advance by 1 byte.
588
+ /// @dev Performs no bounds, key, length, or cursor checks.
589
+ /// @param cur Cursor whose current position is advanced by 1 byte.
590
+ /// @return value Loaded bytes1 value.
591
+ function read1(Cur memory cur) internal pure returns (bytes1 value) {
592
+ uint abs = cur.offset + cur.i;
593
+ assembly ("memory-safe") {
594
+ value := calldataload(abs)
595
+ }
596
+ cur.i += 1;
597
+ }
598
+
599
+ /// @notice Read the next 2 bytes from the cursor and advance by 2 bytes.
600
+ /// @dev Performs no bounds, key, length, or cursor checks.
601
+ /// @param cur Cursor whose current position is advanced by 2 bytes.
602
+ /// @return value Loaded bytes2 value.
603
+ function read2(Cur memory cur) internal pure returns (bytes2 value) {
604
+ uint abs = cur.offset + cur.i;
605
+ assembly ("memory-safe") {
606
+ value := calldataload(abs)
607
+ }
608
+ cur.i += 2;
609
+ }
610
+
602
611
  /// @notice Read the next 4 bytes from the cursor and advance by 4 bytes.
603
612
  /// @dev Performs no bounds, key, length, or cursor checks.
604
613
  /// @param cur Cursor whose current position is advanced by 4 bytes.
@@ -1131,33 +1140,18 @@ library Cursors {
1131
1140
  cur.exit(end);
1132
1141
  }
1133
1142
 
1134
- /// @notice Consume a PIPE block and return its resources and context fields.
1135
- /// @param cur Cursor; advanced past the block.
1136
- /// @return resources Chain resources assigned to the pipe.
1137
- /// @return account Command account identifier.
1138
- /// @return state Embedded state block stream.
1139
- /// @return steps Embedded step block stream.
1140
- function unpackPipe(
1141
- Cur memory cur
1142
- ) internal pure returns (uint resources, bytes32 account, bytes calldata state, bytes calldata steps) {
1143
- uint end = cur.enter(Keys.Pipe, 32 + Sizes.Header + 32 + 2 * Sizes.Header, 0);
1144
- resources = uint(cur.read32());
1145
- (account, state, steps) = cur.unpackContext();
1146
- cur.exit(end);
1147
- }
1148
-
1149
- /// @notice Consume a RELAY block and return its destination chain, resources, and step stream.
1143
+ /// @notice Consume a RELAY block and return its destination chain, resources, and request stream.
1150
1144
  /// @param cur Cursor; advanced past the block.
1151
1145
  /// @return chain Destination chain node ID.
1152
- /// @return resources Chain-adapter-specific resources for the destination pipe.
1153
- /// @return steps Embedded step block stream.
1146
+ /// @return resources Chain-adapter-specific resources for the destination context.
1147
+ /// @return request Embedded request block stream.
1154
1148
  function unpackRelay(
1155
1149
  Cur memory cur
1156
- ) internal pure returns (uint chain, uint resources, bytes calldata steps) {
1150
+ ) internal pure returns (uint chain, uint resources, bytes calldata request) {
1157
1151
  uint end = cur.enter(Keys.Relay, 64 + Sizes.Header, 0);
1158
1152
  chain = cur.readUint();
1159
1153
  resources = cur.readUint();
1160
- steps = cur.unpackBytes();
1154
+ request = cur.unpackBytes();
1161
1155
  cur.exit(end);
1162
1156
  }
1163
1157
 
@@ -1176,6 +1170,23 @@ library Cursors {
1176
1170
  cur.exit(end);
1177
1171
  }
1178
1172
 
1173
+ /// @notice Consume a CONTEXT_RECOVERY block and return its port, key, resources, and embedded context cursor.
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(
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();
1185
+ resources = cur.readUint();
1186
+ context = cur.take(Keys.Context);
1187
+ cur.exit(end);
1188
+ }
1189
+
1179
1190
  // Type-specific validators
1180
1191
 
1181
1192
  /// @notice Validate an AUTH block at position `i` and extract deadline and proof.
@@ -1364,21 +1375,21 @@ library Cursors {
1364
1375
  // Transform helpers
1365
1376
  // -------------------------------------------------------------------------
1366
1377
 
1367
- /// @notice Consume a RELAY block and encode its destination pipe payload.
1378
+ /// @notice Consume a RELAY block and encode its destination context payload.
1368
1379
  /// @param cur Cursor; advanced past the RELAY block.
1369
- /// @param account Account identifier to embed in the destination pipe context.
1370
- /// @param state State block stream to embed in the destination pipe context.
1380
+ /// @param account Account identifier to embed in the destination context.
1381
+ /// @param state State block stream to embed in the destination context.
1371
1382
  /// @return chain Destination chain node ID.
1372
- /// @return resources Chain resources assigned to the destination pipe.
1373
- /// @return pipe Encoded PIPE block containing `account`, `state`, and relay steps.
1374
- function relayToPipe(
1383
+ /// @return resources Chain resources assigned to the destination context.
1384
+ /// @return context Encoded CONTEXT block containing `account`, `state`, and relay request.
1385
+ function relayToContext(
1375
1386
  Cur memory cur,
1376
1387
  bytes32 account,
1377
1388
  bytes calldata state
1378
- ) internal pure returns (uint chain, uint resources, bytes memory pipe) {
1379
- bytes calldata steps;
1380
- (chain, resources, steps) = cur.unpackRelay();
1381
- pipe = toPipeBlock(resources, account, bytes(state), bytes(steps));
1389
+ ) internal pure returns (uint chain, uint resources, bytes memory context) {
1390
+ bytes calldata request;
1391
+ (chain, resources, request) = cur.unpackRelay();
1392
+ context = toContextBlock(account, bytes(state), bytes(request));
1382
1393
  }
1383
1394
 
1384
1395
  // -------------------------------------------------------------------------
package/blocks/Keys.sol CHANGED
@@ -41,16 +41,16 @@ 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 pipe relay - (uint chain, uint resources, #bytes as steps)
44
+ /// @dev Cross-chain relay request - (uint chain, uint resources, #bytes as request)
45
45
  bytes4 constant Relay = bytes4(keccak256("#relay"));
46
+ /// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
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"));
46
50
  /// @dev Cross-chain encoded payload dispatch - (uint chain, uint resources, #bytes as payload)
47
51
  bytes4 constant Dispatch = bytes4(keccak256("#dispatch"));
48
52
  /// @dev Raw external call - (uint target, uint resources, #bytes as payload)
49
53
  bytes4 constant Call = bytes4(keccak256("#call"));
50
- /// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
51
- bytes4 constant Context = bytes4(keccak256("#context"));
52
- /// @dev Pipeline invocation - (uint resources, #context)
53
- bytes4 constant Pipe = bytes4(keccak256("#pipe"));
54
54
  /// @dev Authentication proof - (uint cid, uint deadline, #bytes as proof); must appear last in its segment
55
55
  bytes4 constant Auth = bytes4(keccak256("#auth"));
56
56
  /// @dev Asset descriptor without amount - (bytes32 asset)
package/blocks/Schema.sol CHANGED
@@ -21,6 +21,8 @@ pragma solidity ^0.8.33;
21
21
  // stable format everywhere. EVM resources use the low 128 bits as native value.
22
22
  // - dotted field names and aliases, e.g. `dst.chain` or `#bytes as dst.payload`,
23
23
  // are offchain projection metadata only and do not change runtime encoding
24
+ // - a child block without an inline body, e.g. `#context as witness`, may resolve
25
+ // to a known schema in the active schema context; unresolved aliases are invalid
24
26
  // - fixed fields are packed in declaration order
25
27
  // - blocks have fixed fields followed by a dynamic child-block tail
26
28
  // - child block tails are embedded directly, without an extra stream wrapper
@@ -69,10 +71,10 @@ library Schemas {
69
71
  string constant Allowance = "#allowance { uint host, bytes32 asset, uint amount }";
70
72
  string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, uint amount }";
71
73
  string constant Context = "#context { bytes32 account, #bytes as state, #bytes as request }";
72
- string constant Pipe = "#pipe { uint resources, #context { bytes32 account, #bytes as state, #bytes as steps } }";
74
+ string constant ContextRecovery = "#contextRecovery { uint port, bytes32 key, uint resources, #context as witness }";
73
75
  string constant Call = "#call { uint target, uint resources, #bytes as payload }";
74
76
  string constant Step = "#step { uint target, uint resources, #bytes as request }";
75
- string constant Relay = "#relay { uint chain, uint resources, #bytes as steps }";
77
+ string constant Relay = "#relay { uint chain, uint resources, #bytes as request }";
76
78
  string constant Dispatch = "#dispatch { uint chain, uint resources, #bytes as payload }";
77
79
  string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
78
80
  string constant Fee = "#fee { uint amount }";
@@ -28,7 +28,6 @@ library Hints {
28
28
  uint constant Step = 256;
29
29
  uint constant Call = 256;
30
30
  uint constant Context = 512;
31
- uint constant Pipe = 608;
32
31
  }
33
32
 
34
33
  /// @title Writers
@@ -233,14 +232,6 @@ library Writers {
233
232
  return allocFromHint(count, Hints.Context);
234
233
  }
235
234
 
236
- /// @notice Allocate a writer for `count` PIPE blocks using a per-block capacity hint.
237
- /// @dev The backing buffer expands automatically if encoded pipes exceed the initial hint.
238
- /// @param count Number of pipe blocks to allocate space for.
239
- /// @return writer Allocated growable writer.
240
- function allocPipes(uint count) internal pure returns (Writer memory writer) {
241
- return allocFromHint(count, Hints.Pipe);
242
- }
243
-
244
235
  // -------------------------------------------------------------------------
245
236
  // Fixed-width write helpers
246
237
  // -------------------------------------------------------------------------
@@ -905,32 +896,6 @@ library Writers {
905
896
  appendBlock32BytesBytes(writer, Keys.Context, account, state, request);
906
897
  }
907
898
 
908
- /// @notice Append a PIPE block with a nested CONTEXT block.
909
- /// @param writer Destination writer; `i` is advanced by the encoded PIPE block length.
910
- /// @param resources Chain resources assigned to the pipe.
911
- /// @param account Command account identifier.
912
- /// @param state Raw nested state payload.
913
- /// @param steps Raw nested step payload.
914
- function appendPipe(
915
- Writer memory writer,
916
- uint resources,
917
- bytes32 account,
918
- bytes memory state,
919
- bytes memory steps
920
- ) internal pure {
921
- uint i = writer.i;
922
- uint len = 64 + 3 * Sizes.Header + state.length + steps.length;
923
- uint next = i + Sizes.Header + len;
924
- i = reserve(writer, next, next);
925
-
926
- uint p = writeHeader(writer.dst, i, Keys.Pipe, uint32(max32(len)));
927
- assembly ("memory-safe") {
928
- mstore(add(p, 0x08), resources)
929
- }
930
-
931
- writeBlock32BytesBytes(writer.dst, i + Sizes.Header + 32, Keys.Context, account, state, steps);
932
- }
933
-
934
899
  /// @notice Append a STATUS form block.
935
900
  /// @param writer Destination writer; `i` is advanced by `Sizes.Status`.
936
901
  /// @param code Status code to encode.
@@ -81,7 +81,7 @@ abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
81
81
  ) external payable onlyCommand returns (bytes memory) {
82
82
  (Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
83
83
  Writer memory writer = Writers.allocBalances(groups);
84
- Budget memory budget = valueBudget();
84
+ Budget memory budget = openValue();
85
85
 
86
86
  while (request.i < request.len) {
87
87
  (bytes32 asset, uint amount) = request.unpackAmount();
@@ -89,7 +89,7 @@ abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
89
89
  writer.appendBalance(asset, amount);
90
90
  }
91
91
 
92
- settleValue(c.account, budget);
92
+ closeValue(c.account, budget);
93
93
  request.complete();
94
94
  return writer.finish();
95
95
  }
@@ -78,7 +78,7 @@ abstract contract ProvisionPayable is CommandBase, Payable, ProvisionPayableHook
78
78
  ) external payable onlyCommand returns (bytes memory) {
79
79
  (Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
80
80
  Writer memory writer = Writers.allocCustodies(groups);
81
- Budget memory budget = valueBudget();
81
+ Budget memory budget = openValue();
82
82
 
83
83
  while (request.i < request.len) {
84
84
  HostAmount memory allocation = request.unpackAllocationValue();
@@ -86,7 +86,7 @@ abstract contract ProvisionPayable is CommandBase, Payable, ProvisionPayableHook
86
86
  writer.appendCustody(allocation);
87
87
  }
88
88
 
89
- settleValue(c.account, budget);
89
+ closeValue(c.account, budget);
90
90
  request.complete();
91
91
  return writer.finish();
92
92
  }
@@ -0,0 +1,48 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {CommandBase, CommandContext, Keys} from "./Base.sol";
5
+ import {Payable} from "../core/Payable.sol";
6
+ import {Cursors, Cur, Schemas} from "../Cursors.sol";
7
+ import {Budget} from "../utils/Value.sol";
8
+
9
+ using Cursors for Cur;
10
+
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.
23
+ /// Produces no output state.
24
+ abstract contract RecoverContextPayable is CommandBase, Payable, RecoverContextPayableHook {
25
+ uint internal immutable recoverContextPayableId = commandId(this.recoverContextPayable.selector);
26
+
27
+ constructor() {
28
+ emit Command(host, recoverContextPayableId, "1:0:0", Schemas.ContextRecovery, Keys.Empty, Keys.Empty, true);
29
+ emit Labeled(recoverContextPayableId, bytes32(0), "recoverContextPayable");
30
+ }
31
+
32
+ /// @notice Recover each ContextRecovery block in the command request.
33
+ /// @param c Command context; `c.request` must contain ContextRecovery blocks.
34
+ /// @return Empty output state.
35
+ function recoverContextPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory) {
36
+ (Cur memory request, , ) = Cursors.init(c.request, 1);
37
+ Budget memory budget = openValue();
38
+
39
+ while (request.i < request.len) {
40
+ (uint port, bytes32 key, uint resources, Cur memory context) = request.unpackContextRecovery();
41
+ recoverContext(port, key, resources, context, budget);
42
+ }
43
+
44
+ closeValue(c.account, budget);
45
+ request.complete();
46
+ return "";
47
+ }
48
+ }
@@ -37,12 +37,12 @@ abstract contract RelayPayable is CommandBase, Payable, DispatchPayableHook {
37
37
  /// @return output Empty output state.
38
38
  function relayPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory output) {
39
39
  (Cur memory request, ) = Cursors.init(c.request, 1, 1);
40
- Budget memory budget = valueBudget();
40
+ Budget memory budget = openValue();
41
41
 
42
- (uint chain, uint resources, bytes memory pipe) = request.relayToPipe(c.account, c.state);
43
- dispatch(chain, resources, pipe, budget);
42
+ (uint chain, uint resources, bytes memory context) = request.relayToContext(c.account, c.state);
43
+ dispatch(chain, resources, context, budget);
44
44
 
45
- settleValue(c.account, budget);
45
+ closeValue(c.account, budget);
46
46
  request.complete();
47
47
  return "";
48
48
  }
@@ -1,9 +1,8 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  abstract contract AllowAssetsHook {
@@ -16,7 +15,7 @@ abstract contract AllowAssetsHook {
16
15
  /// @title AllowAssets
17
16
  /// @notice Admin command that permits a list of assets via a virtual hook.
18
17
  /// Each ASSET block in the request calls `allowAsset`. Only callable by the admin account.
19
- abstract contract AllowAssets is CommandBase, AdminEvent, AllowAssetsHook {
18
+ abstract contract AllowAssets is AdminBase, AllowAssetsHook {
20
19
  uint internal immutable allowAssetsId = commandId(this.allowAssets.selector);
21
20
 
22
21
  constructor() {
@@ -1,9 +1,8 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {CommandBase, CommandContext, Keys} from "../Base.sol";
4
+ import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
5
  import {Cursors, Cur, Schemas} from "../../Cursors.sol";
6
- import {AdminEvent} from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  abstract contract AllowanceHook {
@@ -20,7 +19,7 @@ abstract contract AllowanceHook {
20
19
  /// @title Allowance
21
20
  /// @notice Admin command that applies cross-host allowance entries via a virtual hook.
22
21
  /// Each ALLOWANCE block grants or updates a host-scoped asset cap. Only callable by the admin account.
23
- abstract contract Allowance is CommandBase, AdminEvent, AllowanceHook {
22
+ abstract contract Allowance is AdminBase, AllowanceHook {
24
23
  uint internal immutable allowanceId = commandId(this.allowance.selector);
25
24
 
26
25
  constructor() {
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  /// @title Appoint
10
9
  /// @notice Admin command that grants guardian status to a list of account IDs.
11
10
  /// Each ACCOUNT block in the request is enabled as a guardian on the host.
12
11
  /// Only callable by the admin account.
13
- abstract contract Appoint is CommandBase, AdminEvent {
12
+ abstract contract Appoint is AdminBase {
14
13
  uint internal immutable appointId = commandId(this.appoint.selector);
15
14
 
16
15
  constructor() {
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  /// @title Authorize
10
9
  /// @notice Admin command that grants authorization to a list of node IDs.
11
10
  /// Each NODE block in the request is authorized on the host.
12
11
  /// Only callable by the admin account.
13
- abstract contract Authorize is CommandBase, AdminEvent {
12
+ abstract contract Authorize is AdminBase {
14
13
  uint internal immutable authorizeId = commandId(this.authorize.selector);
15
14
 
16
15
  constructor() {