@rootzero/contracts 0.9.4 → 0.9.6

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/Core.sol CHANGED
@@ -7,14 +7,12 @@ pragma solidity ^0.8.33;
7
7
  import { AccessControl } from "./core/Access.sol";
8
8
  import { Balances } from "./core/Balances.sol";
9
9
  import { RootZeroContext } from "./core/Context.sol";
10
- import { Host } from "./core/Host.sol";
10
+ import { Host, IHostIntroduction } from "./core/Host.sol";
11
11
  import { FailedCall, NodeCalls } from "./core/Calls.sol";
12
12
  import { Payable } from "./core/Payable.sol";
13
13
  import { Pipeline } from "./core/Pipeline.sol";
14
14
  import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
15
15
  import { Validator } from "./core/Validator.sol";
16
- import { HostDiscovery } from "./core/Host.sol";
17
- import { IHostDiscovery } from "./interfaces/IHostDiscovery.sol";
18
16
 
19
17
 
20
18
 
package/Events.sol CHANGED
@@ -6,22 +6,20 @@ pragma solidity ^0.8.33;
6
6
 
7
7
  import { AccessEvent } from "./events/Access.sol";
8
8
  import { AdminEvent } from "./events/Admin.sol";
9
- import { AssetEvent } from "./events/Asset.sol";
9
+ import { AssetStatusEvent } from "./events/Asset.sol";
10
10
  import { BalanceEvent } from "./events/Balance.sol";
11
11
  import { CollateralEvent } from "./events/Collateral.sol";
12
12
  import { CommandEvent } from "./events/Command.sol";
13
+ import { Contexts } from "./events/Contexts.sol";
13
14
  import { DebtEvent } from "./events/Debt.sol";
14
- import { DepositEvent } from "./events/Deposit.sol";
15
- import { AssetPositionEvent } from "./events/Position.sol";
15
+ import { PositionEvent } from "./events/Position.sol";
16
+ import { ReceivedEvent } from "./events/Received.sol";
16
17
  import { EventEmitter } from "./events/Emitter.sol";
17
- import { GovernedEvent } from "./events/Governed.sol";
18
- import { HostAnnouncedEvent } from "./events/Host.sol";
19
- import { ListingEvent } from "./events/Listing.sol";
18
+ import { IntroductionEvent } from "./events/Introduction.sol";
20
19
  import { PeerEvent } from "./events/Peer.sol";
21
20
  import { QueryEvent } from "./events/Query.sol";
22
- import { PipedEvent } from "./events/Piped.sol";
23
- import { SwapEvent } from "./events/Swap.sol";
24
- import { WithdrawalEvent } from "./events/Withdraw.sol";
21
+ import { RootedEvent } from "./events/Rooted.sol";
22
+ import { SpentEvent } from "./events/Spent.sol";
25
23
 
26
24
 
27
25
 
package/Queries.sol CHANGED
@@ -4,7 +4,7 @@ pragma solidity ^0.8.33;
4
4
  // Aggregator: re-exports query abstractions and reusable query bases.
5
5
  // Import this file to build rootzero query contracts without managing individual paths.
6
6
 
7
- import { IsAllowedAsset, IsAllowedAssetHook } from "./queries/Assets.sol";
7
+ import { AssetStatus, AssetStatusHook } from "./queries/Assets.sol";
8
8
  import { GetPosition, GetPositionHook } from "./queries/Positions.sol";
9
9
  import { GetBalances, GetBalancesHook } from "./queries/Balances.sol";
10
10
  import { QueryBase, encodeQueryCall } from "./queries/Base.sol";
