@rootzero/contracts 1.1.0 → 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 (51) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/Endpoints.sol +1 -0
  3. package/Events.sol +1 -0
  4. package/blocks/Cursors.sol +39 -0
  5. package/blocks/Keys.sol +4 -0
  6. package/blocks/Schema.sol +3 -0
  7. package/blocks/Writers.sol +16 -0
  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 +3 -4
  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 +3 -4
  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/Host.sol +7 -11
  29. package/events/Admin.sol +2 -4
  30. package/events/Chain.sol +2 -3
  31. package/events/Command.sol +2 -4
  32. package/events/Guard.sol +2 -3
  33. package/events/Introduction.sol +2 -4
  34. package/events/Labeled.sol +18 -0
  35. package/events/Peer.sol +2 -11
  36. package/events/Query.sol +2 -3
  37. package/guards/Base.sol +7 -6
  38. package/guards/Revoke.sol +3 -4
  39. package/package.json +1 -1
  40. package/peer/AllowAssets.sol +3 -3
  41. package/peer/Allowance.sol +3 -3
  42. package/peer/BalancePull.sol +3 -3
  43. package/peer/Base.sol +7 -6
  44. package/peer/DenyAssets.sol +3 -3
  45. package/peer/Dispatch.sol +3 -3
  46. package/peer/Pipe.sol +3 -3
  47. package/peer/Settle.sol +3 -3
  48. package/queries/Assets.sol +3 -3
  49. package/queries/Balances.sol +3 -3
  50. package/queries/Base.sol +9 -8
  51. package/queries/Positions.sol +3 -4
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
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.2.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - Removed human-readable names from Command, Admin, Peer, Query, Guard, and Chain discovery events.
11
+ - Added the Labeled event and default labels for commands, admin commands, peers, queries, guards, and examples.
12
+ - Added LABEL and STRING block schemas, plus cursor helpers for decoding labels supplied by callers.
13
+ - Added the admin label command for publishing mutable namespaced labels.
14
+ - Removed version and namespace fields from host Introduction events and host constructor introductions.
15
+
6
16
  ## 1.1.0
7
17
 
8
18
  ### Breaking Changes
package/Endpoints.sol CHANGED
@@ -29,6 +29,7 @@ import { DenyAssets, DenyAssetsHook } from "./commands/admin/DenyAssets.sol";
29
29
  import { Dismiss } from "./commands/admin/Dismiss.sol";
30
30
  import { ExecutePayable } from "./commands/admin/Execute.sol";
31
31
  import { Init, InitHook } from "./commands/admin/Init.sol";
32
+ import { Label } from "./commands/admin/Label.sol";
32
33
  import { Unauthorize } from "./commands/admin/Unauthorize.sol";
33
34
 
34
35
  // Peer endpoints
package/Events.sol CHANGED
@@ -16,6 +16,7 @@ import { EventEmitter } from "./events/Emitter.sol";
16
16
  import { GuardEvent } from "./events/Guard.sol";
17
17
  import { GuardianEvent } from "./events/Guardian.sol";
18
18
  import { IntroductionEvent } from "./events/Introduction.sol";
19
+ import { LabeledEvent } from "./events/Labeled.sol";
19
20
  import { LockedEvent } from "./events/Locked.sol";
20
21
  import { NodeEvent } from "./events/Node.sol";
21
22
  import { PeerEvent } from "./events/Peer.sol";
@@ -489,6 +489,13 @@ library Cursors {
489
489
  return createBlock(Keys.Bytes, data);
490
490
  }
491
491
 
492
+ /// @notice Encode a STRING block with a UTF-8 payload.
493
+ /// @param data String payload.
494
+ /// @return Encoded STRING block bytes.
495
+ function toStringBlock(string memory data) internal pure returns (bytes memory) {
496
+ return createBlock(Keys.String, bytes(data));
497
+ }
498
+
492
499
  /// @notice Encode a BOUNTY block.
493
500
  /// @param bounty Relayer reward amount.
494
501
  /// @param relayer Relayer account identifier.
@@ -610,6 +617,18 @@ library Cursors {
610
617
  cur.i += 4;
611
618
  }
612
619
 
620
+ /// @notice Read the next 8 bytes from the cursor and advance by 8 bytes.
621
+ /// @dev Performs no bounds, key, length, or cursor checks.
622
+ /// @param cur Cursor whose current position is advanced by 8 bytes.
623
+ /// @return value Loaded bytes8 value.
624
+ function read8(Cur memory cur) internal pure returns (bytes8 value) {
625
+ uint abs = cur.offset + cur.i;
626
+ assembly ("memory-safe") {
627
+ value := calldataload(abs)
628
+ }
629
+ cur.i += 8;
630
+ }
631
+
613
632
  /// @notice Read the next 16 bytes from the cursor and advance by 16 bytes.
