@rootzero/contracts 1.19.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,45 @@
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.20.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - `Nodes.toCommand`, `toPort`, `toQuery`, and `toGuard` now take an endpoint
11
+ name instead of a precomputed selector. The `Selectors` library was removed;
12
+ endpoint node IDs now derive their canonical selectors internally.
13
+ - Renamed the memory-backed pipeline adapters from `InternalDebitAccount`,
14
+ `InternalCreditAccount`, and `InternalSettle` to `DebitAccountInternal`,
15
+ `CreditAccountInternal`, and `SettleInternal`.
16
+ - Replaced `RelayPayableHook.relayTo(portal, resources, payload, funds)` with
17
+ `relay(portal, resources, account, state, input, funds)`. Relay commands now
18
+ pass their semantic context fields to the host instead of encoding a
19
+ `CONTEXT` payload before invoking the hook.
20
+ - `DispatchPayablePort` now uses the dedicated
21
+ `DispatchPayableHook.dispatchTo(portal, resources, payload, funds)` hook
22
+ instead of sharing `RelayPayableHook`.
23
+
24
+ ### Added
25
+
26
+ - Added `RelayEvent`, with account, portal, resources, correlation key, and
27
+ digest fields for recording outbound relay references.
28
+
29
+ ### Changed
30
+
31
+ - Relay hooks retain state and nested relay input as calldata until an
32
+ implementation chooses to encode or otherwise consume the destination
33
+ context.
34
+
35
+ ### Upgrade Compatibility
36
+
37
+ - Pass endpoint names directly to the `Nodes.to*` helpers and remove imports of
38
+ `Selectors`.
39
+ - Update inherited internal adapter names and imports to the new postfix
40
+ convention.
41
+ - Implement the structured `RelayPayableHook.relay` hook for relay commands and
42
+ `DispatchPayableHook.dispatchTo` for opaque dispatch payloads. Hosts that
43
+ support both surfaces must implement both hooks.
44
+
6
45
  ## 1.19.0
7
46
 
8
47
  ### Breaking Changes
package/Endpoints.sol CHANGED
@@ -11,15 +11,15 @@ import {CreditAccountHook, DebitAccountHook, PostHook, RepayHook, SettleHook} fr
11
11
  import {CommandBase} from "./commands/Base.sol";
12
12
  import {Allocate, AllocateHook} from "./commands/Allocate.sol";
13
13
  import {Burn, BurnHook} from "./commands/Burn.sol";
14
- import {CreditAccount, InternalCreditAccount} from "./commands/Credit.sol";
15
- import {DebitAccount, InternalDebitAccount} from "./commands/Debit.sol";
14
+ import {CreditAccount, CreditAccountInternal} from "./commands/Credit.sol";
15
+ import {DebitAccount, DebitAccountInternal} from "./commands/Debit.sol";
16
16
  import {Deposit, DepositHook, DepositPayable, DepositPayableHook} from "./commands/Deposit.sol";
17
17
  import {Payout, PayoutHook} from "./commands/Payout.sol";
18
18
  import {Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook} from "./commands/Provision.sol";
19
19
  import {RecoverPayable, RecoverPayableHook} from "./commands/Recover.sol";
20
20
  import {Repay, RepayPayable, RepayPayableHook} from "./commands/Repay.sol";
21
21
  import {RelayPayable, RelayBalancePayable, RelayPayableHook} from "./commands/Relay.sol";
22
- import {Settle, SettlePayable, SettlePayableHook, InternalSettle} from "./commands/Settle.sol";
22
+ import {Settle, SettlePayable, SettlePayableHook, SettleInternal} from "./commands/Settle.sol";
23
23
  import {Withdraw, WithdrawHook} from "./commands/Withdraw.sol";
24
24
 
25
25
  // Admin commands
@@ -43,7 +43,7 @@ import {CreditAccountPort} from "./ports/Credit.sol";
43
43
  import {DebitAccountPort} from "./ports/Debit.sol";
44
44
  import {DenyAssetsPort} from "./ports/DenyAssets.sol";
45
45
  import {PipePayablePort} from "./ports/Pipe.sol";
46
- import {DispatchPayablePort} from "./ports/Dispatch.sol";
46
+ import {DispatchPayablePort, DispatchPayableHook} from "./ports/Dispatch.sol";
47
47
  import {PostPort} from "./ports/Post.sol";
