@rootzero/contracts 1.14.0 → 1.16.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 (68) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/Codec.sol +1 -1
  3. package/Commands.sol +1 -1
  4. package/Core.sol +8 -5
  5. package/Endpoints.sol +6 -6
  6. package/Events.sol +1 -3
  7. package/README.md +118 -35
  8. package/annotations/Action.sol +17 -0
  9. package/annotations/Label.sol +23 -0
  10. package/annotations/Schema.sol +53 -0
  11. package/codec/Blocks.sol +127 -32
  12. package/codec/Buffers.sol +3 -3
  13. package/codec/Decoders.sol +46 -13
  14. package/codec/Descriptors.sol +0 -1
  15. package/codec/Keys.sol +8 -4
  16. package/codec/Readers.sol +13 -0
  17. package/codec/Schema.sol +12 -3
  18. package/codec/Specs.sol +28 -4
  19. package/codec/Writers.sol +21 -6
  20. package/commands/Base.sol +39 -44
  21. package/commands/Burn.sol +8 -4
  22. package/commands/Credit.sol +35 -3
  23. package/commands/Debit.sol +46 -13
  24. package/commands/Deposit.sol +14 -8
  25. package/commands/Payout.sol +6 -2
  26. package/commands/Provision.sol +4 -4
  27. package/commands/Recover.sol +15 -8
  28. package/commands/Relay.sol +37 -12
  29. package/commands/Settle.sol +77 -0
  30. package/commands/Withdraw.sol +8 -4
  31. package/commands/admin/AllowAssets.sol +2 -2
  32. package/commands/admin/Allowance.sol +2 -2
  33. package/commands/admin/Annotate.sol +36 -0
  34. package/commands/admin/Appoint.sol +6 -5
  35. package/commands/admin/Authorize.sol +2 -2
  36. package/commands/admin/Base.sol +8 -1
  37. package/commands/admin/DenyAssets.sol +2 -2
  38. package/commands/admin/Dismiss.sol +6 -5
  39. package/commands/admin/Execute.sol +5 -4
  40. package/commands/admin/Unauthorize.sol +2 -2
  41. package/core/Access.sol +91 -49
  42. package/core/Calls.sol +27 -22
  43. package/core/Endpoint.sol +36 -46
  44. package/core/Host.sol +63 -21
  45. package/core/Pipeline.sol +6 -6
  46. package/core/Settlement.sol +37 -8
  47. package/core/Types.sol +13 -1
  48. package/docs/Schema.md +68 -7
  49. package/events/Annotation.sol +24 -0
  50. package/events/Guardian.sol +2 -2
  51. package/events/Introduction.sol +3 -2
  52. package/execution/Budget.sol +12 -4
  53. package/execution/Execution.sol +113 -18
  54. package/guards/Base.sol +4 -4
  55. package/package.json +1 -1
  56. package/ports/Base.sol +19 -7
  57. package/ports/Dispatch.sol +6 -6
  58. package/ports/{Settle.sol → Post.sol} +13 -9
  59. package/queries/Base.sol +18 -3
  60. package/utils/Accounts.sol +0 -23
  61. package/utils/Actions.sol +1 -0
  62. package/utils/Cursors.sol +79 -34
  63. package/utils/Layout.sol +0 -2
  64. package/commands/admin/Label.sol +0 -36
  65. package/commands/admin/Schemas.sol +0 -36
  66. package/events/Labeled.sol +0 -21
  67. package/events/Position.sol +0 -22
  68. package/events/Schema.sol +0 -23
@@ -2,6 +2,8 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
5
+ import {Action} from "../annotations/Action.sol";
6
+ import {Actions} from "../utils/Actions.sol";
5
7
  using Executions for Execution;
6
8
 
7
9
  /// @notice Hook implemented by hosts that withdraw account balances.