@@ -524,17 +524,26 @@ library Cursors {
524
524
 
525
525
  /// @notice Encode a CONTEXT block.
526
526
  /// @param account Command account identifier.
527
- /// @param value Native value budget assigned to the context.
528
527
  /// @param state Embedded state block stream.
529
528
  /// @param request Embedded request block stream.
530
529
  /// @return Encoded CONTEXT block bytes.
531
- function toContextBlock(
532
- bytes32 account,
530
+ function toContextBlock(bytes32 account, bytes memory state, bytes memory request) internal pure returns (bytes memory) {
531
+ return createBlock(Keys.Context, bytes.concat(account, toBytesBlock(state), toBytesBlock(request)));
532
+ }
533
+
534
+ /// @notice Encode a PIPE block.
535
+ /// @param value Native value assigned to the pipe.
536
+ /// @param account Command account identifier.
537
+ /// @param state Embedded state block stream.
538
+ /// @param request Embedded request block stream.
539
+ /// @return Encoded PIPE block bytes.
540
+ function toPipeBlock(
533
541
  uint value,
542
+ bytes32 account,
534
543
  bytes memory state,
535
544
  bytes memory request
536
545
  ) internal pure returns (bytes memory) {
537
- return createBlock(Keys.Context, bytes.concat(account, bytes32(value), toBytesBlock(state), toBytesBlock(request)));
546
+ return createBlock(Keys.Pipe, bytes.concat(bytes32(value), toContextBlock(account, state, request)));
538
547
  }
539
548
 
540
549
  // -------------------------------------------------------------------------
@@ -1091,20 +1100,31 @@ library Cursors {
1091
1100
  /// The `state` and `request` slices are the raw payloads of the required BYTES children.
1092
1101
  /// @param cur Cursor; advanced past the block.
1093
1102
  /// @return account Command account identifier.
1094
- /// @return value Native value budget assigned to the context.
1095
1103
  /// @return state Embedded state block stream.
1096
1104
  /// @return request Embedded request block stream.
1097
- function unpackContext(
1098
- Cur memory cur
1099
- ) internal pure returns (bytes32 account, uint value, bytes calldata state, bytes calldata request) {
1100
- uint end = cur.enter(Keys.Context, 64 + 2 * Sizes.Header, 0);
1105
+ function unpackContext(Cur memory cur) internal pure returns (bytes32 account, bytes calldata state, bytes calldata request) {
1106
+ uint end = cur.enter(Keys.Context, 32 + 2 * Sizes.Header, 0);
1101
1107
  account = cur.read32();
1102
- value = uint(cur.read32());
1103
1108
  state = cur.unpackBytes();
1104
1109
  request = cur.unpackBytes();
1105
1110
  cur.exit(end);
1106
1111
  }
1107
1112
 
1113
+ /// @notice Consume a PIPE block and return its value and context fields.
1114
+ /// @param cur Cursor; advanced past the block.
1115
+ /// @return value Native value assigned to the pipe.
1116
+ /// @return account Command account identifier.
1117
+ /// @return state Embedded state block stream.
1118
+ /// @return request Embedded request block stream.
1119
+ function unpackPipe(
1120
+ Cur memory cur
1121
+ ) internal pure returns (uint value, bytes32 account, bytes calldata state, bytes calldata request) {
1122
+ uint end = cur.enter(Keys.Pipe, 32 + Sizes.Header + 32 + 2 * Sizes.Header, 0);
1123
+ value = uint(cur.read32());
1124
+ (account, state, request) = cur.unpackContext();
1125
+ cur.exit(end);
1126
+ }
1127
+
1108
1128
  // Type-specific validators
1109
1129
 
1110
1130
  /// @notice Validate an AUTH block at position `i` and extract deadline and proof.
package/blocks/Keys.sol CHANGED
@@ -43,6 +43,8 @@ library Keys {
43
43
  bytes4 constant Call = bytes4(keccak256("#call"));
44
44
  /// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
45
45
  bytes4 constant Context = bytes4(keccak256("#context"));
46
+ /// @dev Pipeline invocation - (uint value, #context)
47
+ bytes4 constant Pipe = bytes4(keccak256("#pipe"));
46
48
  /// @dev Authentication proof - (uint cid, uint deadline, #bytes as proof); must appear last in its segment
47
49
  bytes4 constant Auth = bytes4(keccak256("#auth"));
48
50
  /// @dev Asset descriptor without amount - (bytes32 asset, bytes32 meta)
@@ -52,7 +54,7 @@ library Keys {
52
54
  /// @dev Relayer bounty - (uint amount, bytes32 relayer)
53
55
  bytes4 constant Bounty = bytes4(keccak256("#bounty"));
54
56
 
55
- /// @dev Structural status form - (bool ok)
57
+ /// @dev Structural status form - (uint code)
56
58
  bytes4 constant Status = bytes4(keccak256("#status"));
57
59
  /// @dev Structural asset amount form - (bytes32 asset, bytes32 meta, uint amount)
58
60
  bytes4 constant AssetAmount = bytes4(keccak256("#assetAmount"));
package/blocks/Schema.sol CHANGED
@@ -59,9 +59,10 @@ library Schemas {
59
59
  string constant Allocation = "#allocation { uint host, bytes32 asset, bytes32 meta, uint amount }";
60
60
  string constant Allowance = "#allowance { uint host, bytes32 asset, bytes32 meta, uint amount }";
61
61
  string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount }";
62
+ string constant Context = "#context { bytes32 account, #bytes as state, #bytes as request }";
63
+ string constant Pipe = "#pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as request } }";
62
64
  string constant Call = "#call { uint target, uint value, #bytes as payload }";
63
65
  string constant Step = "#step { uint target, uint value, #bytes as request }";
64
- string constant Context = "#context { bytes32 account, uint value, #bytes as state, #bytes as request }";
65
66
  string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
66
67
  string constant Fee = "#fee { uint amount }";
67
68
  string constant Auth = "#auth { uint cid, uint deadline, #bytes as proof }";
@@ -75,13 +76,14 @@ library Schemas {
75
76
  /// @notice Reusable structural block schemas for core tuple shapes.
76
77
  /// These describe payload form without assigning command or query semantics.
77
78
  library Forms {
78
- string constant Status = "#status { bool ok }";
79
+ string constant Status = "#status { uint code }";
79
80
  string constant AssetAmount = "#assetAmount { bytes32 asset, bytes32 meta, uint amount }";
80
81
  string constant AccountAsset = "#accountAsset { bytes32 account, bytes32 asset, bytes32 meta }";
81
82
  string constant AccountAmount = "#accountAmount { bytes32 account, bytes32 asset, bytes32 meta, uint amount }";
82
83
  string constant HostAmount = "#hostAmount { uint host, bytes32 asset, bytes32 meta, uint amount }";
83
84
  string constant HostAccountAsset = "#hostAccountAsset { uint host, bytes32 account, bytes32 asset, bytes32 meta }";
84
- string constant HostAccountAmount = "#hostAccountAmount { uint host, bytes32 account, bytes32 asset, bytes32 meta, uint amount }";
85
+ string constant HostAccountAmount =
86
+ "#hostAccountAmount { uint host, bytes32 account, bytes32 asset, bytes32 meta, uint amount }";
85
87
  }
86
88
 
87
89
  /// @title Sizes
@@ -105,8 +107,8 @@ library Sizes {
105
107
  uint constant Proof = 85;
106
108
  /// @dev AUTH block: 8 header + 32 cid + 32 deadline + nested BYTES block with 85-byte proof = 165 bytes
107
109
  uint constant Auth = B64 + Header + Proof;
108
- /// @dev STATUS block: 8 header + 1 bool byte = 9 bytes
109
- uint constant Status = Header + 1;
110
+ /// @dev STATUS block: 8 header + 32 status code = 40 bytes
111
+ uint constant Status = B32;
110
112
  /// @dev AMOUNT block: 8 header + 32 asset + 32 meta + 32 amount = 104 bytes
111
113
  uint constant Amount = B96;
112
114
  /// @dev BALANCE block: 8 header + 32 asset + 32 meta + 32 amount = 104 bytes
@@ -27,6 +27,7 @@ library Hints {
27
27
  uint constant Step = 256;
28
28
  uint constant Call = 256;
29
29
  uint constant Context = 512;
30
+ uint constant Pipe = 608;
30
31
  }
31
32
 
32
33
  /// @title Writers
@@ -223,6 +224,14 @@ library Writers {
223
224
  return allocFromHint(count, Hints.Context);
224
225
  }
225
226
 
227
+ /// @notice Allocate a writer for `count` PIPE blocks using a per-block capacity hint.
228
+ /// @dev The backing buffer expands automatically if encoded pipes exceed the initial hint.
229
+ /// @param count Number of pipe blocks to allocate space for.
230
+ /// @return writer Allocated growable writer.
231
+ function allocPipes(uint count) internal pure returns (Writer memory writer) {
232
+ return allocFromHint(count, Hints.Pipe);
233
+ }
234
+
226
235
  // -------------------------------------------------------------------------
227
236
  // Fixed-width write helpers
228
237
  // -------------------------------------------------------------------------
@@ -871,27 +880,46 @@ library Writers {
871
880
  appendBlock64Bytes(writer, Keys.Call, bytes32(target), bytes32(value), data);
872
881
  }
873
882
 
874
- /// @notice Append a CONTEXT block with a value budget and nested state/request BYTES payloads.
883
+ /// @notice Append a CONTEXT block with nested state/request BYTES payloads.
875
884
  /// @param writer Destination writer; `i` is advanced by the encoded CONTEXT block length.
876
885
  /// @param account Command account identifier.
877
- /// @param value Native value budget assigned to the context.
878
886
  /// @param state Raw nested state payload.
879
887
  /// @param request Raw nested request payload.
880
- function appendContext(
888
+ function appendContext(Writer memory writer, bytes32 account, bytes memory state, bytes memory request) internal pure {
889
+ appendBlock32BytesBytes(writer, Keys.Context, account, state, request);
890
+ }
891
+
892
+ /// @notice Append a PIPE block with a nested CONTEXT block.
893
+ /// @param writer Destination writer; `i` is advanced by the encoded PIPE block length.
894
+ /// @param value Native value assigned to the pipe.
895
+ /// @param account Command account identifier.
896
+ /// @param state Raw nested state payload.
897
+ /// @param request Raw nested request payload.
898
+ function appendPipe(
881
899
  Writer memory writer,
882
- bytes32 account,
883
900
  uint value,
901
+ bytes32 account,
884
902
  bytes memory state,
885
903
  bytes memory request
886
904
  ) internal pure {
887
- appendBlock64BytesBytes(writer, Keys.Context, account, bytes32(value), state, request);
905
+ uint i = writer.i;
906
+ uint len = 64 + 3 * Sizes.Header + state.length + request.length;
907
+ uint next = i + Sizes.Header + len;
908
+ i = reserve(writer, next, next);
909
+
910
+ uint p = writeHeader(writer.dst, i, Keys.Pipe, uint32(max32(len)));
911
+ assembly ("memory-safe") {
912
+ mstore(add(p, 0x08), value)
913
+ }
914
+
915
+ writeBlock32BytesBytes(writer.dst, i + Sizes.Header + 32, Keys.Context, account, state, request);
888
916
  }
889
917
 
890
918
  /// @notice Append a STATUS form block.
891
919
  /// @param writer Destination writer; `i` is advanced by `Sizes.Status`.
892
- /// @param ok Status value to encode.
893
- function appendStatus(Writer memory writer, bool ok) internal pure {
894
- appendBlock32(writer, Keys.Status, ok ? bytes32(uint(1) << 248) : bytes32(0), 1);
920
+ /// @param code Status code to encode.
921
+ function appendStatus(Writer memory writer, uint code) internal pure {
922
+ appendBlock32(writer, Keys.Status, bytes32(code), 32);
895
923
  }
896
924
 
897
925
  /// @notice Append a BALANCE block using separate field values.
package/core/Calls.sol CHANGED
@@ -72,13 +72,13 @@ abstract contract NodeCalls is AccessControl {
72
72
  }
73
73
 
74
74
  /// @notice Encode and call a trusted command node.
75
- /// @param ctx Command execution context.
76
- /// @param cid Command node ID embedding the target selector.
75
+ /// @param id Command node ID embedding the target selector.
77
76
  /// @param value Native value to forward in wei.
77
+ /// @param ctx Command execution context.
78
78
  /// @return Decoded command output block stream.
79
- function callCommand(CommandContext memory ctx, uint cid, uint value) internal returns (bytes memory) {
80
- bytes4 selector = Ids.commandSelector(cid);
79
+ function callCommand(uint id, uint value, CommandContext memory ctx) internal returns (bytes memory) {
80
+ bytes4 selector = Ids.commandSelector(id);
81
81
  bytes memory data = abi.encodeWithSelector(selector, ctx);
82
- return abi.decode(callTo(cid, value, data), (bytes));
82
+ return abi.decode(callTo(id, value, data), (bytes));
83
83
  }
84
84
  }
package/core/Host.sol CHANGED
@@ -5,38 +5,44 @@ import {AccessControl} from "./Access.sol";
5
5
  import {Authorize} from "../commands/admin/Authorize.sol";
6
6
  import {Unauthorize} from "../commands/admin/Unauthorize.sol";
7
7
  import {ExecutePayable} from "../commands/admin/Execute.sol";
8
- import {HostAnnouncedEvent} from "../events/Host.sol";
9
- import {IHostDiscovery} from "../interfaces/IHostDiscovery.sol";
8
+ import {IntroductionEvent} from "../events/Introduction.sol";
10
9
  import {Ids} from "../utils/Ids.sol";
11
10
 
12
- /// @notice Mixin that allows a contract to act as a host discovery registry.
13
- /// Hosts call `announceHost` on a discovery contract to register themselves.
14
- abstract contract HostDiscovery is HostAnnouncedEvent, IHostDiscovery {
15
- /// @notice Announce this host to the discovery registry.
16
- /// Validates that `id` matches `msg.sender` before emitting.
17
- /// @param id Host node ID (must equal `Ids.toHost(msg.sender)`).
18
- /// @param blocknum Block number at which the host was deployed.
19
- /// @param version Protocol version the host implements.
20
- /// @param namespace Human-readable namespace string for the host.
21
- function announceHost(uint id, uint blocknum, uint16 version, string calldata namespace) external {
22
- emit HostAnnounced(Ids.matchHost(id, msg.sender), blocknum, version, namespace);
23
- }
11
+ /// @title IHostIntroduction
12
+ /// @notice Interface implemented by hosts that accept introductions from other hosts.
13
+ interface IHostIntroduction {
14
+ /// @notice Record a host introduction claim.
15
+ /// @param peer Host node ID being introduced.
16
+ /// @param blocknum Block number at which the introduction was made.
17
+ /// @param version Protocol version the host is running.
18
+ /// @param namespace Human-readable namespace or label for the host.
19
+ function introduce(uint peer, uint blocknum, uint16 version, string calldata namespace) external;
24
20
  }
25
21
 
26
22
  /// @title Host
27
23
  /// @notice Abstract base contract for rootzero host implementations.
28
24
  /// Inherits admin command support (authorize, unauthorize, executePayable) and
29
- /// optionally announces itself to a discovery contract at deployment.
25
+ /// optionally introduces itself to a commander host at deployment.
30
26
  /// Accepts native ETH payments via the `receive` function.
31
- abstract contract Host is Authorize, Unauthorize, ExecutePayable {
27
+ abstract contract Host is Authorize, Unauthorize, ExecutePayable, IntroductionEvent, IHostIntroduction {
32
28
  /// @param cmdr Commander address; passed to `AccessControl`.
33
- /// If `cmdr` is a deployed contract, the host calls `announceHost`
34
- /// on it during construction to register with the discovery registry.
29
+ /// If `cmdr` is a deployed contract, the host calls `introduce`
30
+ /// on it during construction.
35
31
  /// @param version Protocol version number to publish in the announcement.
36
32
  /// @param namespace Human-readable namespace string for the host.
37
33
  constructor(address cmdr, uint16 version, string memory namespace) AccessControl(cmdr) {
38
34
  if (cmdr == address(0) || cmdr == address(this) || cmdr.code.length == 0) return;
39
- IHostDiscovery(cmdr).announceHost(host, block.number, version, namespace);
35
+ IHostIntroduction(cmdr).introduce(host, block.number, version, namespace);
36
+ }
37
+
38
+ /// @notice Record a host introduction claim.
39
+ /// @dev Validates that `peer` matches `msg.sender`; it does not authorize or trust the introduced host.
40
+ /// @param peer Host node ID being introduced.
41
+ /// @param blocknum Block number at which the host was deployed.
42
+ /// @param version Protocol version the host implements.
43
+ /// @param namespace Human-readable namespace string for the host.
44
+ function introduce(uint peer, uint blocknum, uint16 version, string calldata namespace) external {
45
+ emit Introduction(Ids.matchHost(peer, msg.sender), blocknum, version, namespace);
40
46
  }
41
47
 
42
48
  /// @notice Accept native ETH transfers (e.g. from command value flows).
package/docs/Schema.md CHANGED
@@ -57,7 +57,8 @@ Once a child block appears, no more fixed fields may follow.
57
57
 
58
58
  ```txt
59
59
  #call { uint target, uint value, #bytes as payload }
60
- #context { bytes32 account, uint value, #bytes as state, #bytes as request }
60
+ #context { bytes32 account, #bytes as state, #bytes as request }
61
+ #pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as request } }
61
62
  ```
62
63
 
63
64
  The tail is embedded directly as child block bytes. There is no wrapper around a
@@ -187,7 +188,8 @@ Common protocol schemas live in `contracts/blocks/Schema.sol`:
187
188
  #payout { bytes32 account, bytes32 asset, bytes32 meta, uint amount }
188
189
  #call { uint target, uint value, #bytes as payload }
189
190
  #step { uint target, uint value, #bytes as request }
190
- #context { bytes32 account, uint value, #bytes as state, #bytes as request }
191
+ #context { bytes32 account, #bytes as state, #bytes as request }
192
+ #pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as request } }
191
193
  #auth { uint cid, uint deadline, #bytes as proof }
192
194
  ```
193
195
 
package/events/Access.sol CHANGED
@@ -3,10 +3,10 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event Access(uint indexed host, uint node, bool trusted)";
7
-
8
6
  /// @notice Emitted when a node's authorization status changes on a host.
9
7
  abstract contract AccessEvent is EventEmitter {
8
+ string private constant ABI = "event Access(uint indexed host, uint node, bool trusted)";
9
+
10
10
  /// @param host Host node ID where the authorization change occurred.
11
11
  /// @param node Node ID that was authorized or deauthorized.
12
12
  /// @param trusted True if the node was authorized, false if deauthorized.
package/events/Admin.sol CHANGED
@@ -3,11 +3,11 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI =
7
- "event Admin(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool acceptsValue)";
8
-
9
6
  /// @notice Emitted once per admin command during host deployment to publish its request schema and state keys.
10
7
  abstract contract AdminEvent is EventEmitter {
8
+ string private constant ABI =
9
+ "event Admin(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool acceptsValue)";
10
+
11
11
  /// @param host Host node ID that owns this admin command.
12
12
  /// @param id Command node ID.
13
13
  /// @param name Human-readable command name.
package/events/Asset.sol CHANGED
@@ -3,14 +3,15 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event Asset(uint indexed host, bytes32 name, uint32 prefix)";
6
+ /// @notice Emitted when an asset support status is updated on a host.
7
+ abstract contract AssetStatusEvent is EventEmitter {
8
+ string private constant ABI = "event AssetStatus(uint indexed host, bytes32 asset, bytes32 meta, uint status)";
7
9
 
8
- /// @notice Emitted when an asset is registered or updated on a host.
9
- abstract contract AssetEvent is EventEmitter {
10
- /// @param host Host node ID that registered the asset.
11
- /// @param name Asset name encoded as a bytes32 string.
12
- /// @param prefix 4-byte type prefix of the asset ID.
13
- event Asset(uint indexed host, bytes32 name, uint32 prefix);
10
+ /// @param host Host node ID that manages this listing.
11
+ /// @param asset Asset identifier.
12
+ /// @param meta Asset metadata slot.
13
+ /// @param status Asset support status. Zero means unsupported; nonzero means supported.
14
+ event AssetStatus(uint indexed host, bytes32 asset, bytes32 meta, uint status);
14
15
 
15
16
  constructor() {
16
17
  emit EventAbi(ABI);
@@ -3,10 +3,10 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event Balance(bytes32 indexed account, bytes32 asset, bytes32 meta, uint balance, int change, uint access)";
7
-
8
6
  /// @notice Emitted when an account balance changes.
9
7
  abstract contract BalanceEvent is EventEmitter {
8
+ string private constant ABI = "event Balance(bytes32 indexed account, bytes32 asset, bytes32 meta, uint balance, int change, uint access)";
9
+
10
10
  /// @param account Account identifier whose balance changed.
11
11
  /// @param asset Asset identifier.
12
12
  /// @param meta Asset metadata slot.
@@ -3,11 +3,11 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event Collateral(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint access)";
7
-
8
6
  /// @notice Emitted when an account's collateral position changes.
9
7
  /// Off-chain indexers should query the access command to retrieve the precise collateral details.
10
8
  abstract contract CollateralEvent is EventEmitter {
9
+ string private constant ABI = "event Collateral(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint access)";
10
+
11
11
  /// @param account Account identifier that holds the collateral.
12
12
  /// @param asset Asset identifier of the collateral.
13
13
  /// @param meta Asset metadata slot.
@@ -3,11 +3,11 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI =
7
- "event Command(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool acceptsValue)";
8
-
9
6
  /// @notice Emitted once per command during host deployment to publish its request schema and state keys.
10
7
  abstract contract CommandEvent is EventEmitter {
8
+ string private constant ABI =
9
+ "event Command(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool acceptsValue)";
10
+
11
11
  /// @param host Host node ID that owns this command.
12
12
  /// @param id Command node ID.
13
13
  /// @param name Human-readable command name.
@@ -0,0 +1,12 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ /// @notice Standard context codes for generic asset activity events.
5
+ library Contexts {
6
+ uint constant Deposit = 1;
7
+ uint constant Withdraw = 2;
8
+ uint constant Fee = 3;
9
+ uint constant Mint = 4;
10
+ uint constant Burn = 5;
11
+ uint constant Swap = 6;
12
+ }
package/events/Debt.sol CHANGED
@@ -3,11 +3,11 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event Debt(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint mode, uint access)";
7
-
8
6
  /// @notice Emitted when an account's debt position changes.
9
7
  /// Off-chain indexers should query the access command to retrieve precise debt details.
10
8
  abstract contract DebtEvent is EventEmitter {
9
+ string private constant ABI = "event Debt(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint mode, uint access)";
10
+
11
11
  /// @param account Account identifier that holds the debt.
12
12
  /// @param asset Asset identifier of the debt.
13
13
  /// @param meta Asset metadata slot.
@@ -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 when a host introduces itself to another host.
7
+ abstract contract IntroductionEvent is EventEmitter {
8
+ string private constant ABI = "event Introduction(uint indexed host, uint blocknum, uint16 version, string namespace)";
9
+
10
+ /// @param host Host node ID of the introducing contract.
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);
15
+
16
+ constructor() {
17
+ emit EventAbi(ABI);
18
+ }
19
+ }
20
+
21
+
22
+
package/events/Peer.sol CHANGED
@@ -1,13 +1,13 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { EventEmitter } from "./Emitter.sol";
5
-
6
- string constant ABI =
7
- "event Peer(uint indexed host, uint id, string name, bytes32 shape, string request, string response, bool acceptsValue)";
4
+ import {EventEmitter} from "./Emitter.sol";
8
5
 
9
6
  /// @notice Emitted once per peer during host deployment to publish its request and response schemas.
10
7
  abstract contract PeerEvent is EventEmitter {
8
+ string private constant ABI =
9
+ "event Peer(uint indexed host, uint id, string name, bytes32 shape, string request, string response, bool acceptsValue)";
10
+
11
11
  /// @param host Host node ID that owns this peer.
12
12
  /// @param id Peer node ID.
13
13
  /// @param name Human-readable peer name.
@@ -15,12 +15,17 @@ abstract contract PeerEvent is EventEmitter {
15
15
  /// @param request Schema DSL string describing the peer request shape.
16
16
  /// @param response Schema DSL string describing the peer response shape.
17
17
  /// @param acceptsValue Whether the peer entrypoint accepts nonzero `msg.value`.
18
- event Peer(uint indexed host, uint id, string name, bytes32 shape, string request, string response, bool acceptsValue);
18
+ event Peer(
19
+ uint indexed host,
20
+ uint id,
21
+ string name,
22
+ bytes32 shape,
23
+ string request,
24
+ string response,
25
+ bool acceptsValue
26
+ );
19
27
 
20
28
  constructor() {
21
29
  emit EventAbi(ABI);
22
30
  }
23
31
  }
24
-
25
-
26
-
@@ -3,17 +3,17 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import {EventEmitter} from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event AssetPosition(bytes32 indexed account, bytes32 asset, bytes32 meta, uint value, uint queryId)";
7
-
8
6
  /// @notice Emitted when the reported value of an asset-backed position changes or is observed.
9
7
  /// A value of 0 should be interpreted as a closed position.
10
- abstract contract AssetPositionEvent is EventEmitter {
8
+ abstract contract PositionEvent is EventEmitter {
9
+ string private constant ABI = "event Position(bytes32 indexed account, bytes32 asset, bytes32 meta, uint value, uint queryId)";
10
+
11
11
  /// @param account Account identifier that owns or is associated with the position.
12
12
  /// @param asset Asset identifier for the asset class.
13
13
  /// @param meta Asset metadata slot carrying the position context.
14
14
  /// @param value Context-specific position value; 0 indicates a closed position.
15
15
  /// @param queryId Query ID associated with the position lookup or reporting context.
16
- event AssetPosition(bytes32 indexed account, bytes32 asset, bytes32 meta, uint value, uint queryId);
16
+ event Position(bytes32 indexed account, bytes32 asset, bytes32 meta, uint value, uint queryId);
17
17
 
18
18
  constructor() {
19
19
  emit EventAbi(ABI);
package/events/Query.sol CHANGED
@@ -3,10 +3,10 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import {EventEmitter} from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event Query(uint indexed host, uint id, string name, bytes32 shape, string request, string response)";
7
-
8
6
  /// @notice Emitted once per query during host deployment to publish its request and response schemas.
9
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)";
9
+
10
10
  /// @param host Host node ID that owns this query.
11
11
  /// @param id Query node ID.
12
12
  /// @param name Human-readable query name.
@@ -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 receives an asset in a protocol operation.
7
+ abstract contract ReceivedEvent is EventEmitter {
8
+ string private constant ABI = "event Received(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint context)";
9
+
10
+ /// @param account Account identifier that received the asset.
11
+ /// @param asset Asset identifier.
12
+ /// @param meta Asset metadata slot.
13
+ /// @param amount Amount received.
14
+ /// @param context Operation context identifier associated with this receipt.
15
+ event Received(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint context);
16
+
17
+ constructor() {
18
+ emit EventAbi(ABI);
19
+ }
20
+ }
@@ -3,14 +3,14 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
- string constant ABI = "event Piped(bytes32 indexed account, uint deadline, uint value)";
7
-
8
6
  /// @notice Emitted for root-level protocol actions (e.g. governance or protocol-wide operations).
9
- abstract contract PipedEvent is EventEmitter {
7
+ abstract contract RootedEvent is EventEmitter {
8
+ string private constant ABI = "event Rooted(bytes32 indexed account, uint deadline, uint value)";
9
+
10
10
  /// @param account Account identifier associated with the action.
11
11
  /// @param deadline Expiry timestamp of the action.
12
12
  /// @param value Native value associated with the action.
13
- event Piped(bytes32 indexed account, uint deadline, uint value);
13
+ event Rooted(bytes32 indexed account, uint deadline, uint value);
14
14
 
15
15
  constructor() {
16
16
  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 an account spends an asset in a protocol operation.
7
+ abstract contract SpentEvent is EventEmitter {
8
+ string private constant ABI = "event Spent(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint context)";
9
+
10
+ /// @param account Account identifier that spent the asset.
11
+ /// @param asset Asset identifier.
12
+ /// @param meta Asset metadata slot.
13
+ /// @param amount Amount spent.
14
+ /// @param context Operation context identifier associated with this spend.
15
+ event Spent(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint context);
16
+
17
+ constructor() {
18
+ emit EventAbi(ABI);
19
+ }
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootzero/contracts",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
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/peer/Pipe.sol CHANGED
@@ -9,26 +9,26 @@ import {Budget} from "../utils/Value.sol";
9
9
  using Cursors for Cur;
10
10
 
11
11
  /// @title PeerPipePayable
12
- /// @notice Peer that consumes CONTEXT blocks and executes each context request as a STEP stream.
13
- /// Each CONTEXT block carries an account, state, and request; the request is passed to the
14
- /// shared pipeline as the step stream.
12
+ /// @notice Peer that consumes PIPE blocks and executes each context request as a STEP stream.
13
+ /// Each PIPE block carries a value budget plus a CONTEXT block; the nested
14
+ /// context request is passed to the shared pipeline as the step stream.
15
15
  abstract contract PeerPipePayable is PeerBase, Pipeline {
16
16
  string private constant NAME = "peerPipePayable";
17
17
  uint internal immutable peerPipePayableId = peerId(NAME);
18
18
 
19
19
  constructor() {
20
- emit Peer(host, peerPipePayableId, NAME, "1:0", Schemas.Context, "", true);
20
+ emit Peer(host, peerPipePayableId, NAME, "1:0", Schemas.Pipe, "", true);
21
21
  }
22
22
 
23
- /// @notice Execute peer-supplied contexts through the shared payable pipe.
24
- /// @dev Each context receives its own explicit value sub-budget. Any top-level
25
- /// `msg.value` not assigned to a context remains on this host.
23
+ /// @notice Execute peer-supplied pipes through the shared payable pipe.
24
+ /// @dev Each pipe receives its own explicit value sub-budget. Any top-level
25
+ /// `msg.value` not assigned to a pipe remains on this host.
26
26
  function peerPipePayable(bytes calldata request) external payable onlyPeer returns (bytes memory) {
27
27
  (Cur memory input, ) = cursor(request, 1);
28
28
  Budget memory budget = valueBudget();
29
29
 
30
30
  while (input.i < input.bound) {
31
- (bytes32 account, uint value, bytes calldata state, bytes calldata steps) = input.unpackContext();
31
+ (uint value, bytes32 account, bytes calldata state, bytes calldata steps) = input.unpackPipe();
32
32
  pipe(account, state, steps, allocateValue(budget, value));
33
33
  }
34
34
 
@@ -8,38 +8,38 @@ import {QueryBase} from "./Base.sol";
8
8
  using Cursors for Cur;
9
9
  using Writers for Writer;
10
10
 
11
- abstract contract IsAllowedAssetHook {
12
- /// @notice Resolve whether one asset tuple is allowed.
13
- /// Concrete implementations define the allowlist policy.
11
+ abstract contract AssetStatusHook {
12
+ /// @notice Resolve support status for one asset tuple.
13
+ /// Concrete implementations define the support policy and optional context codes.
14
14
  /// @param asset Requested asset identifier.
15
15
  /// @param meta Requested asset metadata slot.
16
- /// @return allowed Whether the asset tuple is allowed.
17
- function isAllowedAsset(bytes32 asset, bytes32 meta) internal view virtual returns (bool allowed);
16
+ /// @return status Asset support status. Zero means unsupported; nonzero means supported.
17
+ function assetStatus(bytes32 asset, bytes32 meta) internal view virtual returns (uint status);
18
18
  }
19
19
 
20
- /// @title IsAllowedAsset
21
- /// @notice Rootzero query that checks whether one or more `(asset, meta)` tuples are allowed.
20
+ /// @title AssetStatus
21
+ /// @notice Rootzero query that checks support status for one or more `(asset, meta)` tuples.
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
- abstract contract IsAllowedAsset is QueryBase, IsAllowedAssetHook {
25
- string private constant NAME = "isAllowedAsset";
26
- uint public immutable isAllowedAssetId = queryId(NAME);
24
+ abstract contract AssetStatus is QueryBase, AssetStatusHook {
25
+ string private constant NAME = "assetStatus";
26
+ uint public immutable assetStatusId = queryId(NAME);
27
27
 
28
28
  constructor() {
29
- emit Query(host, isAllowedAssetId, NAME, "1:1", Schemas.Asset, Forms.Status);
29
+ emit Query(host, assetStatusId, NAME, "1:1", Schemas.Asset, Forms.Status);
30
30
  }
31
31
 
32
- /// @notice Resolve allowlist status for a run of requested `(asset, meta)` tuples.
32
+ /// @notice Resolve asset support status for a run of requested `(asset, meta)` tuples.
33
33
  /// @param request Block-stream request consisting of `#asset { bytes32 asset, bytes32 meta }` blocks.
34
- /// @return Block-stream response containing one `#status { bool ok }` per asset block.
35
- function isAllowedAsset(bytes calldata request) external view returns (bytes memory) {
34
+ /// @return Block-stream response containing one `#status { uint code }` per asset block.
35
+ function assetStatus(bytes calldata request) external view returns (bytes memory) {
36
36
  (Cur memory query, uint groups) = cursor(request, 1);
37
37
  Writer memory response = Writers.allocStatuses(groups);
38
38
 
39
39
  while (query.i < query.bound) {
40
40
  (bytes32 asset, bytes32 meta) = query.unpackAsset();
41
- bool allowed = isAllowedAsset(asset, meta);
42
- response.appendStatus(allowed);
41
+ uint status = assetStatus(asset, meta);
42
+ response.appendStatus(status);
43
43
  }
44
44
 
45
45
  query.close();
package/utils/Assets.sol CHANGED
@@ -17,6 +17,8 @@ import {matchesBase, toLocalBase} from "./Utils.sol";
17
17
  library Assets {
18
18
  /// @dev Thrown when an asset ID does not match the expected type or chain.
19
19
  error InvalidAsset();
20
+ /// @dev Thrown when an asset is not authorized for the requested operation.
21
+ error UnauthorizedAsset();
20
22
 
21
23
  /// @dev Full 4-byte type prefix for the native value asset.
22
24
  uint32 constant Value = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Asset) << 8) | uint32(Layout.Value);
@@ -1,22 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import { EventEmitter } from "./Emitter.sol";
5
-
6
- string constant ABI = "event Deposit(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount)";
7
-
8
- /// @notice Emitted when assets are deposited into an account.
9
- abstract contract DepositEvent is EventEmitter {
10
- /// @param account Destination account identifier.
11
- /// @param asset Asset identifier.
12
- /// @param meta Asset metadata slot.
13
- /// @param amount Amount deposited.
14
- event Deposit(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount);
15
-
16
- constructor() {
17
- emit EventAbi(ABI);
18
- }
19
- }
20
-
21
-
22
-
@@ -1,21 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import { EventEmitter } from "./Emitter.sol";
5
-
6
- string constant ABI = "event Governed(uint indexed host, uint deadline, uint value)";
7
-
8
- /// @notice Emitted when a governance action is recorded on a host.
9
- abstract contract GovernedEvent is EventEmitter {
10
- /// @param host Host node ID where the governance action occurred.
11
- /// @param deadline Expiry timestamp of the governance action.
12
- /// @param value Native value associated with the action.
13
- event Governed(uint indexed host, uint deadline, uint value);
14
-
15
- constructor() {
16
- emit EventAbi(ABI);
17
- }
18
- }
19
-
20
-
21
-
package/events/Host.sol DELETED
@@ -1,22 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import { EventEmitter } from "./Emitter.sol";
5
-
6
- string constant ABI = "event HostAnnounced(uint indexed host, uint blocknum, uint16 version, string namespace)";
7
-
8
- /// @notice Emitted by the discovery contract when a host registers itself.
9
- abstract contract HostAnnouncedEvent is EventEmitter {
10
- /// @param host Host node ID of the registering contract.
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 HostAnnounced(uint indexed host, uint blocknum, uint16 version, string namespace);
15
-
16
- constructor() {
17
- emit EventAbi(ABI);
18
- }
19
- }
20
-
21
-
22
-
@@ -1,22 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import { EventEmitter } from "./Emitter.sol";
5
-
6
- string constant ABI = "event Listing(uint indexed host, bytes32 asset, bytes32 meta, bool active)";
7
-
8
- /// @notice Emitted when an asset listing is updated on a host.
9
- abstract contract ListingEvent is EventEmitter {
10
- /// @param host Host node ID that manages this listing.
11
- /// @param asset Asset identifier.
12
- /// @param meta Asset metadata slot.
13
- /// @param active True if the listing is currently active.
14
- event Listing(uint indexed host, bytes32 asset, bytes32 meta, bool active);
15
-
16
- constructor() {
17
- emit EventAbi(ABI);
18
- }
19
- }
20
-
21
-
22
-
package/events/Swap.sol DELETED
@@ -1,20 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import { EventEmitter } from "./Emitter.sol";
5
-
6
- string constant ABI = "event Swap(bytes32 indexed account, bytes32 assetIn, uint amountIn, bytes32 assetOut, uint amountOut)";
7
-
8
- /// @notice Emitted when an account swaps one asset for another.
9
- abstract contract SwapEvent is EventEmitter {
10
- /// @param account Account identifier performing the swap.
11
- /// @param assetIn Input asset identifier.
12
- /// @param amountIn Input amount spent.
13
- /// @param assetOut Output asset identifier.
14
- /// @param amountOut Output amount received.
15
- event Swap(bytes32 indexed account, bytes32 assetIn, uint amountIn, bytes32 assetOut, uint amountOut);
16
-
17
- constructor() {
18
- emit EventAbi(ABI);
19
- }
20
- }
@@ -1,22 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import { EventEmitter } from "./Emitter.sol";
5
-
6
- string constant ABI = "event Withdrawal(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount)";
7
-
8
- /// @notice Emitted when assets are withdrawn from an account.
9
- abstract contract WithdrawalEvent is EventEmitter {
10
- /// @param account Source account identifier.
11
- /// @param asset Asset identifier.
12
- /// @param meta Asset metadata slot.
13
- /// @param amount Amount withdrawn.
14
- event Withdrawal(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount);
15
-
16
- constructor() {
17
- emit EventAbi(ABI);
18
- }
19
- }
20
-
21
-
22
-
@@ -1,16 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- /// @title IHostDiscovery
5
- /// @notice Interface implemented by a discovery registry that hosts announce themselves to.
6
- interface IHostDiscovery {
7
- /// @notice Register or refresh a host entry in the discovery registry.
8
- /// @param id Host node ID.
9
- /// @param blocknum Block number at which the announcement was made.
10
- /// @param version Protocol version the host is running.
11
- /// @param namespace Human-readable namespace or label for the host.
12
- function announceHost(uint id, uint blocknum, uint16 version, string calldata namespace) external;
13
- }
14
-
15
-
16
-