@rootzero/contracts 1.0.1 → 1.2.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 (56) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/Endpoints.sol +2 -1
  3. package/Events.sol +1 -0
  4. package/blocks/Cursors.sol +176 -116
  5. package/blocks/Keys.sol +11 -7
  6. package/blocks/Schema.sol +11 -5
  7. package/blocks/Writers.sol +25 -9
  8. package/commands/Base.sol +10 -9
  9. package/commands/Burn.sol +3 -4
  10. package/commands/Credit.sol +3 -4
  11. package/commands/Debit.sol +3 -4
  12. package/commands/Deposit.sol +6 -8
  13. package/commands/Payout.sol +3 -4
  14. package/commands/Provision.sol +6 -8
  15. package/commands/Relay.sol +24 -32
  16. package/commands/Withdraw.sol +3 -4
  17. package/commands/admin/AllowAssets.sol +3 -4
  18. package/commands/admin/Allowance.sol +3 -3
  19. package/commands/admin/Appoint.sol +3 -4
  20. package/commands/admin/Authorize.sol +3 -4
  21. package/commands/admin/DenyAssets.sol +3 -4
  22. package/commands/admin/Destroy.sol +3 -4
  23. package/commands/admin/Dismiss.sol +3 -4
  24. package/commands/admin/Execute.sol +6 -7
  25. package/commands/admin/Init.sol +3 -4
  26. package/commands/admin/Label.sol +35 -0
  27. package/commands/admin/Unauthorize.sol +3 -4
  28. package/core/Calls.sol +3 -3
  29. package/core/Host.sol +7 -11
  30. package/core/Payable.sol +12 -10
  31. package/core/Pipeline.sol +4 -4
  32. package/docs/Schema.md +13 -6
  33. package/events/Admin.sol +2 -4
  34. package/events/Chain.sol +2 -3
  35. package/events/Command.sol +2 -4
  36. package/events/Guard.sol +2 -3
  37. package/events/Introduction.sol +2 -4
  38. package/events/Labeled.sol +18 -0
  39. package/events/Peer.sol +2 -11
  40. package/events/Query.sol +2 -3
  41. package/guards/Base.sol +7 -6
  42. package/guards/Revoke.sol +3 -4
  43. package/package.json +2 -1
  44. package/peer/AllowAssets.sol +3 -3
  45. package/peer/Allowance.sol +3 -3
  46. package/peer/BalancePull.sol +3 -3
  47. package/peer/Base.sol +7 -6
  48. package/peer/DenyAssets.sol +3 -3
  49. package/peer/Dispatch.sol +13 -23
  50. package/peer/Pipe.sol +7 -7
  51. package/peer/Settle.sol +3 -3
  52. package/queries/Assets.sol +3 -3
  53. package/queries/Balances.sol +3 -3
  54. package/queries/Base.sol +9 -8
  55. package/queries/Positions.sol +3 -4
  56. package/utils/Value.sol +5 -4