48
48
 
49
49
  // Guard endpoints
package/Events.sol CHANGED
@@ -13,6 +13,7 @@ import { DispatchEvent } from "./events/Dispatch.sol";
13
13
  import { EndpointEvent } from "./events/Endpoint.sol";
14
14
  import { ReceivedEvent } from "./events/Received.sol";
15
15
  import { RecoveredEvent } from "./events/Recovered.sol";
16
+ import { RelayEvent } from "./events/Relay.sol";
16
17
  import { EventEmitter } from "./events/Emitter.sol";
17
18
  import { GuardianEvent } from "./events/Guardian.sol";
18
19
  import { IntroductionEvent } from "./events/Introduction.sol";
package/README.md CHANGED
@@ -378,8 +378,8 @@ command batching — and `resources` is a chain-specific word interpreted by the
378
378
  portal adapter (on EVM, the low 128 bits are native value in wei, drawn from a
379
379
  shared budget), so the same pipeline bytes are meaningful to every port.
380
380
 
381
- Hosts that implement a pipeline locally can inherit `InternalDebitAccount`,
382
- `InternalCreditAccount`, and `InternalSettle` to advertise the canonical command
381
+ Hosts that implement a pipeline locally can inherit `DebitAccountInternal`,
382
+ `CreditAccountInternal`, and `SettleInternal` to advertise the canonical command
383
383
  endpoints while routing their local command IDs through `executeDebitAccount`,
384
384
  `executeCreditAccount`, and `executeSettle`. These adapters consume the
385
385
  memory-backed pipeline state directly and avoid an external self-call. Pass the
package/Utils.sol CHANGED
@@ -11,7 +11,6 @@ import { Amounts, Assets } from "./utils/Assets.sol";
11
11
  import { ECDSA } from "./utils/ECDSA.sol";
12
12
  import { Ids } from "./utils/Ids.sol";
13
13
  import { Nodes } from "./utils/Nodes.sol";
14
- import { Selectors } from "./utils/Selectors.sol";
15
14
  import { Layout } from "./utils/Layout.sol";
16
15
  import { addrOr, applyBps, beforeBps, bytes32ToInt, bytes32ToString, clear8, clear16, clear32, clear64, divisible, ensureAddr, hash32, intToBytes32, isFamily, matchesBase, MAX_BPS, max8, max16, max24, max32, max40, max64, max96, max128, max160, NotDivisible, replace8, replace16, replace32, replace64, retryTicket, toLocalBase, toUnspecifiedBase, ValueOverflow, ZeroAddress } from "./utils/Utils.sol";
17
16
 
package/commands/Base.sol CHANGED
@@ -11,7 +11,6 @@ import {ReceivedEvent} from "../events/Received.sol";
11
11
  import {Actions} from "../utils/Actions.sol";
12
12
  import {Descriptors} from "../codec/Descriptors.sol";
13
13
  import {Nodes} from "../utils/Nodes.sol";
14
- import {Selectors} from "../utils/Selectors.sol";
15
14
  import {Cursors} from "../utils/Cursors.sol";
16
15
 
17
16
  using Executions for Execution;
@@ -72,7 +71,7 @@ abstract contract CommandBase is CallerAccess, EndpointBase, ReceivedEvent {
72
71
  /// @return id Command node ID.
73
72
  /// @return published Published endpoint descriptor.
74
73
  function command(string memory name, uint descriptor) internal returns (uint id, uint published) {
75
- id = Nodes.toCommand(Selectors.command(name), address(this));
74
+ id = Nodes.toCommand(name, address(this));
76
75
  published = endpoint(id, name, descriptor);
77
76
  }
78
77
 
@@ -45,11 +45,11 @@ abstract contract CreditAccount is CommandBase, CreditAccountHook {
45
45
  }
46
46
  }
47
47
 
48
- /// @title InternalCreditAccount
48
+ /// @title CreditAccountInternal
49
49
  /// @notice Extends the advertised credit-account command with memory-state pipeline dispatch.
50
50
  /// @dev This adapter is not a separate command. It uses the command ID and account hook
51
51
  /// inherited from `CreditAccount` while accepting the state location used by `Pipeline`.
