@rootzero/contracts 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/Endpoints.sol +10 -7
  3. package/Events.sol +1 -0
  4. package/README.md +300 -79
  5. package/blocks/Cursors.sol +49 -14
  6. package/blocks/Keys.sol +4 -0
  7. package/blocks/Schema.sol +10 -4
  8. package/blocks/Writers.sol +16 -0
  9. package/commands/Base.sol +10 -9
  10. package/commands/Burn.sol +4 -5
  11. package/commands/Credit.sol +4 -5
  12. package/commands/Debit.sol +4 -5
  13. package/commands/Deposit.sol +8 -10
  14. package/commands/Payout.sol +5 -6
  15. package/commands/Provision.sol +8 -10
  16. package/commands/Relay.sol +4 -5
  17. package/commands/Withdraw.sol +4 -5
  18. package/commands/admin/AllowAssets.sol +4 -5
  19. package/commands/admin/Allowance.sol +4 -4
  20. package/commands/admin/Appoint.sol +4 -5
  21. package/commands/admin/Authorize.sol +4 -5
  22. package/commands/admin/DenyAssets.sol +4 -5
  23. package/commands/admin/Destroy.sol +3 -4
  24. package/commands/admin/Dismiss.sol +4 -5
  25. package/commands/admin/Execute.sol +4 -5
  26. package/commands/admin/Init.sol +3 -4
  27. package/commands/admin/Label.sol +35 -0
  28. package/commands/admin/Unauthorize.sol +4 -5
  29. package/core/Host.sol +7 -11
  30. package/core/Pipeline.sol +1 -1
  31. package/docs/Schema.md +59 -2
  32. package/events/Admin.sol +3 -9
  33. package/events/Chain.sol +2 -3
  34. package/events/Command.sol +3 -9
  35. package/events/Guard.sol +2 -3
  36. package/events/Introduction.sol +2 -4
  37. package/events/Labeled.sol +21 -0
  38. package/events/Peer.sol +2 -11
  39. package/events/Query.sol +2 -3
  40. package/events/Transfer.sol +1 -1
  41. package/guards/Base.sol +7 -6
  42. package/guards/Revoke.sol +4 -5
  43. package/package.json +1 -1
  44. package/peer/AllowAssets.sol +9 -5
  45. package/peer/Allowance.sol +9 -5
  46. package/peer/BalancePull.sol +9 -5
  47. package/peer/Base.sol +7 -6
  48. package/peer/Credit.sol +39 -0
  49. package/peer/Debit.sol +39 -0
  50. package/peer/DenyAssets.sol +9 -5
  51. package/peer/Dispatch.sol +9 -5
  52. package/peer/Pipe.sol +9 -5
  53. package/peer/Settle.sol +9 -5
  54. package/queries/Assets.sol +4 -4
  55. package/queries/Balances.sol +4 -4
  56. package/queries/Base.sol +9 -8
  57. package/queries/Positions.sol +4 -5
package/peer/Debit.sol ADDED
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import { PeerBase } 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 IPeerDebitFrom {
11
+ function peerDebitFrom(bytes calldata request) external returns (bytes memory);
12
+ }
13
+
14
+ /// @title PeerDebitFrom
15
+ /// @notice Peer that lets a trusted peer debit supplied accounts directly.
16
+ /// Each ACCOUNT_AMOUNT block calls `debitAccount` for its account.
17
+ abstract contract PeerDebitFrom is PeerBase, DebitAccountHook, IPeerDebitFrom {
18
+ uint internal immutable peerDebitFromId = peerId(this.peerDebitFrom.selector);
19
+
20
+ constructor() {
21
+ emit Peer(host, peerDebitFromId, "1:0", Forms.AccountAmount, "", false);
22
+ emit Labeled(peerDebitFromId, bytes32(0), "peerDebitFrom");
23
+ }
24
+
25
+ /// @notice Execute the peer-debit call.
26
+ /// @param request ACCOUNT_AMOUNT block stream supplied by the trusted peer.
27
+ /// @return Empty response bytes.
28
+ function peerDebitFrom(bytes calldata request) external onlyPeer returns (bytes memory) {
29
+ (Cur memory amounts, , ) = Cursors.init(request, 1);
30
+
31
+ while (amounts.i < amounts.len) {
32
+ (bytes32 account, bytes32 asset, bytes32 meta, uint amount) = amounts.unpackAccountAmount();
33
+ debitAccount(account, asset, meta, amount);
34
+ }
35
+
36
+ amounts.complete();
37
+ return "";
38
+ }
39
+ }
@@ -7,22 +7,26 @@ import {Cursors, Cur, Schemas} from "../Cursors.sol";
7
7
 
8
8
  using Cursors for Cur;
9
9
 