package/core/Pipeline.sol CHANGED
@@ -20,14 +20,14 @@ abstract contract Pipeline is Payable {
20
20
  /// @param account Account identifier for the piped context.
21
21
  /// @param state Current threaded state block stream.
22
22
  /// @param request Step request block stream.
23
- /// @param value Native value assigned to this step.
23
+ /// @param value Native EVM value assigned to this step.
24
24
  /// @return Updated state block stream for the next step.
25
25
  function dispatch(
26
26
  uint target,
27
27
  bytes32 account,
28
28
  bytes memory state,
29
29
  bytes calldata request,
30
- uint value
30
+ uint128 value
31
31
  ) internal virtual returns (bytes memory);
32
32
 
33
33
  /// @notice Execute a STEP block stream through the pipeline.
@@ -45,8 +45,8 @@ abstract contract Pipeline is Payable {
45
45
  (Cur memory input, , ) = Cursors.init(steps, 0, 1);
46
46
 
47
47
  while (input.i < input.len) {
48
- (uint target, uint value, bytes calldata request) = input.unpackStep();
49
- state = dispatch(target, account, state, request, useValue(budget, value));
48
+ (uint target, uint resources, bytes calldata request) = input.unpackStep();
49
+ state = dispatch(target, account, state, request, useValue(budget, resources));
50
50
  }
51
51
 
52
52
  if (state.length != 0) revert UnexpectedState();
package/docs/Schema.md CHANGED
@@ -56,9 +56,9 @@ A block payload has fixed fields first, followed by an optional child-block tail
56
56
  Once a child block appears, no more fixed fields may follow.
57
57
 
58
58
  ```txt
59
- #call { uint target, uint value, #bytes as payload }
59
+ #call { uint target, uint resources, #bytes as payload }
60
60
  #context { bytes32 account, #bytes as state, #bytes as request }
61
- #pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as request } }
61
+ #pipe { uint resources, #context { bytes32 account, #bytes as state, #bytes as steps } }
62
62
  ```
63
63
 
64
64
  The tail is embedded directly as child block bytes. There is no wrapper around a
@@ -108,7 +108,7 @@ or runtime keys.
108
108
 
109
109
  ```txt
110
110
  maybe #account { bytes32 account } as recipient
111
- #call { uint target, uint value, #bytes as payload }
111
+ #call { uint target, uint resources, #bytes as payload }
112
112
  ```
113
113
 
114
114
  Aliases may be used on any block item, including child blocks and prime items.
@@ -131,6 +131,13 @@ Integers are encoded big-endian. Signed integers use two's-complement encoding
131
131
  for their declared width. `bool` is one byte: `0x00` for false and `0x01` for
132
132
  true. `bytesN` values are encoded as exactly `N` bytes with no padding.
133
133
 
134
+ ## Chain Resources
135
+
136
+ Fields named `resources` are chain-specific resource words. Different chain
137
+ types may pack these words differently, but a given chain type must use one
138
+ stable format everywhere. For EVM chains, the low 128 bits are native value /
139
+ endowment in wei; higher bits are reserved for execution resources such as gas.
140
+
134
141
  ## Identifiers
135
142
 
136
143
  Block names, field names, and aliases use lower camelCase ASCII identifiers:
@@ -185,10 +192,10 @@ Common protocol schemas live in `contracts/blocks/Schema.sol`:
185
192
  #amount { bytes32 asset, bytes32 meta, uint amount }
186
193
  #balance { bytes32 asset, bytes32 meta, uint amount }
187
194
  #custody { uint host, bytes32 asset, bytes32 meta, uint amount }
188
- #call { uint target, uint value, #bytes as payload }
189
- #step { uint target, uint value, #bytes as request }
195
+ #call { uint target, uint resources, #bytes as payload }
196
+ #step { uint target, uint resources, #bytes as request }
190
197
  #context { bytes32 account, #bytes as state, #bytes as request }
191
- #pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as request } }
198
+ #pipe { uint resources, #context { bytes32 account, #bytes as state, #bytes as steps } }
192
199
  #auth { uint cid, uint deadline, #bytes as proof }
193
200
  ```
194
201
 
package/events/Admin.sol CHANGED
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { EventEmitter } from "./Emitter.sol";
4
+ import {EventEmitter} from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted once per admin command during host deployment to publish its request schema and state keys.
7
7
  abstract contract AdminEvent is EventEmitter {
8
8
  string private constant ABI =
9
- "event Admin(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool postcheck, bool funded)";
9
+ "event Admin(uint indexed host, uint id, bytes32 shape, string request, bytes4 state, bytes4 output, bool postcheck, bool funded)";
10
10
 
11
11
  /// @param host Host node ID that owns this admin command.
12
12
  /// @param id Command node ID.
13
- /// @param name Human-readable command name.
14
13
  /// @param shape Per-operation block counts encoded as `request:state:output`.
15
14
  /// The request count covers only the input request run. If `postcheck` is true,
16
15
  /// a constraint run follows the input run, or starts the request when `request`
@@ -23,7 +22,6 @@ abstract contract AdminEvent is EventEmitter {
23
22
  event Admin(
24
23
  uint indexed host,
25
24
  uint id,
26
- string name,
27
25
  bytes32 shape,
28
26
  string request,
29
27
  bytes4 state,
package/events/Chain.sol CHANGED
@@ -5,14 +5,13 @@ import {EventEmitter} from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted when a chain/domain node is announced.
7
7
  abstract contract ChainEvent is EventEmitter {
8
- string private constant ABI = "event Chain(uint indexed chain, bytes32 native, uint commander, bytes32 admin, string name)";
8
+ string private constant ABI = "event Chain(uint indexed chain, bytes32 native, uint commander, bytes32 admin)";
9
9
 
10
10
  /// @param chain Chain node ID.
11
11
  /// @param native Native asset ID for the chain.
12
12
  /// @param commander Commander host node ID for the chain.
13
13
  /// @param admin Admin account for the commander host on the chain.
14
- /// @param name Chain or domain name.
15
- event Chain(uint indexed chain, bytes32 native, uint commander, bytes32 admin, string name);
14
+ event Chain(uint indexed chain, bytes32 native, uint commander, bytes32 admin);
16
15
 
17
16
  constructor() {
18
17
  emit EventAbi(ABI);
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { EventEmitter } from "./Emitter.sol";
4
+ import {EventEmitter} from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted once per command during host deployment to publish its request schema and state keys.
7
7
  abstract contract CommandEvent is EventEmitter {
8
8
  string private constant ABI =
9
- "event Command(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool postcheck, bool funded)";
9
+ "event Command(uint indexed host, uint id, bytes32 shape, string request, bytes4 state, bytes4 output, bool postcheck, bool funded)";
10
10
 
11
11
  /// @param host Host node ID that owns this command.
12
12
  /// @param id Command node ID.
13
- /// @param name Human-readable command name.
14
13
  /// @param shape Per-operation block counts encoded as `request:state:output`.
15
14
  /// The request count covers only the input request run. If `postcheck` is true,
16
15
  /// a constraint run follows the input run, or starts the request when `request`
@@ -23,7 +22,6 @@ abstract contract CommandEvent is EventEmitter {
23
22
  event Command(
24
23
  uint indexed host,
25
24
  uint id,
26
- string name,
27
25
  bytes32 shape,
28
26
  string request,
29
27
  bytes4 state,
package/events/Guard.sol CHANGED
@@ -5,13 +5,12 @@ import {EventEmitter} from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted once per guard action during host deployment to publish its request schema.
7
7
  abstract contract GuardEvent is EventEmitter {
8
- string private constant ABI = "event Guard(uint indexed host, uint id, string name, string request)";
8
+ string private constant ABI = "event Guard(uint indexed host, uint id, string request)";
9
9
 
10
10
  /// @param host Host node ID that owns this guard action.
11
11
  /// @param id Guard action node ID.
12
- /// @param name Human-readable guard action name.
13
12
  /// @param request Schema DSL string describing the guard action request shape.
14
- event Guard(uint indexed host, uint id, string name, string request);
13
+ event Guard(uint indexed host, uint id, string request);
15
14
 
16
15
  constructor() {
17
16
  emit EventAbi(ABI);
@@ -5,13 +5,11 @@ import { EventEmitter } from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted when a host introduces itself to another host.
7
7
  abstract contract IntroductionEvent is EventEmitter {
8
- string private constant ABI = "event Introduction(uint indexed host, uint blocknum, uint16 version, string namespace)";
8
+ string private constant ABI = "event Introduction(uint indexed host, uint blocknum)";
9
9
 
10
10
  /// @param host Host node ID of the introducing contract.
11
11
  /// @param blocknum Block number at which the host was deployed.
12
- /// @param version Protocol version the host implements.
13
- /// @param namespace Human-readable namespace string for the host.
14
- event Introduction(uint indexed host, uint blocknum, uint16 version, string namespace);
12
+ event Introduction(uint indexed host, uint blocknum);
15
13
 
16
14
  constructor() {
17
15
  emit EventAbi(ABI);
@@ -0,0 +1,18 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {EventEmitter} from "./Emitter.sol";
5
+
6
+ /// @notice Emitted to attach a human-readable namespaced label to a node ID.
7
+ abstract contract LabeledEvent is EventEmitter {
8
+ string private constant ABI = "event Labeled(uint indexed id, bytes32 namespace, string name)";
9
+
10
+ /// @param id Node or capability ID being labeled.
11
+ /// @param namespace Label namespace.
12
+ /// @param name Human-readable name within the namespace.
13
+ event Labeled(uint indexed id, bytes32 namespace, string name);
14
+
15
+ constructor() {
16
+ emit EventAbi(ABI);
17
+ }
18
+ }
package/events/Peer.sol CHANGED
@@ -6,24 +6,15 @@ import {EventEmitter} from "./Emitter.sol";
6
6
  /// @notice Emitted once per peer during host deployment to publish its request and response schemas.
7
7
  abstract contract PeerEvent is EventEmitter {
8
8
  string private constant ABI =
9
- "event Peer(uint indexed host, uint id, string name, bytes32 shape, string request, string response, bool funded)";
9
+ "event Peer(uint indexed host, uint id, bytes32 shape, string request, string response, bool funded)";
10
10
 
11
11
  /// @param host Host node ID that owns this peer.
12
12
  /// @param id Peer node ID.
13
- /// @param name Human-readable peer name.
14
13
  /// @param shape Per-operation block counts encoded as `request:response`.
15
14
  /// @param request Schema DSL string describing the input request run, or empty if none.
16
15
  /// @param response Schema DSL string describing the peer response shape.
17
16
  /// @param funded Whether the peer entrypoint accepts nonzero `msg.value`.
18
- event Peer(
19
- uint indexed host,
20
- uint id,
21
- string name,
22
- bytes32 shape,
23
- string request,
24
- string response,
25
- bool funded
26
- );
17
+ event Peer(uint indexed host, uint id, bytes32 shape, string request, string response, bool funded);
27
18
 
28
19
  constructor() {
29
20
  emit EventAbi(ABI);
package/events/Query.sol CHANGED
@@ -5,15 +5,14 @@ import {EventEmitter} from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted once per query during host deployment to publish its request and response schemas.
7
7
  abstract contract QueryEvent is EventEmitter {
8
- string private constant ABI = "event Query(uint indexed host, uint id, string name, bytes32 shape, string request, string response)";
8
+ string private constant ABI = "event Query(uint indexed host, uint id, bytes32 shape, string request, string response)";
9
9
 
10
10
  /// @param host Host node ID that owns this query.
11
11
  /// @param id Query node ID.
12
- /// @param name Human-readable query name.
13
12
  /// @param shape Per-operation block counts encoded as `request:response`.
14
13
  /// @param request Schema DSL string describing the input request run, or empty if none.
15
14
  /// @param response Schema DSL string describing the query response shape.
16
- event Query(uint indexed host, uint id, string name, bytes32 shape, string request, string response);
15
+ event Query(uint indexed host, uint id, bytes32 shape, string request, string response);
17
16
 
18
17
  constructor() {
19
18
  emit EventAbi(ABI);
package/guards/Base.sol CHANGED
@@ -3,7 +3,8 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import {AccessControl} from "../core/Access.sol";
5
5
  import {GuardEvent} from "../events/Guard.sol";
6
- import {Ids, Selectors} from "../utils/Ids.sol";
6
+ import {LabeledEvent} from "../events/Labeled.sol";
7
+ import {Ids} from "../utils/Ids.sol";
7
8
 
8
9
  /// @notice ABI-encode a guard action call from a target guard ID and request block stream.
9
10
  /// @dev Derives the function selector from `target` via `Ids.guardSelector(target)`.
@@ -19,17 +20,17 @@ function encodeGuardCall(uint target, bytes calldata request) pure returns (byte
19
20
  /// @title GuardBase
20
21
  /// @notice Abstract base for guardian-only direct host actions.
21
22
  /// Guard actions are non-payable direct calls with no command context, state, or response.
22
- abstract contract GuardBase is AccessControl, GuardEvent {
23
+ abstract contract GuardBase is AccessControl, GuardEvent, LabeledEvent {
23
24
  /// @dev Restrict execution to active guardian addresses.
24
25
  modifier onlyGuardian() {
25
26
  if (!isGuardian(msg.sender)) revert AccessDenied();
26
27
  _;
27
28
  }
28
29
 
29
- /// @notice Derive the deterministic node ID for a named guard action on this contract.
30
- /// @param name Guard action function name (without argument list).
30
+ /// @notice Derive the deterministic node ID for a guard action selector on this contract.
31
+ /// @param selector Guard action entrypoint selector.
31
32
  /// @return Guard action node ID.
32
- function guardId(string memory name) internal view returns (uint) {
33
- return Ids.toGuard(Selectors.guard(name), address(this));
33
+ function guardId(bytes4 selector) internal view returns (uint) {
34
+ return Ids.toGuard(selector, address(this));
34
35
  }
35
36
  }
package/guards/Revoke.sol CHANGED
@@ -10,12 +10,11 @@ using Cursors for Cur;
10
10
  /// Each NODE block in the request is deauthorized on the host.
11
11
  /// Only callable by active guardian addresses.
12
12
  abstract contract Revoke is GuardBase {
13
- string private constant NAME = "revoke";
14
-
15
- uint internal immutable revokeId = guardId(NAME);
13
+ uint internal immutable revokeId = guardId(this.revoke.selector);
16
14
 
17
15
  constructor() {
18
- emit Guard(host, revokeId, NAME, Schemas.Node);
16
+ emit Guard(host, revokeId, Schemas.Node);
17
+ emit Labeled(revokeId, bytes32(0), "revoke");
19
18
  }
20
19
 
21
20
  function revoke(bytes calldata request) external onlyGuardian {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootzero/contracts",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "Solidity contracts and protocol building blocks for rootzero hosts and commands.",
5
5
  "private": false,
6
6
  "license": "GPL-3.0-only",
@@ -8,6 +8,7 @@
8
8
  "files": [
9
9
  "**/*.sol",
10
10
  "README.md",
11
+ "CHANGELOG.md",
11
12
  "LICENSE",
12
13
  "docs/Schema.md"
13
14
  ],
@@ -11,11 +11,11 @@ using Cursors for Cur;
11
11
  /// @notice Peer that permits a list of (asset, meta) pairs on behalf of a peer host.
12
12
  /// Each ASSET block in the request calls `allowAsset`. Restricted to trusted peers.
13
13
  abstract contract PeerAllowAssets is PeerBase, AllowAssetsHook {
14
- string private constant NAME = "peerAllowAssets";
15
- uint internal immutable peerAllowAssetsId = peerId(NAME);
14
+ uint internal immutable peerAllowAssetsId = peerId(this.peerAllowAssets.selector);
16
15
 
17
16
  constructor() {
18
- emit Peer(host, peerAllowAssetsId, NAME, "1:0", Schemas.Asset, "", false);
17
+ emit Peer(host, peerAllowAssetsId, "1:0", Schemas.Asset, "", false);
18
+ emit Labeled(peerAllowAssetsId, bytes32(0), "peerAllowAssets");
19
19
  }
20
20
 
21
21
  /// @notice Execute the allow-assets peer call.
@@ -12,11 +12,11 @@ using Cursors for Cur;
12
12
  /// Each AMOUNT block in the request is scoped to the peer host and passed to the
13
13
  /// shared allowance hook as a host-scoped allowance. Restricted to trusted peers.
14
14
  abstract contract PeerAllowance is PeerBase, AllowanceHook {
15
- string private constant NAME = "peerAllowance";
16
- uint internal immutable peerAllowanceId = peerId(NAME);
15
+ uint internal immutable peerAllowanceId = peerId(this.peerAllowance.selector);
17
16
 
18
17
  constructor() {
19
- emit Peer(host, peerAllowanceId, NAME, "1:0", Schemas.Amount, "", false);
18
+ emit Peer(host, peerAllowanceId, "1:0", Schemas.Amount, "", false);
19
+ emit Labeled(peerAllowanceId, bytes32(0), "peerAllowance");
20
20
  }
21
21
 
22
22
  /// @notice Execute the allowance peer call.
@@ -20,11 +20,11 @@ abstract contract BalancePullHook {
20
20
  /// Each BALANCE block in the request calls `balancePull(peer, asset, meta, amount)`.
21
21
  /// Restricted to trusted peers.
22
22
  abstract contract PeerBalancePull is PeerBase, BalancePullHook {
23
- string private constant NAME = "peerBalancePull";
24
- uint internal immutable peerBalancePullId = peerId(NAME);
23
+ uint internal immutable peerBalancePullId = peerId(this.peerBalancePull.selector);
25
24
 
26
25
  constructor() {
27
- emit Peer(host, peerBalancePullId, NAME, "1:0", Schemas.Balance, "", false);
26
+ emit Peer(host, peerBalancePullId, "1:0", Schemas.Balance, "", false);
27
+ emit Labeled(peerBalancePullId, bytes32(0), "peerBalancePull");
28
28
  }
29
29
 
30
30
  /// @notice Execute the balance-pull peer call.
package/peer/Base.sol CHANGED
@@ -3,7 +3,8 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { NodeCalls } from "../core/Calls.sol";
5
5
  import { PeerEvent } from "../events/Peer.sol";
6
- import { Ids, Selectors } from "../utils/Ids.sol";
6
+ import { LabeledEvent } from "../events/Labeled.sol";
7
+ import { Ids } from "../utils/Ids.sol";
7
8
 
8
9
  /// @notice ABI-encode a peer call from a target peer ID and request block stream.
9
10
  /// @dev Derives the function selector from `target` via `Ids.peerSelector(target)`.
@@ -20,7 +21,7 @@ function encodePeerCall(uint target, bytes calldata request) pure returns (bytes
20
21
  /// @notice Abstract base for all rootzero peer contracts.
21
22
  /// Peers handle inter-host operations and asset allow/deny management
22
23
  /// between cooperating hosts. Access is restricted to trusted callers via `onlyPeer`.
23
- abstract contract PeerBase is NodeCalls, PeerEvent {
24
+ abstract contract PeerBase is NodeCalls, PeerEvent, LabeledEvent {
24
25
  /// @dev Thrown when the commander attempts to call a peer entrypoint directly.
25
26
  error CommanderNotAllowed();
26
27
 
@@ -31,10 +32,10 @@ abstract contract PeerBase is NodeCalls, PeerEvent {
31
32
  _;
32
33
  }
33
34
 
34
- /// @notice Derive the deterministic node ID for a named peer on this contract.
35
- /// @param name Peer function name (without argument list).
35
+ /// @notice Derive the deterministic node ID for a peer selector on this contract.
36
+ /// @param selector Peer entrypoint selector.
36
37
  /// @return Peer node ID.
37
- function peerId(string memory name) internal view returns (uint) {
38
- return Ids.toPeer(Selectors.peer(name), address(this));
38
+ function peerId(bytes4 selector) internal view returns (uint) {
39
+ return Ids.toPeer(selector, address(this));
39
40
  }
40
41
  }
@@ -11,11 +11,11 @@ using Cursors for Cur;
11
11
  /// @notice Peer that blocks a list of (asset, meta) pairs on behalf of a peer host.
12
12
  /// Each ASSET block in the request calls `denyAsset`. Restricted to trusted peers.
13
13
  abstract contract PeerDenyAssets is PeerBase, DenyAssetsHook {
14
- string private constant NAME = "peerDenyAssets";
15
- uint internal immutable peerDenyAssetsId = peerId(NAME);
14
+ uint internal immutable peerDenyAssetsId = peerId(this.peerDenyAssets.selector);
16
15
 
17
16
  constructor() {
18
- emit Peer(host, peerDenyAssetsId, NAME, "1:0", Schemas.Asset, "", false);
17
+ emit Peer(host, peerDenyAssetsId, "1:0", Schemas.Asset, "", false);
18
+ emit Labeled(peerDenyAssetsId, bytes32(0), "peerDenyAssets");
19
19
  }
20
20
 
21
21
  /// @notice Execute the deny-assets peer call.
package/peer/Dispatch.sol CHANGED
@@ -4,29 +4,19 @@ pragma solidity ^0.8.33;
4
4
  import { PeerBase } from "./Base.sol";
5
5
  import { Payable } from "../core/Payable.sol";
6
6
  import { Cursors, Cur, Schemas } from "../Cursors.sol";
7
+ import { DispatchPayableHook } from "../commands/Relay.sol";
7
8
  import { Budget } from "../utils/Value.sol";
8
9
 
9
10
  using Cursors for Cur;
10
11
 
11
- abstract contract PeerDispatchPayableHook {
12
- /// @notice Override to dispatch an already 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 calldata payload, Budget memory budget) internal virtual;
20
- }
21
-
22
12
  /// @title PeerDispatchPayable
23
13
  /// @notice Peer endpoint that forwards DISPATCH blocks to a host-defined dispatch hook.
24
- abstract contract PeerDispatchPayable is PeerBase, Payable, PeerDispatchPayableHook {
25
- string private constant NAME = "peerDispatchPayable";
26
- uint internal immutable peerDispatchPayableId = peerId(NAME);
14
+ abstract contract PeerDispatchPayable is PeerBase, Payable, DispatchPayableHook {
15
+ uint internal immutable peerDispatchPayableId = peerId(this.peerDispatchPayable.selector);
27
16
 
28
17
  constructor() {
29
- emit Peer(host, peerDispatchPayableId, NAME, "1:0", Schemas.Dispatch, "", true);
18
+ emit Peer(host, peerDispatchPayableId, "1:0", Schemas.Dispatch, "", true);
19
+ emit Labeled(peerDispatchPayableId, bytes32(0), "peerDispatchPayable");
30
20
  }
31
21
 
32
22
  /// @notice Forward peer-supplied dispatches to the host-defined dispatch hook.
@@ -36,14 +26,14 @@ abstract contract PeerDispatchPayable is PeerBase, Payable, PeerDispatchPayableH
36
26
  /// @return output Empty response bytes.
37
27
  function peerDispatchPayable(bytes calldata request) external payable onlyPeer returns (bytes memory output) {
38
28
  (Cur memory input, , ) = Cursors.init(request, 0, 1);
39
- Budget memory budget = valueBudget();
40
-
41
- while (input.i < input.len) {
42
- (uint chain, uint resources, bytes calldata payload) = input.unpackDispatch();
43
- dispatch(chain, resources, payload, budget);
44
- }
45
-
46
- input.complete();
29
+ Budget memory budget = valueBudget();
30
+
31
+ while (input.i < input.len) {
32
+ (uint chain, uint resources, bytes calldata payload) = input.unpackDispatch();
33
+ dispatch(chain, resources, bytes(payload), budget);
34
+ }
35
+
36
+ input.complete();
47
37
  return "";
48
38
  }
49
39
 
package/peer/Pipe.sol CHANGED
@@ -10,18 +10,18 @@ using Cursors for Cur;
10
10
 
11
11
  /// @title PeerPipePayable
12
12
  /// @notice Peer that consumes PIPE blocks and executes each context step stream.
13
- /// Each PIPE block carries a value budget plus a CONTEXT block; the nested
13
+ /// Each PIPE block carries chain resources plus a CONTEXT block; the nested
14
14
  /// context steps are passed to the shared pipeline as the step stream.
15
15
  abstract contract PeerPipePayable is PeerBase, Pipeline {
16
- string private constant NAME = "peerPipePayable";
17
- uint internal immutable peerPipePayableId = peerId(NAME);
16
+ uint internal immutable peerPipePayableId = peerId(this.peerPipePayable.selector);
18
17
 
19
18
  constructor() {
20
- emit Peer(host, peerPipePayableId, NAME, "1:0", Schemas.Pipe, "", true);
19
+ emit Peer(host, peerPipePayableId, "1:0", Schemas.Pipe, "", true);
20
+ emit Labeled(peerPipePayableId, bytes32(0), "peerPipePayable");
21
21
  }
22
22
 
23
23
  /// @notice Execute peer-supplied pipes through the shared payable pipe.
24
- /// @dev Each pipe receives its own explicit value sub-budget. Any top-level
24
+ /// @dev Each pipe receives its own explicit EVM value sub-budget. Any top-level
25
25
  /// `msg.value` not assigned to a pipe remains on this host.
26
26
  /// @param request PIPE block stream supplied by the trusted peer.
27
27
  /// @return Empty response bytes.
@@ -30,8 +30,8 @@ abstract contract PeerPipePayable is PeerBase, Pipeline {
30
30
  Budget memory budget = valueBudget();
31
31
 
32
32
  while (input.i < input.len) {
33
- (uint value, bytes32 account, bytes calldata state, bytes calldata steps) = input.unpackPipe();
34
- pipe(account, state, steps, allocateValue(budget, value));
33
+ (uint resources, bytes32 account, bytes calldata state, bytes calldata steps) = input.unpackPipe();
34
+ pipe(account, state, steps, allocateValue(budget, resources));
35
35
  }
36
36
 
37
37
  input.complete();
package/peer/Settle.sol CHANGED
@@ -12,11 +12,11 @@ using Cursors for Cur;
12
12
  /// @notice Peer that consumes peer-supplied TRANSACTION blocks through debit and credit hooks.
13
13
  /// Each TRANSACTION block calls `debitAccount` for `from` and `creditAccount` for `to`.
14
14
  abstract contract PeerSettle is PeerBase, DebitAccountHook, CreditAccountHook {
15
- string private constant NAME = "peerSettle";
16
- uint internal immutable peerSettleId = peerId(NAME);
15
+ uint internal immutable peerSettleId = peerId(this.peerSettle.selector);
17
16
 
18
17
  constructor() {
19
- emit Peer(host, peerSettleId, NAME, "1:0", Schemas.Transaction, "", false);
18
+ emit Peer(host, peerSettleId, "1:0", Schemas.Transaction, "", false);
19
+ emit Labeled(peerSettleId, bytes32(0), "peerSettle");
20
20
  }
21
21
 
22
22
  /// @notice Execute the peer-settle call.
@@ -22,11 +22,11 @@ abstract contract AssetStatusHook {
22
22
  /// The request is a run of `ASSET` blocks.
23
23
  /// The response returns one `STATUS` form block per query entry, preserving request order.
24
24
  abstract contract AssetStatus is QueryBase, AssetStatusHook {
25
- string private constant NAME = "assetStatus";
26
- uint public immutable assetStatusId = queryId(NAME);
25
+ uint public immutable assetStatusId = queryId(this.assetStatus.selector);
27
26
 
28
27
  constructor() {
29
- emit Query(host, assetStatusId, NAME, "1:1", Schemas.Asset, Forms.Status);
28
+ emit Query(host, assetStatusId, "1:1", Schemas.Asset, Forms.Status);
29
+ emit Labeled(assetStatusId, bytes32(0), "assetStatus");
30
30
  }
31
31
 
32
32
  /// @notice Resolve asset support status for a run of requested `(asset, meta)` tuples.
@@ -22,11 +22,11 @@ abstract contract GetBalancesHook {
22
22
  /// The request is a run of `ACCOUNT_ASSET` form blocks.
23
23
  /// The response returns one `ACCOUNT_AMOUNT` form block per requested position, preserving request order.
24
24
  abstract contract GetBalances is QueryBase, GetBalancesHook {
25
- string private constant NAME = "getBalances";
26
- uint public immutable getBalancesId = queryId(NAME);
25
+ uint public immutable getBalancesId = queryId(this.getBalances.selector);
27
26
 
28
27
  constructor() {
29
- emit Query(host, getBalancesId, NAME, "1:1", Forms.AccountAsset, Forms.AccountAmount);
28
+ emit Query(host, getBalancesId, "1:1", Forms.AccountAsset, Forms.AccountAmount);
29
+ emit Labeled(getBalancesId, bytes32(0), "getBalances");
30
30
  }
31
31
 
32
32
  /// @notice Resolve balances for a run of requested `(account, asset, meta)` tuples.
package/queries/Base.sol CHANGED
@@ -2,8 +2,9 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import { Runtime } from "../core/Runtime.sol";
5
+ import { LabeledEvent } from "../events/Labeled.sol";
5
6
  import { QueryEvent } from "../events/Query.sol";
6
- import { Ids, Selectors } from "../utils/Ids.sol";
7
+ import { Ids } from "../utils/Ids.sol";
7
8
 
8
9
  /// @notice ABI-encode a query call from a target query ID and request block stream.
9
10
  /// @dev Derives the function selector from `target` via `Ids.querySelector(target)`.
@@ -20,14 +21,14 @@ function encodeQueryCall(uint target, bytes calldata request) pure returns (byte
20
21
  /// @notice Abstract base for rootzero query contracts.
21
22
  /// Queries are view-only entry points that consume a block-stream request and
22
23
  /// return a block-stream response.
23
- abstract contract QueryBase is Runtime, QueryEvent {
24
+ abstract contract QueryBase is Runtime, QueryEvent, LabeledEvent {
24
25
 
25
- /// @notice Derive the deterministic node ID for a named query on this contract.
26
- /// The ID encodes the ABI selector of `name(bytes)` and `address(this)`,
27
- /// making it unique per (function name, contract address) pair.
28
- /// @param name Query function name (without argument list).
26
+ /// @notice Derive the deterministic node ID for a query selector on this contract.
27
+ /// The ID encodes the ABI selector and `address(this)`, making it unique
28
+ /// per (function selector, contract address) pair.
29
+ /// @param selector Query entrypoint selector.
29
30
  /// @return Query node ID.
30
- function queryId(string memory name) internal view returns (uint) {
31
- return Ids.toQuery(Selectors.query(name), address(this));
31
+ function queryId(bytes4 selector) internal view returns (uint) {
32
+ return Ids.toQuery(selector, address(this));
32
33
  }
33
34
  }
@@ -29,12 +29,11 @@ abstract contract GetPositionHook {
29
29
  /// The request is a run of `ACCOUNT_ASSET` form blocks.
30
30
  /// The response returns one output-schema block per position entry, preserving request order.
31
31
  abstract contract GetPosition is QueryBase, GetPositionHook {
32
- string private constant NAME = "getPosition";
33
-
34
- uint public immutable getPositionId = queryId(NAME);
32
+ uint public immutable getPositionId = queryId(this.getPosition.selector);
35
33
 
36
34
  constructor(string memory output) {
37
- emit Query(host, getPositionId, NAME, "1:1", Forms.AccountAsset, output);
35
+ emit Query(host, getPositionId, "1:1", Forms.AccountAsset, output);
36
+ emit Labeled(getPositionId, bytes32(0), "getPosition");
38
37
  }
39
38
 
40
39
  /// @notice Resolve positions for a run of requested `(account, asset, meta)` tuples.
package/utils/Value.sol CHANGED
@@ -18,9 +18,10 @@ library Values {
18
18
  /// @param budget Mutable budget to deduct from.
19
19
  /// @param amount Native value to spend in wei.
20
20
  /// @return The same `amount`, ready to forward to a callee.
21
- function use(Budget memory budget, uint amount) internal pure returns (uint) {
22
- if (amount > budget.remaining) revert InsufficientValue();
23
- budget.remaining -= amount;
21
+ function use(Budget memory budget, uint128 amount) internal pure returns (uint128) {
22
+ uint value = uint(amount);
23
+ if (value > budget.remaining) revert InsufficientValue();
24
+ budget.remaining -= value;
24
25
  return amount;
25
26
  }
26
27
 
@@ -29,7 +30,7 @@ library Values {
29
30
  /// @param budget Mutable parent budget to deduct from.
30
31
  /// @param amount Native value to assign to the sub-budget, in wei.
31
32
  /// @return A new budget with `amount` remaining.
32
- function allocate(Budget memory budget, uint amount) internal pure returns (Budget memory) {
33
+ function allocate(Budget memory budget, uint128 amount) internal pure returns (Budget memory) {
33
34
  return Budget({remaining: use(budget, amount)});
34
35
  }
35
36
  }