52
- abstract contract InternalCreditAccount is CreditAccount {
52
+ abstract contract CreditAccountInternal is CreditAccount {
53
53
  /// @notice Execute the inherited credit-account command from an internal pipeline.
54
54
  /// @param account Account credited by each balance.
55
55
  /// @param state BALANCE block stream held in pipeline memory.
@@ -49,11 +49,11 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
49
49
  }
50
50
  }
51
51
 
52
- /// @title InternalDebitAccount
52
+ /// @title DebitAccountInternal
53
53
  /// @notice Extends the advertised debit-account command with memory-state pipeline dispatch.
54
54
  /// @dev This adapter is not a separate command. It uses the command ID and account hook
55
55
  /// inherited from `DebitAccount` while accepting the state location used by `Pipeline`.
56
- abstract contract InternalDebitAccount is DebitAccount {
56
+ abstract contract DebitAccountInternal is DebitAccount {
57
57
  /// @notice Execute the inherited debit-account command from an internal pipeline.
58
58
  /// @param account Account whose funds are debited.
59
59
  /// @param state Empty pipeline state required by the command schema.
@@ -1,20 +1,29 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {Blocks, Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
4
+ import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
5
5
 
6
6
  using Executions for Execution;
7
7
 
8
- /// @notice Hook implemented by hosts that forward funded relay payloads.
8
+ /// @notice Hook implemented by hosts that relay command contexts.
9
9
  abstract contract RelayPayableHook {
10
- /// @notice Override to relay an encoded payload to `portal`.
10
+ /// @notice Override to relay a command context to `portal`.
11
11
  /// @param portal Destination portal identifier, often the destination host ID.
12
12
  /// @param resources Chain-specific destination resources. EVM adapters
13
13
  /// may interpret this as packed execution gas and destination value.
14
- /// @param payload Encoded payload ready for the transport layer.
14
+ /// @param account Destination command account.
15
+ /// @param state State forwarded into the destination context.
16
+ /// @param input Input forwarded into the destination context.
15
17
  /// @param funds Execution used for source value available for transport fees
16
18
  /// and destination resource funding.
17
- function relayTo(uint portal, uint resources, bytes memory payload, Execution memory funds) internal virtual;
19
+ function relay(
20
+ uint portal,
21
+ uint resources,
22
+ bytes32 account,
23
+ bytes calldata state,
24
+ bytes calldata input,
25
+ Execution memory funds
26
+ ) internal virtual;
18
27
  }
19
28
 
20
29
  /// @title RelayPayable
@@ -33,10 +42,8 @@ abstract contract RelayPayable is CommandBase, RelayPayableHook {
33
42
  bytes calldata input
34
43
  ) external payable onlyCommand returns (bytes memory, bytes memory) {
35
44
  Execution memory exec = openCommand(state, input, descriptor, 1);
36
- (uint portal, uint resources, bytes calldata payload) = exec.unpackRelay(Lanes.Input);
37
- bytes memory context = Blocks.contextCopy(account, state, payload);
38
-
39
- relayTo(portal, resources, context, exec);
45
+ (uint portal, uint resources, bytes calldata relayInput) = exec.unpackRelay(Lanes.Input);
46
+ relay(portal, resources, account, state, relayInput, exec);
40
47
 
41
48
  return close(exec, account);
42
49
  }
@@ -65,10 +72,8 @@ abstract contract RelayBalancePayable is CommandBase, RelayPayableHook {
65
72
  bytes calldata input
66
73
  ) external payable onlyCommand returns (bytes memory, bytes memory) {
67
74
  Execution memory exec = openCommand(state, input, descriptor, 1);
68
- (uint portal, uint resources, bytes calldata payload) = exec.unpackRelay(Lanes.Input);
69
- bytes memory context = Blocks.contextCopy(account, state, payload);
70
-
71
- relayTo(portal, resources, context, exec);
75
+ (uint portal, uint resources, bytes calldata relayInput) = exec.unpackRelay(Lanes.Input);
76
+ relay(portal, resources, account, state, relayInput, exec);
72
77
 
73
78
  return close(exec, account);
74
79
  }
@@ -97,11 +97,11 @@ abstract contract SettlePayable is CommandBase, SettlePayableHook, Action {
97
97
  }
98
98
  }
99
99
 
100
- /// @title InternalSettle
100
+ /// @title SettleInternal
101
101
  /// @notice Extends the advertised settle command with memory-state pipeline dispatch.
102
102
  /// @dev This adapter is not a separate command. It uses the command ID and settlement hook
103
103
  /// inherited from `Settle` while accepting the state location used by `Pipeline`.
104
- abstract contract InternalSettle is Settle {
104
+ abstract contract SettleInternal is Settle {
105
105
  /// @notice Execute the inherited settle command from an internal pipeline.
106
106
  /// @param account Account for which each position is settled.
107
107
  /// @param state POSITION block stream held in pipeline memory.
@@ -0,0 +1,20 @@
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 when an account records an outbound relay reference.
7
+ abstract contract RelayEvent is EventEmitter {
8
+ string private constant ABI = "event Relay(bytes32 indexed account, uint portal, uint resources, bytes32 key, bytes32 digest)";
9
+
10
+ /// @param account Account that owns the relayed context.
11
+ /// @param portal Destination portal identifier, often the destination host ID.
12
+ /// @param resources Chain-specific resources assigned to the relay.
13
+ /// @param key Relay correlation or recovery lookup key.
14
+ /// @param digest Digest of the relayed payload or canonical envelope.
15
+ event Relay(bytes32 indexed account, uint portal, uint resources, bytes32 key, bytes32 digest);
16
+
17
+ constructor() {
18
+ emit EventAbi(ABI);
19
+ }
20
+ }
package/guards/Base.sol CHANGED
@@ -5,7 +5,6 @@ import {InputEndpointBase} from "../core/Endpoint.sol";
5
5
  import {GuardianAccess} from "../core/Access.sol";
6
6
  import {Specs} from "../codec/Specs.sol";
7
7
  import {Nodes} from "../utils/Nodes.sol";
8
- import {Selectors} from "../utils/Selectors.sol";
9
8
 
10
9
  /// @title GuardBase
11
10
  /// @notice Abstract base for guardian-only direct host actions.
@@ -27,7 +26,7 @@ abstract contract GuardBase is GuardianAccess, InputEndpointBase {
27
26
  string memory name,
28
27
  uint input
29
28
  ) internal returns (uint id, uint descriptor) {
30
- id = Nodes.toGuard(Selectors.guard(name), address(this));
29
+ id = Nodes.toGuard(name, address(this));
31
30
  descriptor = endpoint(id, name, Specs.Empty, input, Specs.Empty, 0, 0);
32
31
  }
33
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootzero/contracts",
3
- "version": "1.19.0",
3
+ "version": "1.20.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",
package/ports/Base.sol CHANGED
@@ -6,7 +6,6 @@ import { NodeAccess } from "../core/Access.sol";
6
6
  import { Specs } from "../codec/Specs.sol";
7
7
  import { InputEndpointBase } from "../core/Endpoint.sol";
8
8
  import { Nodes } from "../utils/Nodes.sol";
9
- import { Selectors } from "../utils/Selectors.sol";
10
9
  import { Descriptors } from "../codec/Descriptors.sol";
11
10
 
12
11
  /// @title PortBase
@@ -56,7 +55,7 @@ abstract contract PortBase is NodeCalls, NodeAccess, InputEndpointBase {
56
55
  string memory name,
57
56
  uint descriptor
58
57
  ) internal returns (uint id, uint published) {
59
- id = Nodes.toPort(Selectors.port(name), address(this));
58
+ id = Nodes.toPort(name, address(this));
60
59
  published = endpoint(id, name, descriptor);
61
60
  }
62
61
  }
@@ -2,23 +2,34 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {PortBase} from "./Base.sol";
5
- import {RelayPayableHook} from "../commands/Relay.sol";
6
5
  import {Specs} from "../Codec.sol";
7
6
  import {Execution, Executions, Lanes} from "../execution/Execution.sol";
8
7
 
9
8
  using Executions for Execution;
10
9
 
10
+ /// @notice Hook implemented by hosts that forward funded dispatch payloads.
11
+ abstract contract DispatchPayableHook {
12
+ /// @notice Override to dispatch an encoded payload to `portal`.
13
+ /// @param portal Destination portal identifier, often the destination host ID.
14
+ /// @param resources Chain-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 funds Execution used for source value available for transport fees
18
+ /// and destination resource funding.
19
+ function dispatchTo(uint portal, uint resources, bytes memory payload, Execution memory funds) internal virtual;
20
+ }
21
+
11
22
  /// @title DispatchPayablePort
12
- /// @notice Port endpoint that forwards DISPATCH blocks to a host-defined relay hook.
13
- abstract contract DispatchPayablePort is PortBase, RelayPayableHook {
23
+ /// @notice Port endpoint that forwards DISPATCH blocks to a host-defined dispatch hook.
24
+ abstract contract DispatchPayablePort is PortBase, DispatchPayableHook {
14
25
  uint private immutable descriptor;
15
26
 
16
27
  constructor() {
17
28
  (, descriptor) = port("portDispatchPayable", Specs.Dispatch, Specs.Empty, true);
18
29
  }
19
30
 
20
- /// @notice Forward peer-supplied dispatches to the host-defined relay hook.
21
- /// @dev Relay hooks receive the shared top-level source value
31
+ /// @notice Forward peer-supplied dispatches to the host-defined dispatch hook.
32
+ /// @dev Dispatch hooks receive the shared top-level source value
22
33
  /// budget. Any `msg.value` not spent by the hook remains on this host.
23
34
  /// @param data DISPATCH block stream supplied by the trusted peer.
24
35
  /// @return Empty response bytes.
@@ -27,7 +38,7 @@ abstract contract DispatchPayablePort is PortBase, RelayPayableHook {
27
38
 
28
39
  while (exec.more()) {
29
40
  (uint portal, uint resources, bytes calldata payload) = exec.unpackDispatch(Lanes.Input);
30
- relayTo(portal, resources, payload, exec);
41
+ dispatchTo(portal, resources, payload, exec);
31
42
  }
32
43
 
33
44
  return "";
package/queries/Base.sol CHANGED
@@ -5,7 +5,6 @@ import { InputEndpointBase } from "../core/Endpoint.sol";
5
5
  import { Descriptors } from "../codec/Descriptors.sol";
6
6
  import { Specs } from "../codec/Specs.sol";
7
7
  import { Nodes } from "../utils/Nodes.sol";
8
- import { Selectors } from "../utils/Selectors.sol";
9
8
 
10
9
  /// @title QueryBase
11
10
  /// @notice Abstract base for rootzero query contracts.
@@ -39,7 +38,7 @@ abstract contract QueryBase is InputEndpointBase {
39
38
  string memory name,
40
39
  uint descriptor
41
40
  ) internal returns (uint id, uint published) {
42
- id = Nodes.toQuery(Selectors.query(name), address(this));
41
+ id = Nodes.toQuery(name, address(this));
43
42
  published = endpoint(id, name, descriptor);
44
43
  }
45
44
  }
package/utils/Nodes.sol CHANGED
@@ -192,40 +192,45 @@ library Nodes {
192
192
  return toLocalBase(Host) | uint(uint160(target));
193
193
  }
194
194
 
195
- /// @notice Build a chain-local command ID for the given selector and contract.
196
- /// @param selector 4-byte ABI selector of the command entry point.
195
+ /// @notice Build a chain-local command ID for the given endpoint name and contract.
196
+ /// @param name Command function name.
197
197
  /// @param target Command contract address.
198
198
  /// @return node Command node ID embedding both the selector and address.
199
- function toCommand(bytes4 selector, address target) internal view returns (uint node) {
199
+ function toCommand(string memory name, address target) internal view returns (uint node) {
200
200
  node = toLocalBase(Command) | uint(uint160(target));
201
- node |= uint(uint32(selector)) << 160;
201
+ node |= uint(uint32(toSelector(name, "(bytes32,bytes,bytes)"))) << 160;
202
202
  }
203
203
 
204
- /// @notice Build a chain-local port ID for the given selector and contract.
205
- /// @param selector 4-byte ABI selector of the port entry point.
204
+ /// @notice Build a chain-local port ID for the given endpoint name and contract.
205
+ /// @param name Port function name.
206
206
  /// @param target Port contract address.
207
207
  /// @return node Port node ID embedding both the selector and address.
208
- function toPort(bytes4 selector, address target) internal view returns (uint node) {
208
+ function toPort(string memory name, address target) internal view returns (uint node) {
209
209
  node = toLocalBase(Port) | uint(uint160(target));
210
- node |= uint(uint32(selector)) << 160;
210
+ node |= uint(uint32(toSelector(name, "(bytes)"))) << 160;
211
211
  }
212
212
 
213
- /// @notice Build a chain-local query ID for the given selector and contract.
214
- /// @param selector 4-byte ABI selector of the query entry point.
213
+ /// @notice Build a chain-local query ID for the given endpoint name and contract.
214
+ /// @param name Query function name.
215
215
  /// @param target Query contract address.
216
216
  /// @return node Query node ID embedding both the selector and address.
217
- function toQuery(bytes4 selector, address target) internal view returns (uint node) {
217
+ function toQuery(string memory name, address target) internal view returns (uint node) {
218
218
  node = toLocalBase(Query) | uint(uint160(target));
219
- node |= uint(uint32(selector)) << 160;
219
+ node |= uint(uint32(toSelector(name, "(bytes)"))) << 160;
220
220
  }
221
221
 
222
- /// @notice Build a chain-local guard action ID for the given selector and contract.
223
- /// @param selector 4-byte ABI selector of the guard action entry point.
222
+ /// @notice Build a chain-local guard action ID for the given endpoint name and contract.
223
+ /// @param name Guard action function name.
224
224
  /// @param target Guard action contract address.
225
225
  /// @return node Guard action node ID embedding both the selector and address.
226
- function toGuard(bytes4 selector, address target) internal view returns (uint node) {
226
+ function toGuard(string memory name, address target) internal view returns (uint node) {
227
227
  node = toLocalBase(Guard) | uint(uint160(target));
228
- node |= uint(uint32(selector)) << 160;
228
+ node |= uint(uint32(toSelector(name, "(bytes)"))) << 160;
229
+ }
230
+
231
+ /// @dev Derive an ABI selector from an endpoint name and argument signature.
232
+ function toSelector(string memory name, string memory args) private pure returns (bytes4) {
233
+ return bytes4(keccak256(bytes(string.concat(name, args))));
229
234
  }
230
235
 
231
236
  /// @notice Derive an opaque node ID from a keccak preimage.
@@ -1,49 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- /// @title Selectors
5
- /// @notice Canonical ABI selector derivation for rootzero endpoint types.
6
- library Selectors {
7
- /// @notice Derive the ABI selector for a command entrypoint.
8
- /// @param name Command function name.
9
- /// @return Selector for `name(bytes32,bytes,bytes)`.
10
- function command(string memory name) internal pure returns (bytes4) {
11
- return derive(name, "(bytes32,bytes,bytes)");
12
- }
13
-
14
- /// @notice Derive the ABI selector for a port entrypoint.
15
- /// @param name Port function name.
16
- /// @return Selector for `name(bytes)`.
17
- function port(string memory name) internal pure returns (bytes4) {
18
- return direct(name);
19
- }
20
-
21
- /// @notice Derive the ABI selector for a query entrypoint.
22
- /// @param name Query function name.
23
- /// @return Selector for `name(bytes)`.
24
- function query(string memory name) internal pure returns (bytes4) {
25
- return direct(name);
26
- }
27
-
28
- /// @notice Derive the ABI selector for a guard action entrypoint.
29
- /// @param name Guard action function name.
30
- /// @return Selector for `name(bytes)`.
31
- function guard(string memory name) internal pure returns (bytes4) {
32
- return direct(name);
33
- }
34
-
35
- /// @dev Derive a direct endpoint selector with a single `bytes` argument.
36
- /// @param name Endpoint function name.
37
- /// @return Selector for `name(bytes)`.
38
- function direct(string memory name) private pure returns (bytes4) {
39
- return derive(name, "(bytes)");
40
- }
41
-
42
- /// @dev Derive an ABI selector from a function name and argument signature suffix.
43
- /// @param name Function name.
44
- /// @param args Parenthesized ABI argument signature.
45
- /// @return First four bytes of the function signature hash.
46
- function derive(string memory name, string memory args) private pure returns (bytes4) {
47
- return bytes4(keccak256(bytes(string.concat(name, args))));
48
- }
49
- }