10
+ interface IPeerDenyAssets {
11
+ function peerDenyAssets(bytes calldata request) external returns (bytes memory);
12
+ }
13
+
10
14
  /// @title PeerDenyAssets
11
15
  /// @notice Peer that blocks a list of (asset, meta) pairs on behalf of a peer host.
12
16
  /// Each ASSET block in the request calls `denyAsset`. Restricted to trusted peers.
13
- abstract contract PeerDenyAssets is PeerBase, DenyAssetsHook {
14
- string private constant NAME = "peerDenyAssets";
15
- uint internal immutable peerDenyAssetsId = peerId(NAME);
17
+ abstract contract PeerDenyAssets is PeerBase, DenyAssetsHook, IPeerDenyAssets {
18
+ uint internal immutable peerDenyAssetsId = peerId(this.peerDenyAssets.selector);
16
19
 
17
20
  constructor() {
18
- emit Peer(host, peerDenyAssetsId, NAME, "1:0", Schemas.Asset, "", false);
21
+ emit Peer(host, peerDenyAssetsId, "1:0", Schemas.Asset, "", false);
22
+ emit Labeled(peerDenyAssetsId, bytes32(0), "peerDenyAssets");
19
23
  }
20
24
 
21
25
  /// @notice Execute the deny-assets peer call.
22
26
  /// @param request ASSET block stream supplied by the trusted peer.
23
27
  /// @return Empty response bytes.
24
28
  function peerDenyAssets(bytes calldata request) external onlyPeer returns (bytes memory) {
25
- (Cur memory assets, , ) = Cursors.init(request, 0, 1);
29
+ (Cur memory assets, , ) = Cursors.init(request, 1);
26
30
 
27
31
  while (assets.i < assets.len) {
28
32
  (bytes32 asset, bytes32 meta) = assets.unpackAsset();
package/peer/Dispatch.sol CHANGED
@@ -9,14 +9,18 @@ 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);
14
+ }
15
+
12
16
  /// @title PeerDispatchPayable
13
17
  /// @notice Peer endpoint that forwards DISPATCH blocks to a host-defined dispatch hook.
14
- abstract contract PeerDispatchPayable is PeerBase, Payable, DispatchPayableHook {
15
- string private constant NAME = "peerDispatchPayable";
16
- uint internal immutable peerDispatchPayableId = peerId(NAME);
18
+ abstract contract PeerDispatchPayable is PeerBase, Payable, DispatchPayableHook, IPeerDispatchPayable {
19
+ uint internal immutable peerDispatchPayableId = peerId(this.peerDispatchPayable.selector);
17
20
 
18
21
  constructor() {
19
- emit Peer(host, peerDispatchPayableId, NAME, "1:0", Schemas.Dispatch, "", true);
22
+ emit Peer(host, peerDispatchPayableId, "1:0", Schemas.Dispatch, "", true);
23
+ emit Labeled(peerDispatchPayableId, bytes32(0), "peerDispatchPayable");
20
24
  }
21
25
 
22
26
  /// @notice Forward peer-supplied dispatches to the host-defined dispatch hook.
@@ -25,7 +29,7 @@ abstract contract PeerDispatchPayable is PeerBase, Payable, DispatchPayableHook
25
29
  /// @param request DISPATCH block stream supplied by the trusted peer.
26
30
  /// @return output Empty response bytes.
27
31
  function peerDispatchPayable(bytes calldata request) external payable onlyPeer returns (bytes memory output) {
28
- (Cur memory input, , ) = Cursors.init(request, 0, 1);
32
+ (Cur memory input, , ) = Cursors.init(request, 1);
29
33
  Budget memory budget = valueBudget();
30
34
 
31
35
  while (input.i < input.len) {
package/peer/Pipe.sol CHANGED
@@ -8,16 +8,20 @@ import {Budget} from "../utils/Value.sol";
8
8
 
9
9
  using Cursors for Cur;
10
10
 
11
+ interface IPeerPipePayable {
12
+ function peerPipePayable(bytes calldata request) external payable returns (bytes memory);
13
+ }
14
+
11
15
  /// @title PeerPipePayable
12
16
  /// @notice Peer that consumes PIPE blocks and executes each context step stream.
13
17
  /// Each PIPE block carries chain resources plus a CONTEXT block; the nested
14
18
  /// context steps are passed to the shared pipeline as the step stream.
15
- abstract contract PeerPipePayable is PeerBase, Pipeline {
16
- string private constant NAME = "peerPipePayable";
17
- uint internal immutable peerPipePayableId = peerId(NAME);
19
+ abstract contract PeerPipePayable is PeerBase, Pipeline, IPeerPipePayable {
20
+ uint internal immutable peerPipePayableId = peerId(this.peerPipePayable.selector);
18
21
 
19
22
  constructor() {
20
- emit Peer(host, peerPipePayableId, NAME, "1:0", Schemas.Pipe, "", true);
23
+ emit Peer(host, peerPipePayableId, "1:0", Schemas.Pipe, "", true);
24
+ emit Labeled(peerPipePayableId, bytes32(0), "peerPipePayable");
21
25
  }
22
26
 
23
27
  /// @notice Execute peer-supplied pipes through the shared payable pipe.
@@ -26,7 +30,7 @@ abstract contract PeerPipePayable is PeerBase, Pipeline {
26
30
  /// @param request PIPE block stream supplied by the trusted peer.
27
31
  /// @return Empty response bytes.
28
32
  function peerPipePayable(bytes calldata request) external payable onlyPeer returns (bytes memory) {
29
- (Cur memory input, , ) = Cursors.init(request, 0, 1);
33
+ (Cur memory input, , ) = Cursors.init(request, 1);
30
34
  Budget memory budget = valueBudget();
31
35
 
32
36
  while (input.i < input.len) {
package/peer/Settle.sol CHANGED
@@ -8,22 +8,26 @@ import { Cursors, Cur, Schemas } from "../Cursors.sol";
8
8
 
9
9
  using Cursors for Cur;
10
10
 
11
+ interface IPeerSettle {
12
+ function peerSettle(bytes calldata request) external returns (bytes memory);
13
+ }
14
+
11
15
  /// @title PeerSettle
12
16
  /// @notice Peer that consumes peer-supplied TRANSACTION blocks through debit and credit hooks.
13
17
  /// Each TRANSACTION block calls `debitAccount` for `from` and `creditAccount` for `to`.
14
- abstract contract PeerSettle is PeerBase, DebitAccountHook, CreditAccountHook {
15
- string private constant NAME = "peerSettle";
16
- uint internal immutable peerSettleId = peerId(NAME);
18
+ abstract contract PeerSettle is PeerBase, DebitAccountHook, CreditAccountHook, IPeerSettle {
19
+ uint internal immutable peerSettleId = peerId(this.peerSettle.selector);
17
20
 
18
21
  constructor() {
19
- emit Peer(host, peerSettleId, NAME, "1:0", Schemas.Transaction, "", false);
22
+ emit Peer(host, peerSettleId, "1:0", Schemas.Transaction, "", false);
23
+ emit Labeled(peerSettleId, bytes32(0), "peerSettle");
20
24
  }
21
25
 
22
26
  /// @notice Execute the peer-settle call.
23
27
  /// @param request TRANSACTION block stream supplied by the trusted peer.
24
28
  /// @return Empty response bytes.
25
29
  function peerSettle(bytes calldata request) external onlyPeer returns (bytes memory) {
26
- (Cur memory state, , ) = Cursors.init(request, 0, 1);
30
+ (Cur memory state, , ) = Cursors.init(request, 1);
27
31
 
28
32
  while (state.i < state.len) {
29
33
  (bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount) = state.unpackTransaction();
@@ -22,18 +22,18 @@ abstract contract AssetStatusHook {
22
22
  /// The request is a run of `ASSET` blocks.
23
23
  /// The response returns one `STATUS` form block per query entry, preserving request order.
24
24
  abstract contract AssetStatus is QueryBase, AssetStatusHook {
25
- string private constant NAME = "assetStatus";
26
- uint public immutable assetStatusId = queryId(NAME);
25
+ uint public immutable assetStatusId = queryId(this.assetStatus.selector);
27
26
 
28
27
  constructor() {
29
- emit Query(host, assetStatusId, NAME, "1:1", Schemas.Asset, Forms.Status);
28
+ emit Query(host, assetStatusId, "1:1", Schemas.Asset, Forms.Status);
29
+ emit Labeled(assetStatusId, bytes32(0), "assetStatus");
30
30
  }
31
31
 
32
32
  /// @notice Resolve asset support status for a run of requested `(asset, meta)` tuples.
33
33
  /// @param request Block-stream request consisting of `#asset { bytes32 asset, bytes32 meta }` blocks.
34
34
  /// @return Block-stream response containing one `#status { uint code }` per asset block.
35
35
  function assetStatus(bytes calldata request) external view returns (bytes memory) {
36
- (Cur memory query, uint groups, ) = Cursors.init(request, 0, 1);
36
+ (Cur memory query, uint groups, ) = Cursors.init(request, 1);
37
37
  Writer memory response = Writers.allocStatuses(groups);
38
38
 
39
39
  while (query.i < query.len) {
@@ -22,18 +22,18 @@ abstract contract GetBalancesHook {
22
22
  /// The request is a run of `ACCOUNT_ASSET` form blocks.
23
23
  /// The response returns one `ACCOUNT_AMOUNT` form block per requested position, preserving request order.
24
24
  abstract contract GetBalances is QueryBase, GetBalancesHook {
25
- string private constant NAME = "getBalances";
26
- uint public immutable getBalancesId = queryId(NAME);
25
+ uint public immutable getBalancesId = queryId(this.getBalances.selector);
27
26
 
28
27
  constructor() {
29
- emit Query(host, getBalancesId, NAME, "1:1", Forms.AccountAsset, Forms.AccountAmount);
28
+ emit Query(host, getBalancesId, "1:1", Forms.AccountAsset, Forms.AccountAmount);
29
+ emit Labeled(getBalancesId, bytes32(0), "getBalances");
30
30
  }
31
31
 
32
32
  /// @notice Resolve balances for a run of requested `(account, asset, meta)` tuples.
33
33
  /// @param request Block-stream request consisting of `accountAsset(account, asset, meta)*`.
34
34
  /// @return Block-stream response containing one `accountAmount(account, asset, meta, amount)` block per request block.
35
35
  function getBalances(bytes calldata request) external view returns (bytes memory) {
36
- (Cur memory query, uint groups, ) = Cursors.init(request, 0, 1);
36
+ (Cur memory query, uint groups, ) = Cursors.init(request, 1);
37
37
  Writer memory response = Writers.allocAccountAmounts(groups);
38
38
 
39
39
  while (query.i < query.len) {
package/queries/Base.sol CHANGED
@@ -2,8 +2,9 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import { Runtime } from "../core/Runtime.sol";
5
+ import { LabeledEvent } from "../events/Labeled.sol";
5
6
  import { QueryEvent } from "../events/Query.sol";
6
- import { Ids, Selectors } from "../utils/Ids.sol";
7
+ import { Ids } from "../utils/Ids.sol";
7
8
 
8
9
  /// @notice ABI-encode a query call from a target query ID and request block stream.
9
10
  /// @dev Derives the function selector from `target` via `Ids.querySelector(target)`.
@@ -20,14 +21,14 @@ function encodeQueryCall(uint target, bytes calldata request) pure returns (byte
20
21
  /// @notice Abstract base for rootzero query contracts.
21
22
  /// Queries are view-only entry points that consume a block-stream request and
22
23
  /// return a block-stream response.
23
- abstract contract QueryBase is Runtime, QueryEvent {
24
+ abstract contract QueryBase is Runtime, QueryEvent, LabeledEvent {
24
25
 
25
- /// @notice Derive the deterministic node ID for a named query on this contract.
26
- /// The ID encodes the ABI selector of `name(bytes)` and `address(this)`,
27
- /// making it unique per (function name, contract address) pair.
28
- /// @param name Query function name (without argument list).
26
+ /// @notice Derive the deterministic node ID for a query selector on this contract.
27
+ /// The ID encodes the ABI selector and `address(this)`, making it unique
28
+ /// per (function selector, contract address) pair.
29
+ /// @param selector Query entrypoint selector.
29
30
  /// @return Query node ID.
30
- function queryId(string memory name) internal view returns (uint) {
31
- return Ids.toQuery(Selectors.query(name), address(this));
31
+ function queryId(bytes4 selector) internal view returns (uint) {
32
+ return Ids.toQuery(selector, address(this));
32
33
  }
33
34
  }
@@ -29,12 +29,11 @@ abstract contract GetPositionHook {
29
29
  /// The request is a run of `ACCOUNT_ASSET` form blocks.
30
30
  /// The response returns one output-schema block per position entry, preserving request order.
31
31
  abstract contract GetPosition is QueryBase, GetPositionHook {
32
- string private constant NAME = "getPosition";
33
-
34
- uint public immutable getPositionId = queryId(NAME);
32
+ uint public immutable getPositionId = queryId(this.getPosition.selector);
35
33
 
36
34
  constructor(string memory output) {
37
- emit Query(host, getPositionId, NAME, "1:1", Forms.AccountAsset, output);
35
+ emit Query(host, getPositionId, "1:1", Forms.AccountAsset, output);
36
+ emit Labeled(getPositionId, bytes32(0), "getPosition");
38
37
  }
39
38
 
40
39
  /// @notice Resolve positions for a run of requested `(account, asset, meta)` tuples.
@@ -42,7 +41,7 @@ abstract contract GetPosition is QueryBase, GetPositionHook {
42
41
  /// @param request Block-stream request consisting of `accountAsset(account, asset, meta)*`.
43
42
  /// @return Block-stream response containing one output-schema block per position block.
44
43
  function getPosition(bytes calldata request) external view returns (bytes memory) {
45
- (Cur memory query, uint groups, ) = Cursors.init(request, 0, 1);
44
+ (Cur memory query, uint groups, ) = Cursors.init(request, 1);
46
45
  Writer memory response = Writers.allocAny(groups);
47
46
 
48
47
  while (query.i < query.len) {