614
633
  /// @dev Performs no bounds, key, length, or cursor checks.
615
634
  /// @param cur Cursor whose current position is advanced by 16 bytes.
@@ -708,6 +727,26 @@ library Cursors {
708
727
  return unpackRaw(cur, Keys.Bytes);
709
728
  }
710
729
 
730
+ /// @notice Consume a reserved STRING block and return its UTF-8 payload.
731
+ /// @param cur Cursor; advanced past the STRING block.
732
+ /// @return data Decoded STRING payload.
733
+ function unpackString(Cur memory cur) internal pure returns (string memory data) {
734
+ return string(unpackRaw(cur, Keys.String));
735
+ }
736
+
737
+ /// @notice Consume a LABEL block and return its fields.
738
+ /// @param cur Cursor; advanced past the LABEL block.
739
+ /// @return id Node ID being labelled.
740
+ /// @return namespace Label namespace.
741
+ /// @return name Label value.
742
+ function unpackLabel(Cur memory cur) internal pure returns (uint id, bytes32 namespace, string memory name) {
743
+ uint end = cur.enter(Keys.Label, 64 + Sizes.Header, 0);
744
+ id = cur.readUint();
745
+ namespace = cur.read32();
746
+ name = cur.unpackString();
747
+ cur.exit(end);
748
+ }
749
+
711
750
  /// @notice Consume a dynamic block with a single bytes32 payload.
712
751
  /// @param cur Cursor; advanced past the block.
713
752
  /// @param key Expected dynamic block key.