@@ -18,11 +20,13 @@ abstract contract WithdrawHook {
18
20
  /// @notice Command that delivers BALANCE state blocks to an external destination.
19
21
  /// Use `withdraw` for assets being sent outside the protocol (e.g. ERC-20 transfers, ETH sends).
20
22
  /// For internal balance credits, use `creditAccount` instead.
21
- abstract contract Withdraw is CommandBase, WithdrawHook {
23
+ abstract contract Withdraw is CommandBase, WithdrawHook, Action {
22
24
  uint private immutable descriptor;
23
25
 
24
26
  constructor() {
25
- (, descriptor) = command("withdraw", Specs.Balance, Specs.Empty, Specs.Empty, 0, false, false);
27
+ uint id;
28
+ (id, descriptor) = command("withdraw", Specs.Balance, Specs.Empty, Specs.Empty, 0, false, false);
29
+ action(id, Actions.Withdraw);
26
30
  }
27
31
 
28
32
  /// @notice Withdraw each BALANCE block from the command state to the command account.
@@ -32,9 +36,9 @@ abstract contract Withdraw is CommandBase, WithdrawHook {
32
36
  function withdraw(
33
37
  bytes32 account,
34
38
  bytes calldata state,
35
- bytes calldata
39
+ bytes calldata input
36
40
  ) external onlyCommand returns (bytes memory, bytes memory) {
37
- Execution memory exec = openState(state, descriptor, 0);
41
+ Execution memory exec = openCommand(state, input, descriptor, 0);
38
42
 
39
43
  while (exec.more()) {
40
44
  (bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
@@ -28,10 +28,10 @@ abstract contract AllowAssets is AdminBase, AllowAssetsHook {
28
28
  /// @return Empty transaction stream.
29
29
  function allowAssets(
30
30
  bytes32 account,
31
- bytes calldata,
31
+ bytes calldata state,
32
32
  bytes calldata input
33
33
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
34
- Execution memory exec = openInput(input, descriptor, 0);
34
+ Execution memory exec = openCommand(state, input, descriptor, 0);
35
35
 
36
36
  while (exec.more()) {
37
37
  bytes32 asset = exec.unpackAsset(Lanes.Input);
@@ -32,10 +32,10 @@ abstract contract Allowance is AdminBase, AllowanceHook {
32
32
  /// @return Empty transaction stream.
33
33
  function allowance(
34
34
  bytes32 account,
35
- bytes calldata,
35
+ bytes calldata state,
36
36
  bytes calldata input
37
37
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
38
- Execution memory exec = openInput(input, descriptor, 0);
38
+ Execution memory exec = openCommand(state, input, descriptor, 0);
39
39
 
40
40
  while (exec.more()) {
41
41
  (uint peer, bytes32 asset, uint amount) = exec.unpackAllowance(Lanes.Input);
@@ -0,0 +1,36 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {AdminBase, Execution, Executions, Lanes, Specs} from "./Base.sol";
5
+ using Executions for Execution;
6
+
7
+ /// @title Annotate
8
+ /// @notice Admin command that attaches encoded annotation block streams to entities.
9
+ /// Each ANNOTATION block in the input emits one `Annotation` event. Only callable
10
+ /// by the admin account.
11
+ abstract contract Annotate is AdminBase {
12
+ uint private immutable descriptor;
13
+
14
+ constructor() {
15
+ (, descriptor) = command("annotate", Specs.Empty, Specs.Annotation, Specs.Empty, 0, false, true);
16
+ }
17
+
18
+ /// @notice Publish each ANNOTATION block in the admin input.
19
+ /// @param input ANNOTATION block stream.
20
+ /// @return Empty output state.
21
+ /// @return Empty transaction stream.
22
+ function annotate(
23
+ bytes32 account,
24
+ bytes calldata state,
25
+ bytes calldata input
26
+ ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
27
+ Execution memory exec = openCommand(state, input, descriptor, 0);
28
+
29
+ while (exec.more()) {
30
+ (uint entity, bytes calldata data) = exec.unpackAnnotation(Lanes.Input);
31
+ emit Annotation(entity, data);
32
+ }
33
+
34
+ return close(exec, account);
35
+ }
36
+ }
@@ -2,29 +2,30 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import { AdminBase, Execution, Executions, Lanes, Specs } from "./Base.sol";
5
+ import { GuardianAccess } from "../../core/Access.sol";
5
6
  using Executions for Execution;
6
7
 
7
8
  /// @title Appoint
8
9
  /// @notice Admin command that grants guardian status to a list of account IDs.
9
- /// Each ACCOUNT block in the input is enabled as a guardian on the host.
10
+ /// Each USER ACCOUNT block in the input is assigned the guardian role on the host.
10
11
  /// Only callable by the admin account.
11
- abstract contract Appoint is AdminBase {
12
+ abstract contract Appoint is GuardianAccess, AdminBase {
12
13
  uint private immutable descriptor;
13
14
 
14
15
  constructor() {
15
16
  (, descriptor) = command("appoint", Specs.Empty, Specs.Account, Specs.Empty, 0, false, true);
16
17
  }
17
18
 
18
- /// @notice Appoint each ACCOUNT block in the admin input as a guardian.
19
+ /// @notice Appoint each user ACCOUNT block in the admin input as a guardian.
19
20
  /// @param input ACCOUNT block stream.
20
21
  /// @return Empty output state.
21
22
  /// @return Empty transaction stream.
22
23
  function appoint(
23
24
  bytes32 account,
24
- bytes calldata,
25
+ bytes calldata state,
25
26
  bytes calldata input
26
27
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
27
- Execution memory exec = openInput(input, descriptor, 0);
28
+ Execution memory exec = openCommand(state, input, descriptor, 0);
28
29
 
29
30
  while (exec.more()) {
30
31
  bytes32 guardian = exec.unpackAccount(Lanes.Input);
@@ -27,10 +27,10 @@ abstract contract Authorize is AdminBase {
27
27
  /// @return Empty transaction stream.
28
28
  function authorize(
29
29
  bytes32 account,
30
- bytes calldata,
30
+ bytes calldata state,
31
31
  bytes calldata input
32
32
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
33
- Execution memory exec = openInput(input, descriptor, 0);
33
+ Execution memory exec = openCommand(state, input, descriptor, 0);
34
34
 
35
35
  while (exec.more()) {
36
36
  uint node = exec.unpackNode(Lanes.Input);
@@ -2,7 +2,14 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {CommandBase, Execution, Executions, Lanes, Specs} from "../Base.sol";
5
+ import {NodeAccess} from "../../core/Access.sol";
5
6
 
6
7
  /// @title AdminBase
7
8
  /// @notice Shared base for admin commands.
8
- abstract contract AdminBase is CommandBase {}
9
+ abstract contract AdminBase is NodeAccess, CommandBase {
10
+ /// @dev Restrict execution to the commander using the host's admin account.
11
+ modifier onlyAdmin(bytes32 account) {
12
+ enforceAdmin(account, msg.sender);
13
+ _;
14
+ }
15
+ }
@@ -28,10 +28,10 @@ abstract contract DenyAssets is AdminBase, DenyAssetsHook {
28
28
  /// @return Empty transaction stream.
29
29
  function denyAssets(
30
30
  bytes32 account,
31
- bytes calldata,
31
+ bytes calldata state,
32
32
  bytes calldata input
33
33
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
34
- Execution memory exec = openInput(input, descriptor, 0);
34
+ Execution memory exec = openCommand(state, input, descriptor, 0);
35
35
 
36
36
  while (exec.more()) {
37
37
  bytes32 asset = exec.unpackAsset(Lanes.Input);
@@ -2,29 +2,30 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import { AdminBase, Execution, Executions, Lanes, Specs } from "./Base.sol";
5
+ import { GuardianAccess } from "../../core/Access.sol";
5
6
  using Executions for Execution;
6
7
 
7
8
  /// @title Dismiss
8
9
  /// @notice Admin command that revokes guardian status from a list of account IDs.
9
- /// Each ACCOUNT block in the input is disabled as a guardian on the host.
10
+ /// Each USER ACCOUNT block in the input loses the guardian role on the host.
10
11
  /// Only callable by the admin account.
11
- abstract contract Dismiss is AdminBase {
12
+ abstract contract Dismiss is GuardianAccess, AdminBase {
12
13
  uint private immutable descriptor;
13
14
 
14
15
  constructor() {
15
16
  (, descriptor) = command("dismiss", Specs.Empty, Specs.Account, Specs.Empty, 0, false, true);
16
17
  }
17
18
 
18
- /// @notice Dismiss each ACCOUNT block in the admin input from guardian status.
19
+ /// @notice Dismiss each user ACCOUNT block in the admin input from guardian status.
19
20
  /// @param input ACCOUNT block stream.
20
21
  /// @return Empty output state.
21
22
  /// @return Empty transaction stream.
22
23
  function dismiss(
23
24
  bytes32 account,
24
- bytes calldata,
25
+ bytes calldata state,
25
26
  bytes calldata input
26
27
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
27
- Execution memory exec = openInput(input, descriptor, 0);
28
+ Execution memory exec = openCommand(state, input, descriptor, 0);
28
29
 
29
30
  while (exec.more()) {
30
31
  bytes32 guardian = exec.unpackAccount(Lanes.Input);
@@ -2,6 +2,7 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {AdminBase, Execution, Executions, Lanes, Specs} from "./Base.sol";
5
+ import {RawNodeCalls} from "../../core/Calls.sol";
5
6
 
6
7
  using Executions for Execution;
7
8
 
@@ -10,7 +11,7 @@ using Executions for Execution;
10
11
  /// Each CALL block specifies a target node ID, packed resources, and raw calldata payload.
11
12
  /// Only callable by the admin account.
12
13
  /// Unspent top-level `msg.value` is returned as a refund transaction.
13
- abstract contract ExecutePayable is AdminBase {
14
+ abstract contract ExecutePayable is RawNodeCalls, AdminBase {
14
15
  uint private immutable descriptor;
15
16
 
16
17
  constructor() {
@@ -23,14 +24,14 @@ abstract contract ExecutePayable is AdminBase {
23
24
  /// @return Remaining native value as a refund transaction stream.
24
25
  function executePayable(
25
26
  bytes32 account,
26
- bytes calldata,
27
+ bytes calldata state,
27
28
  bytes calldata input
28
29
  ) external payable onlyAdmin(account) returns (bytes memory, bytes memory) {
29
- Execution memory exec = openInput(input, descriptor, 0);
30
+ Execution memory exec = openCommand(state, input, descriptor, 0);
30
31
 
31
32
  while (exec.more()) {
32
33
  (uint target, uint resources, bytes calldata data) = exec.unpackCall(Lanes.Input);
33
- rawCall(target, exec.useValue(resources), data);
34
+ rawCall(target, exec.useResourceValue(resources), data);
34
35
  }
35
36
 
36
37
  return close(exec, account);
@@ -27,10 +27,10 @@ abstract contract Unauthorize is AdminBase {
27
27
  /// @return Empty transaction stream.
28
28
  function unauthorize(
29
29
  bytes32 account,
30
- bytes calldata,
30
+ bytes calldata state,
31
31
  bytes calldata input
32
32
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
33
- Execution memory exec = openInput(input, descriptor, 0);
33
+ Execution memory exec = openCommand(state, input, descriptor, 0);
34
34
 
35
35
  while (exec.more()) {
36
36
  uint node = exec.unpackNode(Lanes.Input);
package/core/Access.sol CHANGED
@@ -8,34 +8,75 @@ import {Accounts} from "../utils/Accounts.sol";
8
8
  import {Nodes} from "../utils/Nodes.sol";
9
9
  import {addrOr} from "../utils/Utils.sol";
10
10
 
11
- /// @title AccessControl
12
- /// @notice Host access control layer.
13
- /// Tracks an immutable trusted commander, the host's own node ID, and a
14
- /// mapping of externally trusted node IDs. Inbound trust is host-based:
15
- /// trusted hosts, the commander, and this contract itself may interact
16
- /// with the host through the guarded command and peer entrypoints.
17
- abstract contract AccessControl is Runtime, NodeEvent, GuardianEvent {
18
- /// @dev Trusted commander address. All calls from this address are implicitly trusted.
19
- /// Defaults to `address(this)` when no external commander is provided.
20
- address internal immutable commander;
21
- /// @dev Admin account ID derived from the commander address at construction time.
22
- bytes32 internal immutable admin;
11
+ /// @dev Thrown when a caller, account, or node lacks required access.
12
+ error AccessDenied();
13
+ error CommanderNotAllowed();
23
14
 
24
- /// @dev Mapping from guardian account ID to guardian status.
25
- mapping(bytes32 account => bool) internal guardians;
15
+ /// @title CallerAccess
16
+ /// @notice Authorization capability required by command entrypoints.
17
+ abstract contract CallerAccess is Runtime {
18
+ /// @notice Assert that `caller` may invoke a command and return it.
19
+ function enforceCaller(address caller) internal view virtual returns (address);
20
+ }
26
21
 
27
- /// @dev Mapping from node ID to trust status.
28
- mapping(uint node => bool) internal nodes;
22
+ /// @title TrustAccess
23
+ /// @notice Authorization capability required by trusted outbound node calls.
24
+ abstract contract TrustAccess {
25
+ /// @notice Assert that `node` is trusted and return it.
26
+ function ensureTrusted(uint node) internal view virtual returns (uint);
27
+ }
29
28
 
30
- /// @dev Thrown when a caller, account, or node lacks required access.
31
- error AccessDenied();
29
+ /// @title CommanderAccess
30
+ /// @notice Minimal commander-based access control shared by host access policies.
31
+ abstract contract CommanderAccess is Runtime {
32
+ /// @dev Trusted commander address.
33
+ /// Defaults to `address(this)` when no external commander is provided.
34
+ address internal immutable commander;
32
35
 
33
36
  /// @param cmdr Commander address, or zero to make this contract self-managed.
34
37
  constructor(address cmdr) {
35
38
  commander = addrOr(cmdr, address(this));
39
+ }
40
+
41
+ /// @notice Assert that `caller` is the commander and return it.
42
+ /// @param caller Address to validate.
43
+ /// @return The same `caller` value if it is the commander.
44
+ function enforceCommander(address caller) internal view returns (address) {
45
+ if (caller == address(0) || caller != commander) {
46
+ revert AccessDenied();
47
+ }
48
+ return caller;
49
+ }
50
+
51
+ }
52
+
53
+ /// @title AdminAccess
54
+ /// @notice Commander access with the admin account derived from the commander.
55
+ abstract contract AdminAccess is CommanderAccess {
56
+ /// @dev Admin account ID derived from the commander address at construction time.
57
+ bytes32 internal immutable admin;
58
+
59
+ constructor() {
36
60
  admin = Accounts.toAdmin(commander);
37
61
  }
38
62
 
63
+ /// @notice Assert that `account` is the admin account and `caller` is the commander.
64
+ function enforceAdmin(bytes32 account, address caller) internal view returns (bytes32) {
65
+ if (account != admin) revert AccessDenied();
66
+ enforceCommander(caller);
67
+ return account;
68
+ }
69
+ }
70
+
71
+ /// @title NodeAccess
72
+ /// @notice Admin access extended with externally trusted node IDs.
73
+ /// Inbound trust is host-based:
74
+ /// trusted hosts, the commander, and this contract itself may interact
75
+ /// with the host through the guarded command and peer entrypoints.
76
+ abstract contract NodeAccess is AdminAccess, TrustAccess, NodeEvent {
77
+ /// @dev Mapping from node ID to trust status.
78
+ mapping(uint node => bool) internal nodes;
79
+
39
80
  /// @notice Set authorization status for a node.
40
81
  /// @param node Node ID to update.
41
82
  /// @param active True to authorize the node, false to revoke it.
@@ -44,58 +85,59 @@ abstract contract AccessControl is Runtime, NodeEvent, GuardianEvent {
44
85
  emit Node(host, node, active);
45
86
  }
46
87
 
47
- /// @notice Set guardian status for an account.
48
- /// @param account Guardian account ID to update.
49
- /// @param active True to enable the guardian, false to revoke it.
50
- function setGuardian(bytes32 account, bool active) internal {
51
- Accounts.guardian(account);
52
- guardians[account] = active;
53
- emit Guardian(host, account, active);
54
- }
55
-
56
- /// @notice Return true if `addr` is an active guardian.
57
- /// @param addr EVM address to check as a guardian account.
58
- function isGuardian(address addr) internal view returns (bool) {
59
- return guardians[Accounts.toGuardian(addr)];
60
- }
61
-
62
88
  /// @notice Return true if `caller` is an implicitly trusted address.
63
89
  /// Trusted callers: the commander, this contract itself, or any address
64
90
  /// whose host ID has been explicitly authorized.
65
91
  /// @param caller Address to check.
66
- function isTrusted(address caller) internal view returns (bool) {
92
+ function isTrustedCaller(address caller) internal view returns (bool) {
67
93
  return caller == commander || caller == address(this) || nodes[Nodes.toHost(caller)];
68
94
  }
69
95
 
70
96
  /// @notice Assert that `node` is in the trusted set and return it.
71
97
  /// @param node Node ID to validate.
72
98
  /// @return The same `node` value if trusted.
73
- function ensureTrusted(uint node) internal view returns (uint) {
99
+ function ensureTrusted(uint node) internal view override returns (uint) {
74
100
  if (node == 0 || !nodes[node]) {
75
101
  revert AccessDenied();
76
102
  }
77
103
  return node;
78
104
  }
79
105
 
80
- /// @notice Assert that `caller` is trusted and return it.
81
- /// Used by command and peer modifiers to gate execution to authorized senders.
82
- /// @param caller Address to validate.
83
- /// @return The same `caller` value if trusted.
84
- function enforceCaller(address caller) internal view returns (address) {
85
- if (caller == address(0) || !isTrusted(caller)) {
106
+ /// @notice Assert that `caller` is a trusted peer other than the commander.
107
+ function enforcePeer(address caller) internal view returns (address) {
108
+ if (caller == commander) revert CommanderNotAllowed();
109
+ if (caller == address(0) || !isTrustedCaller(caller)) {
86
110
  revert AccessDenied();
87
111
  }
88
112
  return caller;
89
113
  }
90
114
 
91
- /// @notice Assert that `caller` is the commander and return it.
92
- /// Used by admin modifiers to keep governance authority separate from peer trust.
93
- /// @param caller Address to validate.
94
- /// @return The same `caller` value if it is the commander.
95
- function enforceCommander(address caller) internal view returns (address) {
96
- if (caller == address(0) || caller != commander) {
97
- revert AccessDenied();
98
- }
115
+ }
116
+
117
+ /// @title GuardianAccess
118
+ /// @notice Node access extended with guardian identity and authorization.
119
+ abstract contract GuardianAccess is NodeAccess, GuardianEvent {
120
+ /// @dev Mapping from user account ID to guardian status.
121
+ mapping(bytes32 account => bool) internal guardians;
122
+
123
+ /// @notice Set guardian status for an account.
124
+ /// @param account User account ID whose guardian role is updated.
125
+ /// @param active True to enable the guardian, false to revoke it.
126
+ function setGuardian(bytes32 account, bool active) internal {
127
+ account = Accounts.user(account);
128
+ guardians[account] = active;
129
+ emit Guardian(host, account, active);
130
+ }
131
+
132
+ /// @notice Return true if `addr` is an active guardian.
133
+ /// @param addr EVM address to check for the guardian role.
134
+ function isGuardian(address addr) internal view returns (bool) {
135
+ return guardians[Accounts.toUser(addr)];
136
+ }
137
+
138
+ /// @notice Assert that `caller` is an active guardian and return it.
139
+ function enforceGuardian(address caller) internal view returns (address) {
140
+ if (caller == address(0) || !isGuardian(caller)) revert AccessDenied();
99
141
  return caller;
100
142
  }
101
143
  }
package/core/Calls.sol CHANGED
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {AccessControl} from "./Access.sol";
4
+ import {TrustAccess} from "./Access.sol";
5
5
  import {Nodes} from "../utils/Nodes.sol";
6
6
 
7
7
  /// @dev Emitted when a trusted inter-node call fails.
@@ -10,9 +10,9 @@ import {Nodes} from "../utils/Nodes.sol";
10
10
  /// @param err Revert data returned by the failed call.
11
11
  error FailedCall(address addr, bytes4 selector, bytes err);
12
12
 
13
- /// @title NodeCalls
14
- /// @notice Shared low-level inter-node call helpers for contracts that can talk to other nodes.
15
- abstract contract NodeCalls is AccessControl {
13
+ /// @title RawNodeCalls
14
+ /// @notice Low-level inter-node call helpers without target authorization.
15
+ abstract contract RawNodeCalls {
16
16
  /// @notice Try a raw low-level call to another node and return whether it succeeded.
17
17
  /// @param node Node ID of the callee.
18
18
  /// @param value Native value to forward in wei.
@@ -23,15 +23,6 @@ abstract contract NodeCalls is AccessControl {
23
23
  (success, ) = payable(addr).call{value: value}(data);
24
24
  }
25
25
 
26
- /// @notice Try a trusted low-level call to another node and return whether it succeeded.
27
- /// @param node Node ID of the callee.
28
- /// @param value Native value to forward in wei.
29
- /// @param data Encoded calldata to send.
30
- /// @return success True if the low-level call succeeded.
31
- function tryTrustedCall(uint node, uint128 value, bytes memory data) internal returns (bool success) {
32
- return tryRawCall(ensureTrusted(node), value, data);
33
- }
34
-
35
26
  /// @notice Make a raw low-level call to another node and revert when it fails.
36
27
  /// @param node Node ID of the callee.
37
28
  /// @param value Native value to forward in wei.
@@ -44,15 +35,6 @@ abstract contract NodeCalls is AccessControl {
44
35
  if (!success) revert FailedCall(addr, bytes4(data), out);
45
36
  }
46
37
 
47
- /// @notice Make a trusted low-level call to another node and revert when it fails.
48
- /// @param node Node ID of the callee.
49
- /// @param value Native value to forward in wei.
50
- /// @param data Encoded calldata to send.
51
- /// @return out Return data from the successful call.
52
- function trustedCall(uint node, uint128 value, bytes memory data) internal returns (bytes memory out) {
53
- return rawCall(ensureTrusted(node), value, data);
54
- }
55
-
56
38
  /// @notice Make a raw low-level read-only query to another node and revert when it fails.
57
39
  /// @param node Node ID of the callee.
58
40
  /// @param data Encoded calldata to send.
@@ -64,6 +46,29 @@ abstract contract NodeCalls is AccessControl {
64
46
  if (!success) revert FailedCall(addr, bytes4(data), out);
65
47
  }
66
48
 
49
+ }
50
+
51
+ /// @title NodeCalls
52
+ /// @notice Trusted low-level inter-node calls backed by a host-provided node policy.
53
+ abstract contract NodeCalls is RawNodeCalls, TrustAccess {
54
+ /// @notice Try a trusted low-level call to another node and return whether it succeeded.
55
+ /// @param node Node ID of the callee.
56
+ /// @param value Native value to forward in wei.
57
+ /// @param data Encoded calldata to send.
58
+ /// @return success True if the low-level call succeeded.
59
+ function tryTrustedCall(uint node, uint128 value, bytes memory data) internal returns (bool success) {
60
+ return tryRawCall(ensureTrusted(node), value, data);
61
+ }
62
+
63
+ /// @notice Make a trusted low-level call to another node and revert when it fails.
64
+ /// @param node Node ID of the callee.
65
+ /// @param value Native value to forward in wei.
66
+ /// @param data Encoded calldata to send.
67
+ /// @return out Return data from the successful call.
68
+ function trustedCall(uint node, uint128 value, bytes memory data) internal returns (bytes memory out) {
69
+ return rawCall(ensureTrusted(node), value, data);
70
+ }
71
+
67
72
  /// @notice Make a trusted low-level read-only query to another node and revert when it fails.
68
73
  /// @param node Node ID of the callee.
69
74
  /// @param data Encoded calldata to send.
package/core/Endpoint.sol CHANGED
@@ -1,57 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {Specs} from "../codec/Specs.sol";
5
4
  import {Execution, Executions} from "../execution/Execution.sol";
6
5
  import {EndpointEvent} from "../events/Endpoint.sol";
7
- import {LabeledEvent} from "../events/Labeled.sol";
8
- import {SchemaEvent} from "../events/Schema.sol";
6
+ import {Label} from "../annotations/Label.sol";
7
+ import {Schema} from "../annotations/Schema.sol";
9
8
  import {Descriptors} from "../codec/Descriptors.sol";
10
- import {Runtime} from "./Runtime.sol";
11
9
 
12
10
  /// @title EndpointBase
13
11
  /// @notice Shared endpoint metadata helpers.
14
- abstract contract EndpointBase is Runtime, EndpointEvent, LabeledEvent, SchemaEvent {
15
- /// @notice Open an endpoint input stream with an expected batch count.
16
- /// @param source Input block stream to open.
17
- /// @param descriptor Packed endpoint descriptor.
18
- /// @param batches Required batch count, or zero to accept the input count.
19
- /// @return exec Execution with its output buffer metadata initialized for the input batch count.
20
- function openInput(
21
- bytes calldata source,
22
- uint descriptor,
23
- uint batches
24
- ) internal view returns (Execution memory exec) {
25
- return Executions.openInput(source, descriptor, batches);
26
- }
27
-
28
- /// @notice Finalize an execution output and return its encoded block stream.
29
- /// @param exec Completed endpoint execution.
30
- /// @return Encoded output block stream.
31
- function close(Execution memory exec) internal pure returns (bytes memory) {
32
- return Executions.finish(exec);
33
- }
34
-
35
- /// @notice Construct and publish a context-local block specification.
36
- /// @param key Context-local key value.
37
- /// @param min Minimum accepted payload length.
38
- /// @param max Maximum accepted payload length; zero means unbounded.
39
- /// @param hint Initial per-block payload capacity.
40
- /// @param body Schema DSL string describing the block payload body.
41
- /// @param name Schema alias name, or zero for unnamed schemas.
42
- /// @return spec The context-local block specification.
43
- function schema(
44
- uint32 key,
45
- uint32 min,
46
- uint32 max,
47
- uint32 hint,
48
- string memory body,
49
- bytes32 name
50
- ) internal returns (uint spec) {
51
- spec = Specs.create(bytes4(key), min, max, hint);
52
- emit Schema(host, spec, body, name);
53
- }
54
-
12
+ abstract contract EndpointBase is EndpointEvent, Label, Schema {
55
13
  /// @notice Create and publish endpoint metadata with a default label.
56
14
  /// @param id Endpoint node ID.
57
15
  /// @param name Default human-readable endpoint label.
@@ -71,7 +29,39 @@ abstract contract EndpointBase is Runtime, EndpointEvent, LabeledEvent, SchemaEv
71
29
  uint8 flags
72
30
  ) internal returns (uint descriptor) {
73
31
  descriptor = Descriptors.create(state, input, output, transactions, flags);
32
+ return endpoint(id, name, descriptor);
33
+ }
34
+
35
+ /// @notice Publish already constructed endpoint metadata with a default label.
36
+ /// @param id Endpoint node ID.
37
+ /// @param name Default human-readable endpoint label.
38
+ /// @param descriptor Packed endpoint lane metadata and flags.
39
+ /// @return The published endpoint descriptor.
40
+ function endpoint(uint id, string memory name, uint descriptor) internal returns (uint) {
74
41
  emit Endpoint(host, id, descriptor);
75
- emit Labeled(id, bytes32(0), name);
42
+ label(id, bytes32(0), name);
43
+ return descriptor;
44
+ }
45
+
46
+ /// @notice Finalize an execution output and return its encoded block stream.
47
+ /// @param exec Completed endpoint execution.
48
+ /// @return Encoded output block stream.
49
+ function close(Execution memory exec) internal pure returns (bytes memory) {
50
+ return Executions.finish(exec);
51
+ }
52
+ }
53
+
54
+ /// @title InputEndpointBase
55
+ /// @notice Shared input opening for endpoint families that have only an input lane.
56
+ /// Commands intentionally do not inherit this base because they must open state
57
+ /// and input together through `openCommand`.
58
+ abstract contract InputEndpointBase is EndpointBase {
59
+ /// @notice Open an endpoint input stream with an expected batch count.
60
+ function openInput(
61
+ bytes calldata input,
62
+ uint descriptor,
63
+ uint batches
64
+ ) internal view returns (Execution memory exec) {
65
+ return Executions.openInput(input, descriptor, batches);
76
66
  }
77
67
  }