@rootzero/contracts 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,15 +3,15 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- /// @notice Emitted when an account-scoped commitment is updated.
6
+ /// @notice Emitted when a host-scoped commitment is updated.
7
7
  abstract contract CommitmentEvent is EventEmitter {
8
- string private constant ABI = "event Commitment(bytes32 indexed account, bytes32 key, bytes32 digest, uint status)";
8
+ string private constant ABI = "event Commitment(uint indexed host, bytes32 key, bytes32 digest, uint status)";
9
9
 
10
- /// @param account Account associated with the commitment.
10
+ /// @param host Host node ID that manages the commitment.
11
11
  /// @param key Commitment lookup key.
12
12
  /// @param digest Committed digest. Zero may be used when clearing without revealing the previous digest.
13
13
  /// @param status Commitment status. Zero means cleared; nonzero means committed or application-defined.
14
- event Commitment(bytes32 indexed account, bytes32 key, bytes32 digest, uint status);
14
+ event Commitment(uint indexed host, bytes32 key, bytes32 digest, uint status);
15
15
 
16
16
  constructor() {
17
17
  emit EventAbi(ABI);
@@ -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 a host records an outbound dispatch reference.
7
+ abstract contract DispatchEvent is EventEmitter {
8
+ string private constant ABI = "event Dispatch(uint indexed host, uint chain, uint resources, bytes32 digest, bytes32 ref)";
9
+
10
+ /// @param host Host node ID that owns the dispatch.
11
+ /// @param chain Destination chain/domain node ID.
12
+ /// @param resources Chain-adapter-specific resources assigned to the dispatch.
13
+ /// @param digest Digest of the dispatched payload or canonical envelope.
14
+ /// @param ref Dispatch correlation or recovery reference.
15
+ event Dispatch(uint indexed host, uint chain, uint resources, bytes32 digest, bytes32 ref);
16
+
17
+ constructor() {
18
+ emit EventAbi(ABI);
19
+ }
20
+ }
@@ -0,0 +1,22 @@
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 by hosts to advertise callable peer-facing ports.
7
+ abstract contract PortEvent is EventEmitter {
8
+ string private constant ABI =
9
+ "event Port(uint indexed host, uint id, bytes32 shape, string request, string response, bool funded)";
10
+
11
+ /// @param host Host node ID that exposes the port.
12
+ /// @param id Port node ID.
13
+ /// @param shape Block shape/version descriptor.
14
+ /// @param request Human-readable request schema.
15
+ /// @param response Human-readable response schema.
16
+ /// @param funded True if the port accepts native value.
17
+ event Port(uint indexed host, uint id, bytes32 shape, string request, string response, bool funded);
18
+
19
+ constructor() {
20
+ emit EventAbi(ABI);
21
+ }
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootzero/contracts",
3
- "version": "1.6.0",
3
+ "version": "1.7.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",
@@ -0,0 +1,44 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { PortBase } from "./Base.sol";
5
+ import { AllowAssetsHook } from "../commands/admin/AllowAssets.sol";
6
+ import { Cursors, Cur, Schemas } from "../Cursors.sol";
7
+
8
+ using Cursors for Cur;
9
+
10
+ interface IPortAllowAssets {
11
+ function portAllowAssets(bytes calldata data) external returns (bytes memory);
12
+ }
13
+
14
+ /// @title PortAllowAssets
15
+ /// @notice Port that permits a list of assets on behalf of a peer host.
16
+ /// Each ASSET block in the request calls `allowAsset`. Restricted to trusted peers.
17
+ abstract contract PortAllowAssets is PortBase, AllowAssetsHook, IPortAllowAssets {
18
+ uint internal immutable portAllowAssetsId = portId(this.portAllowAssets.selector);
19
+
20
+ constructor() {
21
+ emit Port(host, portAllowAssetsId, "1:0", Schemas.Asset, "", false);
22
+ emit Labeled(portAllowAssetsId, bytes32(0), "portAllowAssets");
23
+ }
24
+
25
+ /// @notice Execute the allow-assets peer call.
26
+ /// @param data ASSET block stream supplied by the trusted peer.
27
+ /// @return Empty response bytes.
28
+ function portAllowAssets(bytes calldata data) external onlyPeer returns (bytes memory) {
29
+ (Cur memory assets, , ) = Cursors.init(data, 1);
30
+
31
+ while (assets.i < assets.len) {
32
+ bytes32 asset = assets.unpackAsset();
33
+ allowAsset(asset);
34
+ }
35
+
36
+ assets.complete();
37
+ return "";
38
+ }
39
+ }
40
+
41
+
42
+
43
+
44
+
@@ -0,0 +1,41 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {PortBase} from "./Base.sol";
5
+ import {AllowanceHook} from "../commands/admin/Allowance.sol";
6
+ import {Cursors, Cur, Schemas} from "../Cursors.sol";
7
+
8
+ using Cursors for Cur;
9
+
10
+ interface IPortAllowance {
11
+ function portAllowance(bytes calldata data) external returns (bytes memory);
12
+ }
13
+
14
+ /// @title PortAllowance
15
+ /// @notice Port that lets a trusted peer host request or refresh its own allowance.
16
+ /// Each AMOUNT block in the request is scoped to the peer host and passed to the
17
+ /// shared allowance hook as a host-scoped allowance. Restricted to trusted peers.
18
+ abstract contract PortAllowance is PortBase, AllowanceHook, IPortAllowance {
19
+ uint internal immutable portAllowanceId = portId(this.portAllowance.selector);
20
+
21
+ constructor() {
22
+ emit Port(host, portAllowanceId, "1:0", Schemas.Amount, "", false);
23
+ emit Labeled(portAllowanceId, bytes32(0), "portAllowance");
24
+ }
25
+
26
+ /// @notice Execute the allowance port call.
27
+ /// @param data AMOUNT block stream requested by the trusted peer.
28
+ /// @return Empty response bytes.
29
+ function portAllowance(bytes calldata data) external onlyPeer returns (bytes memory) {
30
+ (Cur memory amounts, , ) = Cursors.init(data, 1);
31
+ uint peer = caller();
32
+
33
+ while (amounts.i < amounts.len) {
34
+ (bytes32 asset, uint amount) = amounts.unpackAmount();
35
+ allowance(peer, asset, amount);
36
+ }
37
+
38
+ amounts.complete();
39
+ return "";
40
+ }
41
+ }
package/ports/Base.sol ADDED
@@ -0,0 +1,41 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { NodeCalls } from "../core/Calls.sol";
5
+ import { PortEvent } from "../events/Port.sol";
6
+ import { LabeledEvent } from "../events/Labeled.sol";
7
+ import { Nodes } from "../utils/Nodes.sol";
8
+
9
+ /// @notice ABI-encode a port call from a target port ID and data block stream.
10
+ /// @dev Derives the function selector from `target` via `Nodes.portSelector(target)`.
11
+ /// Reverts if `target` is not a valid port ID.
12
+ /// @param target Destination port node ID embedding the target selector.
13
+ /// @param data Input block stream for the port invocation.
14
+ /// @return ABI-encoded calldata for the port entry point.
15
+ function encodePortCall(uint target, bytes calldata data) pure returns (bytes memory) {
16
+ bytes4 selector = Nodes.portSelector(target);
17
+ return abi.encodeWithSelector(selector, data);
18
+ }
19
+
20
+ /// @title PortBase
21
+ /// @notice Abstract base for peer-facing rootzero ports.
22
+ /// Ports handle inter-host operations between cooperating hosts.
23
+ /// Access is restricted to trusted peer callers via `onlyPeer`.
24
+ abstract contract PortBase is NodeCalls, PortEvent, LabeledEvent {
25
+ /// @dev Thrown when the commander attempts to call a port entrypoint directly.
26
+ error CommanderNotAllowed();
27
+
28
+ /// @dev Restrict execution to trusted callers, excluding the commander.
29
+ modifier onlyPeer() {
30
+ if (msg.sender == commander) revert CommanderNotAllowed();
31
+ enforceCaller(msg.sender);
32
+ _;
33
+ }
34
+
35
+ /// @notice Derive the deterministic node ID for a port selector on this contract.
36
+ /// @param selector Port entrypoint selector.
37
+ /// @return Port node ID.
38
+ function portId(bytes4 selector) internal view returns (uint) {
39
+ return Nodes.toPort(selector, address(this));
40
+ }
41
+ }
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { PortBase } from "./Base.sol";
5
+ import { CreditAccountHook } from "../commands/Credit.sol";
6
+ import { Cursors, Cur, Forms } from "../Cursors.sol";
7
+
8
+ using Cursors for Cur;
9
+
10
+ interface IPortCreditAccount {
11
+ function portCreditAccount(bytes calldata data) external returns (bytes memory);
12
+ }
13
+
14
+ /// @title PortCreditAccount
15
+ /// @notice Port that lets a trusted peer credit supplied accounts directly.
16
+ /// Each ACCOUNT_AMOUNT block calls `creditAccount` for its account.
17
+ abstract contract PortCreditAccount is PortBase, CreditAccountHook, IPortCreditAccount {
18
+ uint internal immutable portCreditAccountId = portId(this.portCreditAccount.selector);
19
+
20
+ constructor() {
21
+ emit Port(host, portCreditAccountId, "1:0", Forms.AccountAmount, "", false);
22
+ emit Labeled(portCreditAccountId, bytes32(0), "portCreditAccount");
23
+ }
24
+
25
+ /// @notice Execute the port-credit call.
26
+ /// @param data ACCOUNT_AMOUNT block stream supplied by the trusted peer.
27
+ /// @return Empty response bytes.
28
+ function portCreditAccount(bytes calldata data) external onlyPeer returns (bytes memory) {
29
+ (Cur memory amounts, , ) = Cursors.init(data, 1);
30
+
31
+ while (amounts.i < amounts.len) {
32
+ (bytes32 account, bytes32 asset, uint amount) = amounts.unpackAccountAmount();
33
+ creditAccount(account, asset, amount);
34
+ }
35
+
36
+ amounts.complete();
37
+ return "";
38
+ }
39
+ }
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { PortBase } from "./Base.sol";
5
+ import { DebitAccountHook } from "../commands/Debit.sol";
6
+ import { Cursors, Cur, Forms } from "../Cursors.sol";
7
+
8
+ using Cursors for Cur;
9
+
10
+ interface IPortDebitAccount {
11
+ function portDebitAccount(bytes calldata data) external returns (bytes memory);
12
+ }
13
+
14
+ /// @title PortDebitAccount
15
+ /// @notice Port that lets a trusted peer debit supplied accounts directly.
16
+ /// Each ACCOUNT_AMOUNT block calls `debitAccount` for its account.
17
+ abstract contract PortDebitAccount is PortBase, DebitAccountHook, IPortDebitAccount {
18
+ uint internal immutable portDebitAccountId = portId(this.portDebitAccount.selector);
19
+
20
+ constructor() {
21
+ emit Port(host, portDebitAccountId, "1:0", Forms.AccountAmount, "", false);
22
+ emit Labeled(portDebitAccountId, bytes32(0), "portDebitAccount");
23
+ }
24
+
25
+ /// @notice Execute the port-debit call.
26
+ /// @param data ACCOUNT_AMOUNT block stream supplied by the trusted peer.
27
+ /// @return Empty response bytes.
28
+ function portDebitAccount(bytes calldata data) external onlyPeer returns (bytes memory) {
29
+ (Cur memory amounts, , ) = Cursors.init(data, 1);
30
+
31
+ while (amounts.i < amounts.len) {
32
+ (bytes32 account, bytes32 asset, uint amount) = amounts.unpackAccountAmount();
33
+ debitAccount(account, asset, amount);
34
+ }
35
+
36
+ amounts.complete();
37
+ return "";
38
+ }
39
+ }
@@ -0,0 +1,44 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {PortBase} from "./Base.sol";
5
+ import {DenyAssetsHook} from "../commands/admin/DenyAssets.sol";
6
+ import {Cursors, Cur, Schemas} from "../Cursors.sol";
7
+
8
+ using Cursors for Cur;
9
+
10
+ interface IPortDenyAssets {
11
+ function portDenyAssets(bytes calldata data) external returns (bytes memory);
12
+ }
13
+
14
+ /// @title PortDenyAssets
15
+ /// @notice Port that blocks a list of assets on behalf of a peer host.
16
+ /// Each ASSET block in the request calls `denyAsset`. Restricted to trusted peers.
17
+ abstract contract PortDenyAssets is PortBase, DenyAssetsHook, IPortDenyAssets {
18
+ uint internal immutable portDenyAssetsId = portId(this.portDenyAssets.selector);
19
+
20
+ constructor() {
21
+ emit Port(host, portDenyAssetsId, "1:0", Schemas.Asset, "", false);
22
+ emit Labeled(portDenyAssetsId, bytes32(0), "portDenyAssets");
23
+ }
24
+
25
+ /// @notice Execute the deny-assets peer call.
26
+ /// @param data ASSET block stream supplied by the trusted peer.
27
+ /// @return Empty response bytes.
28
+ function portDenyAssets(bytes calldata data) external onlyPeer returns (bytes memory) {
29
+ (Cur memory assets, , ) = Cursors.init(data, 1);
30
+
31
+ while (assets.i < assets.len) {
32
+ bytes32 asset = assets.unpackAsset();
33
+ denyAsset(asset);
34
+ }
35
+
36
+ assets.complete();
37
+ return "";
38
+ }
39
+ }
40
+
41
+
42
+
43
+
44
+
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { PeerBase } from "./Base.sol";
4
+ import { PortBase } from "./Base.sol";
5
5
  import { Payable } from "../core/Payable.sol";
6
6
  import { Cursors, Cur, Schemas } from "../Cursors.sol";
7
7
  import { DispatchPayableHook } from "../commands/Relay.sol";
@@ -9,28 +9,28 @@ import { Budget } from "../utils/Value.sol";
9
9
 
10
10
  using Cursors for Cur;
11
11
 
12
- interface IPeerDispatchPayable {
13
- function peerDispatchPayable(bytes calldata request) external payable returns (bytes memory);
12
+ interface IPortDispatchPayable {
13
+ function portDispatchPayable(bytes calldata data) external payable returns (bytes memory);
14
14
  }
15
15
 
16
- /// @title PeerDispatchPayable
17
- /// @notice Peer endpoint that forwards DISPATCH blocks to a host-defined dispatch hook.
18
- abstract contract PeerDispatchPayable is PeerBase, Payable, DispatchPayableHook, IPeerDispatchPayable {
19
- uint internal immutable peerDispatchPayableId = peerId(this.peerDispatchPayable.selector);
16
+ /// @title PortDispatchPayable
17
+ /// @notice Port endpoint that forwards DISPATCH blocks to a host-defined dispatch hook.
18
+ abstract contract PortDispatchPayable is PortBase, Payable, DispatchPayableHook, IPortDispatchPayable {
19
+ uint internal immutable portDispatchPayableId = portId(this.portDispatchPayable.selector);
20
20
 
21
21
  constructor() {
22
- emit Peer(host, peerDispatchPayableId, "1:0", Schemas.Dispatch, "", true);
23
- emit Labeled(peerDispatchPayableId, bytes32(0), "peerDispatchPayable");
22
+ emit Port(host, portDispatchPayableId, "1:0", Schemas.Dispatch, "", true);
23
+ emit Labeled(portDispatchPayableId, bytes32(0), "portDispatchPayable");
24
24
  }
25
25
 
26
26
  /// @notice Forward peer-supplied dispatches to the host-defined dispatch hook.
27
27
  /// @dev Dispatch hooks receive the shared top-level source-chain value
28
28
  /// budget. Any `msg.value` not spent by the hook remains on this host.
29
- /// @param request DISPATCH block stream supplied by the trusted peer.
29
+ /// @param data DISPATCH block stream supplied by the trusted peer.
30
30
  /// @return output Empty response bytes.
31
- function peerDispatchPayable(bytes calldata request) external payable onlyPeer returns (bytes memory output) {
32
- (Cur memory input, , ) = Cursors.init(request, 1);
33
- Budget memory budget = valueBudget();
31
+ function portDispatchPayable(bytes calldata data) external payable onlyPeer returns (bytes memory output) {
32
+ (Cur memory input, , ) = Cursors.init(data, 1);
33
+ Budget memory budget = openValue();
34
34
 
35
35
  while (input.i < input.len) {
36
36
  (uint chain, uint resources, bytes calldata payload) = input.unpackDispatch();
package/ports/Pipe.sol ADDED
@@ -0,0 +1,43 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {PortBase} from "./Base.sol";
5
+ import {Pipeline} from "../core/Pipeline.sol";
6
+ import {Cursors, Cur, Schemas} from "../Cursors.sol";
7
+ import {Budget} from "../utils/Value.sol";
8
+
9
+ using Cursors for Cur;
10
+
11
+ interface IPortPipePayable {
12
+ function portPipePayable(bytes calldata data) external payable returns (bytes memory);
13
+ }
14
+
15
+ /// @title PortPipePayable
16
+ /// @notice Port that consumes CONTEXT blocks and executes each request as a step stream.
17
+ /// Each context's request bytes are passed to the shared pipeline.
18
+ abstract contract PortPipePayable is PortBase, Pipeline, IPortPipePayable {
19
+ uint internal immutable portPipePayableId = portId(this.portPipePayable.selector);
20
+
21
+ constructor() {
22
+ emit Port(host, portPipePayableId, "1:0", Schemas.Context, "", true);
23
+ emit Labeled(portPipePayableId, bytes32(0), "portPipePayable");
24
+ }
25
+
26
+ /// @notice Execute peer-supplied contexts through the shared payable pipe.
27
+ /// @dev All contexts share the peer call's native-value budget. Any unspent
28
+ /// `msg.value` remains on this host.
29
+ /// @param data CONTEXT block stream supplied by the trusted peer.
30
+ /// @return Empty response bytes.
31
+ function portPipePayable(bytes calldata data) external payable onlyPeer returns (bytes memory) {
32
+ (Cur memory input, , ) = Cursors.init(data, 1);
33
+ Budget memory budget = openValue();
34
+
35
+ while (input.i < input.len) {
36
+ (bytes32 account, bytes calldata state, bytes calldata request) = input.unpackContext();
37
+ pipe(account, state, request, budget);
38
+ }
39
+
40
+ input.complete();
41
+ return "";
42
+ }
43
+ }
@@ -1,13 +1,13 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {PeerBase} from "./Base.sol";
4
+ import {PortBase} from "./Base.sol";
5
5
  import {Cursors, Cur, Schemas} from "../Cursors.sol";
6
6
 
7
7
  using Cursors for Cur;
8
8
 
9
- interface IPeerRedeemBalance {
10
- function peerRedeemBalance(bytes calldata request) external returns (bytes memory);
9
+ interface IPortRedeemBalance {
10
+ function portRedeemBalance(bytes calldata data) external returns (bytes memory);
11
11
  }
12
12
 
13
13
  abstract contract RedeemBalanceHook {
@@ -18,23 +18,23 @@ abstract contract RedeemBalanceHook {
18
18
  function redeemBalance(uint peer, bytes32 asset, uint amount) internal virtual;
19
19
  }
20
20
 
21
- /// @title PeerRedeemBalance
22
- /// @notice Peer that redeems balance state from a peer host into local assets.
21
+ /// @title PortRedeemBalance
22
+ /// @notice Port that redeems balance state from a peer host into local assets.
23
23
  /// Each BALANCE block in the request calls `redeemBalance(peer, asset, amount)`.
24
24
  /// Restricted to trusted peers.
25
- abstract contract PeerRedeemBalance is PeerBase, RedeemBalanceHook, IPeerRedeemBalance {
26
- uint internal immutable peerRedeemBalanceId = peerId(this.peerRedeemBalance.selector);
25
+ abstract contract PortRedeemBalance is PortBase, RedeemBalanceHook, IPortRedeemBalance {
26
+ uint internal immutable portRedeemBalanceId = portId(this.portRedeemBalance.selector);
27
27
 
28
28
  constructor() {
29
- emit Peer(host, peerRedeemBalanceId, "1:0", Schemas.Balance, "", false);
30
- emit Labeled(peerRedeemBalanceId, bytes32(0), "peerRedeemBalance");
29
+ emit Port(host, portRedeemBalanceId, "1:0", Schemas.Balance, "", false);
30
+ emit Labeled(portRedeemBalanceId, bytes32(0), "portRedeemBalance");
31
31
  }
32
32
 
33
- /// @notice Execute the balance redemption peer call.
34
- /// @param request BALANCE block stream supplied by the trusted peer.
33
+ /// @notice Execute the balance redemption port call.
34
+ /// @param data BALANCE block stream supplied by the trusted peer.
35
35
  /// @return Empty response bytes.
36
- function peerRedeemBalance(bytes calldata request) external onlyPeer returns (bytes memory) {
37
- (Cur memory input, , ) = Cursors.init(request, 1);
36
+ function portRedeemBalance(bytes calldata data) external onlyPeer returns (bytes memory) {
37
+ (Cur memory input, , ) = Cursors.init(data, 1);
38
38
  uint peer = caller();
39
39
 
40
40
  while (input.i < input.len) {
@@ -0,0 +1,41 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { PortBase } from "./Base.sol";
5
+ import { CreditAccountHook } from "../commands/Credit.sol";
6
+ import { DebitAccountHook } from "../commands/Debit.sol";
7
+ import { Cursors, Cur, Schemas } from "../Cursors.sol";
8
+
9
+ using Cursors for Cur;
10
+
11
+ interface IPortSettle {
12
+ function portSettle(bytes calldata data) external returns (bytes memory);
13
+ }
14
+
15
+ /// @title PortSettle
16
+ /// @notice Port that consumes peer-supplied TRANSACTION blocks through debit and credit hooks.
17
+ /// Each TRANSACTION block calls `debitAccount` for `from` and `creditAccount` for `to`.
18
+ abstract contract PortSettle is PortBase, DebitAccountHook, CreditAccountHook, IPortSettle {
19
+ uint internal immutable portSettleId = portId(this.portSettle.selector);
20
+
21
+ constructor() {
22
+ emit Port(host, portSettleId, "1:0", Schemas.Transaction, "", false);
23
+ emit Labeled(portSettleId, bytes32(0), "portSettle");
24
+ }
25
+
26
+ /// @notice Execute the port-settle call.
27
+ /// @param data TRANSACTION block stream supplied by the trusted peer.
28
+ /// @return Empty response bytes.
29
+ function portSettle(bytes calldata data) external onlyPeer returns (bytes memory) {
30
+ (Cur memory state, , ) = Cursors.init(data, 1);
31
+
32
+ while (state.i < state.len) {
33
+ (bytes32 from, bytes32 to, bytes32 asset, uint amount) = state.unpackTransaction();
34
+ if (from != 0) debitAccount(from, asset, amount);
35
+ if (to != 0) creditAccount(to, asset, amount);
36
+ }
37
+
38
+ state.complete();
39
+ return "";
40
+ }
41
+ }
package/utils/Layout.sol CHANGED
@@ -29,7 +29,7 @@ library Layout {
29
29
 
30
30
  /// @dev ID encodes an account.
31
31
  uint8 constant Account = 0x01;
32
- /// @dev ID encodes a network node (host, command, or peer).
32
+ /// @dev ID encodes a network node (host, command, port, query, or guard).
33
33
  uint8 constant Node = 0x02;
34
34
  /// @dev ID encodes an asset.
35
35
  uint8 constant Asset = 0x03;
@@ -54,8 +54,8 @@ library Layout {
54
54
  uint8 constant Host = 0x02;
55
55
  /// @dev Node is a command contract.
56
56
  uint8 constant Command = 0x03;
57
- /// @dev Node is a peer contract.
58
- uint8 constant Peer = 0x04;
57
+ /// @dev Node is a port callable by trusted peer hosts.
58
+ uint8 constant Port = 0x04;
59
59
  /// @dev Node is a query contract.
60
60
  uint8 constant Query = 0x05;
61
61
  /// @dev Node is a guardian-only direct action.
package/utils/Nodes.sol CHANGED
@@ -9,9 +9,9 @@ import {ensureAddr, isFamily, matchesBase, toLocalBase} from "./Utils.sol";
9
9
  /// @notice Encoding and decoding helpers for 256-bit node identifiers.
10
10
  ///
11
11
  /// Node IDs share a common layout:
12
- /// - bits [255:224] — 4-byte type prefix (`Host`, `Command`, or `Peer`)
12
+ /// - bits [255:224] — 4-byte type prefix (`Host`, `Command`, `Port`, etc.)
13
13
  /// - bits [223:192] — current `block.chainid` (makes IDs chain-local)
14
- /// - bits [191:160] — 4-byte ABI selector (commands and peers only)
14
+ /// - bits [191:160] — 4-byte ABI selector (commands, ports, queries, and guards)
15
15
  /// - bits [159:0] — 160-bit EVM contract address
16
16
  ///
17
17
  /// If the first byte is zero, the node is an opaque
@@ -31,8 +31,8 @@ library Nodes {
31
31
  uint32 constant Host = (uint32(Layout.Evm) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Host);
32
32
  /// @dev Full 4-byte type prefix for command nodes.
33
33
  uint32 constant Command = (uint32(Layout.Evm) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Command);
34
- /// @dev Full 4-byte type prefix for peer nodes.
35
- uint32 constant Peer = (uint32(Layout.Evm) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Peer);
34
+ /// @dev Full 4-byte type prefix for port nodes.
35
+ uint32 constant Port = (uint32(Layout.Evm) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Port);
36
36
  /// @dev Full 4-byte type prefix for query nodes.
37
37
  uint32 constant Query = (uint32(Layout.Evm) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Query);
38
38
  /// @dev Full 4-byte type prefix for guard action nodes.
@@ -48,9 +48,9 @@ library Nodes {
48
48
  return uint32(node >> 224) == Command;
49
49
  }
50
50
 
51
- /// @notice Return true if `node` is a peer node ID.
52
- function isPeer(uint node) internal pure returns (bool) {
53
- return uint32(node >> 224) == Peer;
51
+ /// @notice Return true if `node` is a port node ID.
52
+ function isPort(uint node) internal pure returns (bool) {
53
+ return uint32(node >> 224) == Port;
54
54
  }
55
55
 
56
56
  /// @notice Return true if `node` is a query node ID.
@@ -94,11 +94,11 @@ library Nodes {
94
94
  return value;
95
95
  }
96
96
 
97
- /// @notice Assert that `value` is a peer node ID and return it as a node.
97
+ /// @notice Assert that `value` is a port node ID and return it as a node.
98
98
  /// @param value Value to validate.
99
- /// @return node The same `value` if it is a peer node.
100
- function peer(uint value) internal pure returns (uint node) {
101
- if (!isPeer(value)) revert InvalidId();
99
+ /// @return node The same `value` if it is a port node.
100
+ function port(uint value) internal pure returns (uint node) {
101
+ if (!isPort(value)) revert InvalidId();
102
102
  return value;
103
103
  }
104
104
 
@@ -149,11 +149,11 @@ library Nodes {
149
149
  return bytes4(uint32(command(node) >> 160));
150
150
  }
151
151
 
152
- /// @notice Assert that `node` is a peer ID and return its embedded ABI selector.
152
+ /// @notice Assert that `node` is a port ID and return its embedded ABI selector.
153
153
  /// @param node Node ID to validate.
154
- /// @return selector 4-byte peer selector stored in bits [191:160].
155
- function peerSelector(uint node) internal pure returns (bytes4 selector) {
156
- return bytes4(uint32(peer(node) >> 160));
154
+ /// @return selector 4-byte port selector stored in bits [191:160].
155
+ function portSelector(uint node) internal pure returns (bytes4 selector) {
156
+ return bytes4(uint32(port(node) >> 160));
157
157
  }
158
158
 
159
159
  /// @notice Assert that `node` is a query ID and return its embedded ABI selector.
@@ -201,12 +201,12 @@ library Nodes {
201
201
  node |= uint(uint32(selector)) << 160;
202
202
  }
203
203
 
204
- /// @notice Build a chain-local peer ID for the given selector and contract.
205
- /// @param selector 4-byte ABI selector of the peer entry point.
206
- /// @param target Peer contract address.
207
- /// @return node Peer node ID embedding both the selector and address.
208
- function toPeer(bytes4 selector, address target) internal view returns (uint node) {
209
- node = toLocalBase(Peer) | uint(uint160(target));
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.
206
+ /// @param target Port contract address.
207
+ /// @return node Port node ID embedding both the selector and address.
208
+ function toPort(bytes4 selector, address target) internal view returns (uint node) {
209
+ node = toLocalBase(Port) | uint(uint160(target));
210
210
  node |= uint(uint32(selector)) << 160;
211
211
  }
212
212
 
package/utils/Value.sol CHANGED
@@ -18,19 +18,26 @@ library Values {
18
18
  /// @param budget Mutable budget to deduct from.
19
19
  /// @param amount Native value to spend in wei.
20
20
  /// @return The same `amount`, ready to forward to a callee.
21
- function use(Budget memory budget, uint128 amount) internal pure returns (uint128) {
22
- uint value = uint(amount);
23
- if (value > budget.remaining) revert InsufficientValue();
24
- budget.remaining -= value;
21
+ function use(Budget memory budget, uint amount) internal pure returns (uint) {
22
+ if (amount > budget.remaining) revert InsufficientValue();
23
+ budget.remaining -= amount;
25
24
  return amount;
26
25
  }
27
26
 
27
+ /// @notice Drain the remaining native value from `budget` and return it.
28
+ /// @param budget Mutable budget to drain.
29
+ /// @return value Native value removed from the budget, in wei.
30
+ function drain(Budget memory budget) internal pure returns (uint value) {
31
+ value = budget.remaining;
32
+ budget.remaining = 0;
33
+ }
34
+
28
35
  /// @notice Deduct `amount` from the budget and return it as a new sub-budget.
29
36
  /// Reverts if `amount` exceeds `budget.remaining`.
30
37
  /// @param budget Mutable parent budget to deduct from.
31
38
  /// @param amount Native value to assign to the sub-budget, in wei.
32
39
  /// @return A new budget with `amount` remaining.
33
- function allocate(Budget memory budget, uint128 amount) internal pure returns (Budget memory) {
40
+ function allocate(Budget memory budget, uint amount) internal pure returns (Budget memory) {
34
41
  return Budget({remaining: use(budget, amount)});
35
42
  }
36
43
  }