package/blocks/Keys.sol CHANGED
@@ -33,6 +33,8 @@ library Keys {
33
33
  bytes4 constant Evm = bytes4(keccak256("#evm"));
34
34
  /// @dev Reserved raw bytes child block.
35
35
  bytes4 constant Bytes = bytes4(keccak256("#bytes"));
36
+ /// @dev Reserved UTF-8 string child block.
37
+ bytes4 constant String = bytes4(keccak256("#string"));
36
38
  /// @dev Account identifier - (bytes32 account)
37
39
  bytes4 constant Account = bytes4(keccak256("#account"));
38
40
  /// @dev Transfer record passed through the pipeline - (bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)
@@ -57,6 +59,8 @@ library Keys {
57
59
  bytes4 constant Node = bytes4(keccak256("#node"));
58
60
  /// @dev Relayer bounty - (uint amount, bytes32 relayer)
59
61
  bytes4 constant Bounty = bytes4(keccak256("#bounty"));
62
+ /// @dev Mutable node label - (uint id, bytes32 namespace, #string as name)
63
+ bytes4 constant Label = bytes4(keccak256("#label"));
60
64
 
61
65
  /// @dev Structural status form - (uint code)
62
66
  bytes4 constant Status = bytes4(keccak256("#status"));
package/blocks/Schema.sol CHANGED
@@ -25,6 +25,7 @@ pragma solidity ^0.8.33;
25
25
  // - blocks have fixed fields followed by a dynamic child-block tail
26
26
  // - child block tails are embedded directly, without an extra stream wrapper
27
27
  // - `#bytes` is a reserved child block that stores raw bytes and has no body
28
+ // - `#string` is a reserved child block that stores UTF-8 string bytes and has no body
28
29
  // - generic `#data` uses the stable key derived from `#data`
29
30
  // - generic lists use the stable key derived from `#list`
30
31
  // - keys are derived from block names, e.g. bytes4(keccak256("#amount"))
@@ -73,7 +74,9 @@ library Schemas {
73
74
  string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
74
75
  string constant Fee = "#fee { uint amount }";
75
76
  string constant Auth = "#auth { uint cid, uint deadline, #bytes as proof }";
77
+ string constant Label = "#label { uint id, bytes32 namespace, #string as name }";
76
78
  string constant Bytes = "#bytes";
79
+ string constant String = "#string";
77
80
  string constant Data = "#data";
78
81
  string constant List = "#list";
79
82
  string constant Evm = "#evm";
@@ -24,6 +24,7 @@ struct Writer {
24
24
  library Hints {
25
25
  uint constant Any = 128;
26
26
  uint constant Bytes = 128;
27
+ uint constant String = 128;
27
28
  uint constant Step = 256;
28
29
  uint constant Call = 256;
29
30
  uint constant Context = 512;
@@ -116,6 +117,14 @@ library Writers {
116
117
  return allocFromHint(count, Hints.Bytes);
117
118
  }
118
119
 
120
+ /// @notice Allocate a writer for `count` STRING blocks using a per-block capacity hint.
121
+ /// @dev The backing buffer expands automatically if encoded string blocks exceed the initial hint.
122
+ /// @param count Number of string blocks to allocate space for.
123
+ /// @return writer Allocated growable writer.
124
+ function allocStrings(uint count) internal pure returns (Writer memory writer) {
125
+ return allocFromHint(count, Hints.String);
126
+ }
127
+
119
128
  /// @notice Allocate a writer sized for exactly `count` 32-byte-payload blocks.
120
129
  /// @param count Number of blocks to allocate space for.
121
130
  /// @return writer Allocated writer.
@@ -862,6 +871,13 @@ library Writers {
862
871
  appendBlock(writer, Keys.Bytes, data);
863
872
  }
864
873
 
874
+ /// @notice Append a STRING block.
875
+ /// @param writer Destination writer; `i` is advanced by the encoded STRING block length.
876
+ /// @param data String payload.
877
+ function appendString(Writer memory writer, string memory data) internal pure {
878
+ appendBlock(writer, Keys.String, bytes(data));
879
+ }
880
+
865
881
  /// @notice Append a STEP block with a nested request BYTES payload.
866
882
  /// @param writer Destination writer; `i` is advanced by the encoded STEP block length.
867
883
  /// @param target Command target identifier.
package/commands/Base.sol CHANGED
@@ -3,8 +3,9 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import {NodeCalls} from "../core/Calls.sol";
5
5
  import {CommandEvent} from "../events/Command.sol";
6
+ import {LabeledEvent} from "../events/Labeled.sol";
6
7
  import {Keys} from "../blocks/Keys.sol";
7
- import {Ids, Selectors} from "../utils/Ids.sol";
8
+ import {Ids} from "../utils/Ids.sol";
8
9
 
9
10
  /// @notice Execution context passed to every command invocation.
10
11
  struct CommandContext {
@@ -19,8 +20,8 @@ struct CommandContext {
19
20
  /// @title CommandBase
20
21
  /// @notice Abstract base for all rootzero command contracts.
21
22
  /// Provides access control modifiers, event emission, and the `commandId`
22
- /// helper used to derive stable identifiers for named commands.
23
- abstract contract CommandBase is NodeCalls, CommandEvent {
23
+ /// helper used to derive stable identifiers for command selectors.
24
+ abstract contract CommandBase is NodeCalls, CommandEvent, LabeledEvent {
24
25
  /// @dev Thrown when `onlyActive` finds that `deadline` has already passed.
25
26
  error Expired();
26
27
 
@@ -44,12 +45,12 @@ abstract contract CommandBase is NodeCalls, CommandEvent {
44
45
  _;
45
46
  }
46
47
 
47
- /// @notice Derive the deterministic node ID for a named command on this contract.
48
- /// The ID encodes the ABI selector of `name((bytes32,bytes,bytes))` and
49
- /// `address(this)`, making it unique per (function name, contract address) pair.
50
- /// @param name Command function name (without argument list).
48
+ /// @notice Derive the deterministic node ID for a command selector on this contract.
49
+ /// The ID encodes the ABI selector and `address(this)`, making it unique
50
+ /// per (function selector, contract address) pair.
51
+ /// @param selector Command entrypoint selector.
51
52
  /// @return Command node ID.
52
- function commandId(string memory name) internal view returns (uint) {
53
- return Ids.toCommand(Selectors.command(name), address(this));
53
+ function commandId(bytes4 selector) internal view returns (uint) {
54
+ return Ids.toCommand(selector, address(this));
54
55
  }
55
56
  }
package/commands/Burn.sol CHANGED
@@ -20,12 +20,11 @@ abstract contract BurnHook {
20
20
  /// @notice Command that irreversibly destroys each BALANCE state block via a virtual hook.
21
21
  /// Produces no output state.
22
22
  abstract contract Burn is CommandBase, BurnHook {
23
- string private constant NAME = "burn";
24
-
25
- uint internal immutable burnId = commandId(NAME);
23
+ uint internal immutable burnId = commandId(this.burn.selector);
26
24
 
27
25
  constructor() {
28
- emit Command(host, burnId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
26
+ emit Command(host, burnId, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
27
+ emit Labeled(burnId, bytes32(0), "burn");
29
28
  }
30
29
 
31
30
  /// @notice Burn each BALANCE block from the command state.
@@ -20,12 +20,11 @@ abstract contract CreditAccountHook {
20
20
  /// @notice Command that delivers BALANCE state blocks to an account via a virtual hook.
21
21
  /// Use for internally recording credits that have already been settled externally.
22
22
  abstract contract CreditAccount is CommandBase, CreditAccountHook {
23
- string private constant NAME = "creditAccount";
24
-
25
- uint internal immutable creditAccountId = commandId(NAME);
23
+ uint internal immutable creditAccountId = commandId(this.creditAccount.selector);
26
24
 
27
25
  constructor() {
28
- emit Command(host, creditAccountId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
26
+ emit Command(host, creditAccountId, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
27
+ emit Labeled(creditAccountId, bytes32(0), "creditAccount");
29
28
  }
30
29
 
31
30
  /// @notice Credit each BALANCE block from the command state to the command account.
@@ -22,12 +22,11 @@ abstract contract DebitAccountHook {
22
22
  /// Use for internally recording debits. The virtual `debitAccount` hook is called once per
23
23
  /// AMOUNT block; the default batch implementation handles the full request loop.
24
24
  abstract contract DebitAccount is CommandBase, DebitAccountHook {
25
- string private constant NAME = "debitAccount";
26
-
27
- uint internal immutable debitAccountId = commandId(NAME);
25
+ uint internal immutable debitAccountId = commandId(this.debitAccount.selector);
28
26
 
29
27
  constructor() {
30
- emit Command(host, debitAccountId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, false);
28
+ emit Command(host, debitAccountId, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, false);
29
+ emit Labeled(debitAccountId, bytes32(0), "debitAccount");
31
30
  }
32
31
 
33
32
  /// @notice Override to customize request parsing or batching for debits.
@@ -37,12 +37,11 @@ abstract contract DepositPayableHook {
37
37
  /// Use `deposit` for assets arriving from outside the protocol (e.g. ERC-20 transfers, ETH).
38
38
  /// For internal balance deductions, use `debitAccount` instead.
39
39
  abstract contract Deposit is CommandBase, DepositHook {
40
- string private constant NAME = "deposit";
41
-
42
- uint internal immutable depositId = commandId(NAME);
40
+ uint internal immutable depositId = commandId(this.deposit.selector);
43
41
 
44
42
  constructor() {
45
- emit Command(host, depositId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, false);
43
+ emit Command(host, depositId, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, false);
44
+ emit Labeled(depositId, bytes32(0), "deposit");
46
45
  }
47
46
 
48
47
  /// @notice Deposit AMOUNT request blocks into the command account and output matching BALANCE blocks.
@@ -69,12 +68,11 @@ abstract contract Deposit is CommandBase, DepositHook {
69
68
  /// @notice Command that receives externally sourced assets and records them as BALANCE state.
70
69
  /// Use `depositPayable` when the hook needs tracked access to `msg.value` via a mutable budget.
71
70
  abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
72
- string private constant NAME = "depositPayable";
73
-
74
- uint internal immutable depositPayableId = commandId(NAME);
71
+ uint internal immutable depositPayableId = commandId(this.depositPayable.selector);
75
72
 
76
73
  constructor() {
77
- emit Command(host, depositPayableId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, true);
74
+ emit Command(host, depositPayableId, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, true);
75
+ emit Labeled(depositPayableId, bytes32(0), "depositPayable");
78
76
  }
79
77
 
80
78
  /// @notice Deposit AMOUNT request blocks with access to a mutable native-value budget.
@@ -22,12 +22,11 @@ abstract contract PayoutHook {
22
22
  /// @notice Command that sinks BALANCE state blocks to matching ACCOUNT request blocks.
23
23
  /// Each BALANCE block is paired with one ACCOUNT block at the same position.
24
24
  abstract contract Payout is CommandBase, PayoutHook {
25
- string private constant NAME = "payout";
26
-
27
- uint internal immutable payoutId = commandId(NAME);
25
+ uint internal immutable payoutId = commandId(this.payout.selector);
28
26
 
29
27
  constructor() {
30
- emit Command(host, payoutId, NAME, "1:1:0", Schemas.Account, Keys.Balance, Keys.Empty, false, false);
28
+ emit Command(host, payoutId, "1:1:0", Schemas.Account, Keys.Balance, Keys.Empty, false, false);
29
+ emit Labeled(payoutId, bytes32(0), "payout");
31
30
  }
32
31
 
33
32
  /// @notice Pay out BALANCE state blocks to matching ACCOUNT request blocks.
@@ -33,12 +33,11 @@ abstract contract ProvisionPayableHook {
33
33
  /// @notice Command that provisions assets to peer hosts from ALLOCATION request blocks.
34
34
  /// Each request block supplies the target host plus an asset amount; the output is a CUSTODY state stream.
35
35
  abstract contract Provision is CommandBase, ProvisionHook {
36
- string private constant NAME = "provision";
37
-
38
- uint internal immutable provisionId = commandId(NAME);
36
+ uint internal immutable provisionId = commandId(this.provision.selector);
39
37
 
40
38
  constructor() {
41
- emit Command(host, provisionId, NAME, "1:0:1", Schemas.Allocation, Keys.Empty, Keys.Custody, false, false);
39
+ emit Command(host, provisionId, "1:0:1", Schemas.Allocation, Keys.Empty, Keys.Custody, false, false);
40
+ emit Labeled(provisionId, bytes32(0), "provision");
42
41
  }
43
42
 
44
43
  /// @notice Provision ALLOCATION request blocks and output matching CUSTODY state blocks.
@@ -64,12 +63,11 @@ abstract contract Provision is CommandBase, ProvisionHook {
64
63
  /// Each request block supplies the target host plus an asset amount; the output is a CUSTODY state stream.
65
64
  /// The hook receives a mutable native-value budget drawn from `msg.value`.
66
65
  abstract contract ProvisionPayable is CommandBase, Payable, ProvisionPayableHook {
67
- string private constant NAME = "provisionPayable";
68
-
69
- uint internal immutable provisionPayableId = commandId(NAME);
66
+ uint internal immutable provisionPayableId = commandId(this.provisionPayable.selector);
70
67
 
71
68
  constructor() {
72
- emit Command(host, provisionPayableId, NAME, "1:0:1", Schemas.Allocation, Keys.Empty, Keys.Custody, false, true);
69
+ emit Command(host, provisionPayableId, "1:0:1", Schemas.Allocation, Keys.Empty, Keys.Custody, false, true);
70
+ emit Labeled(provisionPayableId, bytes32(0), "provisionPayable");
73
71
  }
74
72
 
75
73
  /// @notice Provision ALLOCATION request blocks with access to a mutable native-value budget.
@@ -25,12 +25,11 @@ abstract contract DispatchPayableHook {
25
25
  /// the same state from being duplicated across multiple relays.
26
26
  /// Produces no output state.
27
27
  abstract contract RelayPayable is CommandBase, Payable, DispatchPayableHook {
28
- string private constant NAME = "relayPayable";
29
-
30
- uint internal immutable relayPayableId = commandId(NAME);
28
+ uint internal immutable relayPayableId = commandId(this.relayPayable.selector);
31
29
 
32
30
  constructor() {
33
- emit Command(host, relayPayableId, NAME, "1:0:0", Schemas.Relay, Keys.Any, Keys.Empty, false, true);
31
+ emit Command(host, relayPayableId, "1:0:0", Schemas.Relay, Keys.Any, Keys.Empty, false, true);
32
+ emit Labeled(relayPayableId, bytes32(0), "relayPayable");
34
33
  }
35
34
 
36
35
  /// @notice Relay one RELAY request block with the command account and current state.
@@ -20,12 +20,11 @@ abstract contract WithdrawHook {
20
20
  /// Use `withdraw` for assets being sent outside the protocol (e.g. ERC-20 transfers, ETH sends).
21
21
  /// For internal balance credits, use `creditAccount` instead.
22
22
  abstract contract Withdraw is CommandBase, WithdrawHook {
23
- string private constant NAME = "withdraw";
24
-
25
- uint internal immutable withdrawId = commandId(NAME);
23
+ uint internal immutable withdrawId = commandId(this.withdraw.selector);
26
24
 
27
25
  constructor() {
28
- emit Command(host, withdrawId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
26
+ emit Command(host, withdrawId, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
27
+ emit Labeled(withdrawId, bytes32(0), "withdraw");
29
28
  }
30
29
 
31
30
  /// @notice Withdraw each BALANCE block from the command state to the command account.
@@ -18,12 +18,11 @@ abstract contract AllowAssetsHook {
18
18
  /// @notice Admin command that permits a list of (asset, meta) pairs via a virtual hook.
19
19
  /// Each ASSET block in the request calls `allowAsset`. Only callable by the admin account.
20
20
  abstract contract AllowAssets is CommandBase, AdminEvent, AllowAssetsHook {
21
- string private constant NAME = "allowAssets";
22
-
23
- uint internal immutable allowAssetsId = commandId(NAME);
21
+ uint internal immutable allowAssetsId = commandId(this.allowAssets.selector);
24
22
 
25
23
  constructor() {
26
- emit Admin(host, allowAssetsId, NAME, "1:0:0", Schemas.Asset, Keys.Empty, Keys.Empty, false, false);
24
+ emit Admin(host, allowAssetsId, "1:0:0", Schemas.Asset, Keys.Empty, Keys.Empty, false, false);
25
+ emit Labeled(allowAssetsId, bytes32(0), "allowAssets");
27
26
  }
28
27
 
29
28
  /// @notice Allow each ASSET block in the admin request.
@@ -22,11 +22,11 @@ abstract contract AllowanceHook {
22
22
  /// @notice Admin command that applies cross-host allowance entries via a virtual hook.
23
23
  /// Each ALLOWANCE block grants or updates a host-scoped asset cap. Only callable by the admin account.
24
24
  abstract contract Allowance is CommandBase, AdminEvent, AllowanceHook {
25
- string private constant NAME = "allowance";
26
- uint internal immutable allowanceId = commandId(NAME);
25
+ uint internal immutable allowanceId = commandId(this.allowance.selector);
27
26
 
28
27
  constructor() {
29
- emit Admin(host, allowanceId, NAME, "1:0:0", Schemas.Allowance, Keys.Empty, Keys.Empty, false, false);
28
+ emit Admin(host, allowanceId, "1:0:0", Schemas.Allowance, Keys.Empty, Keys.Empty, false, false);
29
+ emit Labeled(allowanceId, bytes32(0), "allowance");
30
30
  }
31
31
 
32
32
  /// @notice Apply each ALLOWANCE block in the admin request.
@@ -11,12 +11,11 @@ using Cursors for Cur;
11
11
  /// Each ACCOUNT block in the request is enabled as a guardian on the host.
12
12
  /// Only callable by the admin account.
13
13
  abstract contract Appoint is CommandBase, AdminEvent {
14
- string private constant NAME = "appoint";
15
-
16
- uint internal immutable appointId = commandId(NAME);
14
+ uint internal immutable appointId = commandId(this.appoint.selector);
17
15
 
18
16
  constructor() {
19
- emit Admin(host, appointId, NAME, "1:0:0", Schemas.Account, Keys.Empty, Keys.Empty, false, false);
17
+ emit Admin(host, appointId, "1:0:0", Schemas.Account, Keys.Empty, Keys.Empty, false, false);
18
+ emit Labeled(appointId, bytes32(0), "appoint");
20
19
  }
21
20
 
22
21
  /// @notice Appoint each ACCOUNT block in the admin request as a guardian.
@@ -11,12 +11,11 @@ using Cursors for Cur;
11
11
  /// Each NODE block in the request is authorized on the host.
12
12
  /// Only callable by the admin account.
13
13
  abstract contract Authorize is CommandBase, AdminEvent {
14
- string private constant NAME = "authorize";
15
-
16
- uint internal immutable authorizeId = commandId(NAME);
14
+ uint internal immutable authorizeId = commandId(this.authorize.selector);
17
15
 
18
16
  constructor() {
19
- emit Admin(host, authorizeId, NAME, "1:0:0", Schemas.Node, Keys.Empty, Keys.Empty, false, false);
17
+ emit Admin(host, authorizeId, "1:0:0", Schemas.Node, Keys.Empty, Keys.Empty, false, false);
18
+ emit Labeled(authorizeId, bytes32(0), "authorize");
20
19
  }
21
20
 
22
21
  /// @notice Authorize each NODE block in the admin request.
@@ -18,12 +18,11 @@ abstract contract DenyAssetsHook {
18
18
  /// @notice Admin command that blocks a list of (asset, meta) pairs via a virtual hook.
19
19
  /// Each ASSET block in the request calls `denyAsset`. Only callable by the admin account.
20
20
  abstract contract DenyAssets is CommandBase, AdminEvent, DenyAssetsHook {
21
- string private constant NAME = "denyAssets";
22
-
23
- uint internal immutable denyAssetsId = commandId(NAME);
21
+ uint internal immutable denyAssetsId = commandId(this.denyAssets.selector);
24
22
 
25
23
  constructor() {
26
- emit Admin(host, denyAssetsId, NAME, "1:0:0", Schemas.Asset, Keys.Empty, Keys.Empty, false, false);
24
+ emit Admin(host, denyAssetsId, "1:0:0", Schemas.Asset, Keys.Empty, Keys.Empty, false, false);
25
+ emit Labeled(denyAssetsId, bytes32(0), "denyAssets");
27
26
  }
28
27
 
29
28
  /// @notice Deny each ASSET block in the admin request.
@@ -17,12 +17,11 @@ abstract contract DestroyHook {
17
17
  /// @notice Admin command that runs host teardown logic via a virtual hook.
18
18
  /// The full request is passed to `destroy` as a cursor. Only callable by the admin account.
19
19
  abstract contract Destroy is CommandBase, AdminEvent, DestroyHook {
20
- string private constant NAME = "destroy";
21
-
22
- uint internal immutable destroyId = commandId(NAME);
20
+ uint internal immutable destroyId = commandId(this.destroy.selector);
23
21
 
24
22
  constructor(string memory input) {
25
- emit Admin(host, destroyId, NAME, "1:0:0", input, Keys.Empty, Keys.Empty, false, false);
23
+ emit Admin(host, destroyId, "1:0:0", input, Keys.Empty, Keys.Empty, false, false);
24
+ emit Labeled(destroyId, bytes32(0), "destroy");
26
25
  }
27
26
 
28
27
  /// @notice Run host teardown logic over the full admin request.
@@ -11,12 +11,11 @@ using Cursors for Cur;
11
11
  /// Each ACCOUNT block in the request is disabled as a guardian on the host.
12
12
  /// Only callable by the admin account.
13
13
  abstract contract Dismiss is CommandBase, AdminEvent {
14
- string private constant NAME = "dismiss";
15
-
16
- uint internal immutable dismissId = commandId(NAME);
14
+ uint internal immutable dismissId = commandId(this.dismiss.selector);
17
15
 
18
16
  constructor() {
19
- emit Admin(host, dismissId, NAME, "1:0:0", Schemas.Account, Keys.Empty, Keys.Empty, false, false);
17
+ emit Admin(host, dismissId, "1:0:0", Schemas.Account, Keys.Empty, Keys.Empty, false, false);
18
+ emit Labeled(dismissId, bytes32(0), "dismiss");
20
19
  }
21
20
 
22
21
  /// @notice Dismiss each ACCOUNT block in the admin request from guardian status.
@@ -16,12 +16,11 @@ using Cursors for Cur;
16
16
  /// Only callable by the admin account.
17
17
  /// Unspent top-level `msg.value` remains on this host.
18
18
  abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
19
- string private constant NAME = "executePayable";
20
-
21
- uint internal immutable executePayableId = commandId(NAME);
19
+ uint internal immutable executePayableId = commandId(this.executePayable.selector);
22
20
 
23
21
  constructor() {
24
- emit Admin(host, executePayableId, NAME, "1:0:0", Schemas.Call, Keys.Empty, Keys.Empty, false, true);
22
+ emit Admin(host, executePayableId, "1:0:0", Schemas.Call, Keys.Empty, Keys.Empty, false, true);
23
+ emit Labeled(executePayableId, bytes32(0), "executePayable");
25
24
  }
26
25
 
27
26
  /// @notice Execute each CALL block in the admin request.
@@ -17,12 +17,11 @@ abstract contract InitHook {
17
17
  /// @notice Admin command that runs host initialization logic via a virtual hook.
18
18
  /// The full request is passed to `init` as a cursor. Only callable by the admin account.
19
19
  abstract contract Init is CommandBase, AdminEvent, InitHook {
20
- string private constant NAME = "init";
21
-
22
- uint internal immutable initId = commandId(NAME);
20
+ uint internal immutable initId = commandId(this.init.selector);
23
21
 
24
22
  constructor(string memory input) {
25
- emit Admin(host, initId, NAME, "1:0:0", input, Keys.Empty, Keys.Empty, false, false);
23
+ emit Admin(host, initId, "1:0:0", input, Keys.Empty, Keys.Empty, false, false);
24
+ emit Labeled(initId, bytes32(0), "init");
26
25
  }
27
26
 
28
27
  /// @notice Run host initialization logic over the full admin request.
@@ -0,0 +1,35 @@
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 {Cursors, Cur, Schemas} from "../../Cursors.sol";
6
+ import {AdminEvent} from "../../events/Admin.sol";
7
+ using Cursors for Cur;
8
+
9
+ /// @title Label
10
+ /// @notice Admin command that publishes namespaced labels for node IDs.
11
+ /// Each LABEL block in the request emits one `Labeled` event. Only callable by
12
+ /// the admin account.
13
+ abstract contract Label is CommandBase, AdminEvent {
14
+ uint internal immutable labelId = commandId(this.label.selector);
15
+
16
+ constructor() {
17
+ emit Admin(host, labelId, "1:0:0", Schemas.Label, Keys.Empty, Keys.Empty, false, false);
18
+ emit Labeled(labelId, bytes32(0), "label");
19
+ }
20
+
21
+ /// @notice Publish each LABEL block in the admin request.
22
+ /// @param c Admin command context; `c.request` must contain LABEL blocks.
23
+ /// @return Empty output state.
24
+ function label(CommandContext calldata c) external onlyAdmin(c.account) returns (bytes memory) {
25
+ (Cur memory request, , ) = Cursors.init(c.request, 0, 1);
26
+
27
+ while (request.i < request.len) {
28
+ (uint id, bytes32 namespace, string memory name) = request.unpackLabel();
29
+ emit Labeled(id, namespace, name);
30
+ }
31
+
32
+ request.complete();
33
+ return "";
34
+ }
35
+ }
@@ -11,12 +11,11 @@ using Cursors for Cur;
11
11
  /// Each NODE block in the request is deauthorized on the host.
12
12
  /// Only callable by the admin account.
13
13
  abstract contract Unauthorize is CommandBase, AdminEvent {
14
- string private constant NAME = "unauthorize";
15
-
16
- uint internal immutable unauthorizeId = commandId(NAME);
14
+ uint internal immutable unauthorizeId = commandId(this.unauthorize.selector);
17
15
 
18
16
  constructor() {
19
- emit Admin(host, unauthorizeId, NAME, "1:0:0", Schemas.Node, Keys.Empty, Keys.Empty, false, false);
17
+ emit Admin(host, unauthorizeId, "1:0:0", Schemas.Node, Keys.Empty, Keys.Empty, false, false);
18
+ emit Labeled(unauthorizeId, bytes32(0), "unauthorize");
20
19
  }
21
20
 
22
21
  /// @notice Unauthorize each NODE block in the admin request.
package/core/Host.sol CHANGED
@@ -7,6 +7,7 @@ import {Authorize} from "../commands/admin/Authorize.sol";
7
7
  import {Dismiss} from "../commands/admin/Dismiss.sol";
8
8
  import {Unauthorize} from "../commands/admin/Unauthorize.sol";
9
9
  import {ExecutePayable} from "../commands/admin/Execute.sol";
10
+ import {Label} from "../commands/admin/Label.sol";
10
11
  import {Revoke} from "../guards/Revoke.sol";
11
12
  import {IntroductionEvent} from "../events/Introduction.sol";
12
13
  import {Ids} from "../utils/Ids.sol";
@@ -17,9 +18,7 @@ interface IHostIntroduction {
17
18
  /// @notice Record a host introduction claim.
18
19
  /// @param peer Host node ID being introduced.
19
20
  /// @param blocknum Block number at which the introduction was made.
20
- /// @param version Protocol version the host is running.
21
- /// @param namespace Human-readable namespace or label for the host.
22
- function introduce(uint peer, uint blocknum, uint16 version, string calldata namespace) external;
21
+ function introduce(uint peer, uint blocknum) external;
23
22
  }
24
23
 
25
24
  /// @title Host
@@ -34,6 +33,7 @@ abstract contract Host is
34
33
  Revoke,
35
34
  Appoint,
36
35
  Dismiss,
36
+ Label,
37
37
  ExecutePayable,
38
38
  IntroductionEvent,
39
39
  IHostIntroduction
@@ -41,21 +41,17 @@ abstract contract Host is
41
41
  /// @param cmdr Commander address; passed to `AccessControl`.
42
42
  /// If `cmdr` is a deployed contract, the host calls `introduce`
43
43
  /// on it during construction.
44
- /// @param version Protocol version number to publish in the announcement.
45
- /// @param namespace Human-readable namespace string for the host.
46
- constructor(address cmdr, uint16 version, string memory namespace) AccessControl(cmdr) {
44
+ constructor(address cmdr) AccessControl(cmdr) {
47
45
  if (cmdr == address(0) || cmdr == address(this) || cmdr.code.length == 0) return;
48
- IHostIntroduction(cmdr).introduce(host, block.number, version, namespace);
46
+ IHostIntroduction(cmdr).introduce(host, block.number);
49
47
  }
50
48
 
51
49
  /// @notice Record a host introduction claim.
52
50
  /// @dev Validates that `peer` matches `msg.sender`; it does not authorize or trust the introduced host.
53
51
  /// @param peer Host node ID being introduced.
54
52
  /// @param blocknum Block number at which the host was deployed.
55
- /// @param version Protocol version the host implements.
56
- /// @param namespace Human-readable namespace string for the host.
57
- function introduce(uint peer, uint blocknum, uint16 version, string calldata namespace) external {
58
- emit Introduction(Ids.matchHost(peer, msg.sender), blocknum, version, namespace);
53
+ function introduce(uint peer, uint blocknum) external {
54
+ emit Introduction(Ids.matchHost(peer, msg.sender), blocknum);
59
55
  }
60
56
 
61
57
  /// @notice Accept native ETH transfers (e.g. from command value flows).
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.1.0",
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",
@@ -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
@@ -12,11 +12,11 @@ using Cursors for Cur;
12
12
  /// @title PeerDispatchPayable
13
13
  /// @notice Peer endpoint that forwards DISPATCH blocks to a host-defined dispatch hook.
14
14
  abstract contract PeerDispatchPayable is PeerBase, Payable, DispatchPayableHook {
15
- string private constant NAME = "peerDispatchPayable";
16
- uint internal immutable peerDispatchPayableId = peerId(NAME);
15
+ uint internal immutable peerDispatchPayableId = peerId(this.peerDispatchPayable.selector);
17
16
 
18
17
  constructor() {
19
- 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");
20
20
  }
21
21
 
22
22
  /// @notice Forward peer-supplied dispatches to the host-defined dispatch hook.
package/peer/Pipe.sol CHANGED
@@ -13,11 +13,11 @@ using Cursors for Cur;
13
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.
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.