@rootzero/contracts 1.5.0 → 1.6.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,22 @@
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.6.0
7
+
8
+ ### Added
9
+
10
+ - Added `AdminBase` as the shared base for admin commands and exported it from
11
+ `Endpoints.sol`.
12
+ - Added `Cursors.read1` and `Cursors.read2` for unchecked byte-sized calldata
13
+ reads.
14
+ - Added `NativeAsset` as a reusable base for helpers that need the local native
15
+ asset ID without the full host runtime.
16
+ - Added `Escrows` as a keyed ledger for amounts reserved outside normal
17
+ balances.
18
+ - Added `Commitment(bytes32 indexed account, bytes32 key, bytes32 digest, uint status)`
19
+ and the `Commitments` core mixin for digest commitments and witness/recovery
20
+ flows.
21
+
6
22
  ## 1.5.0
7
23
 
8
24
  ### Breaking Changes
package/Core.sol CHANGED
@@ -1,12 +1,14 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- // Aggregator: re-exports the core host, runtime, access, node-call, and validation layer.
4
+ // Aggregator: re-exports the core host, runtime, access, ledger, node-call, and validation layer.
5
5
  // Import this file to bring the full rootzero host base layer into scope.
6
6
 
7
7
  import { AccessControl } from "./core/Access.sol";
8
8
  import { Balances, InsufficientFunds } from "./core/Balances.sol";
9
- import { Runtime } from "./core/Runtime.sol";
9
+ import { Commitments } from "./core/Commitments.sol";
10
+ import { Escrows, InsufficientEscrow } from "./core/Escrows.sol";
11
+ import { NativeAsset, Runtime } from "./core/Runtime.sol";
10
12
  import { Host, IHostIntroduction } from "./core/Host.sol";
11
13
  import { FailedCall, NodeCalls } from "./core/Calls.sol";
12
14
  import { Payable } from "./core/Payable.sol";
package/Endpoints.sol CHANGED
@@ -20,6 +20,7 @@ import { RelayPayable, DispatchPayableHook } from "./commands/Relay.sol";
20
20
  import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
21
21
 
22
22
  // Admin commands
23
+ import { AdminBase } from "./commands/admin/Base.sol";
23
24
  import { AllowAssets, AllowAssetsHook } from "./commands/admin/AllowAssets.sol";
24
25
  import { Allowance, AllowanceHook } from "./commands/admin/Allowance.sol";
25
26
  import { Appoint } from "./commands/admin/Appoint.sol";
package/Events.sol CHANGED
@@ -10,6 +10,7 @@ import { Actions } from "./utils/Actions.sol";
10
10
  import { BalanceEvent } from "./events/Balance.sol";
11
11
  import { CommanderEvent } from "./events/Commander.sol";
12
12
  import { CommandEvent } from "./events/Command.sol";
13
+ import { CommitmentEvent } from "./events/Commitment.sol";
13
14
  import { PositionEvent } from "./events/Position.sol";
14
15
  import { ReceivedEvent } from "./events/Received.sol";
15
16
  import { EventEmitter } from "./events/Emitter.sol";
@@ -599,6 +599,30 @@ library Cursors {
599
599
  cur.i += n;
600
600
  }
601
601
 
602
+ /// @notice Read the next byte from the cursor and advance by 1 byte.
603
+ /// @dev Performs no bounds, key, length, or cursor checks.
604
+ /// @param cur Cursor whose current position is advanced by 1 byte.
605
+ /// @return value Loaded bytes1 value.
606
+ function read1(Cur memory cur) internal pure returns (bytes1 value) {
607
+ uint abs = cur.offset + cur.i;
608
+ assembly ("memory-safe") {
609
+ value := calldataload(abs)
610
+ }
611
+ cur.i += 1;
612
+ }
613
+
614
+ /// @notice Read the next 2 bytes from the cursor and advance by 2 bytes.
615
+ /// @dev Performs no bounds, key, length, or cursor checks.
616
+ /// @param cur Cursor whose current position is advanced by 2 bytes.
617
+ /// @return value Loaded bytes2 value.
618
+ function read2(Cur memory cur) internal pure returns (bytes2 value) {
619
+ uint abs = cur.offset + cur.i;
620
+ assembly ("memory-safe") {
621
+ value := calldataload(abs)
622
+ }
623
+ cur.i += 2;
624
+ }
625
+
602
626
  /// @notice Read the next 4 bytes from the cursor and advance by 4 bytes.
603
627
  /// @dev Performs no bounds, key, length, or cursor checks.
604
628
  /// @param cur Cursor whose current position is advanced by 4 bytes.
@@ -1,9 +1,8 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  abstract contract AllowAssetsHook {
@@ -16,7 +15,7 @@ abstract contract AllowAssetsHook {
16
15
  /// @title AllowAssets
17
16
  /// @notice Admin command that permits a list of assets via a virtual hook.
18
17
  /// Each ASSET block in the request calls `allowAsset`. Only callable by the admin account.
19
- abstract contract AllowAssets is CommandBase, AdminEvent, AllowAssetsHook {
18
+ abstract contract AllowAssets is AdminBase, AllowAssetsHook {
20
19
  uint internal immutable allowAssetsId = commandId(this.allowAssets.selector);
21
20
 
22
21
  constructor() {
@@ -1,9 +1,8 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {CommandBase, CommandContext, Keys} from "../Base.sol";
4
+ import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
5
  import {Cursors, Cur, Schemas} from "../../Cursors.sol";
6
- import {AdminEvent} from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  abstract contract AllowanceHook {
@@ -20,7 +19,7 @@ abstract contract AllowanceHook {
20
19
  /// @title Allowance
21
20
  /// @notice Admin command that applies cross-host allowance entries via a virtual hook.
22
21
  /// Each ALLOWANCE block grants or updates a host-scoped asset cap. Only callable by the admin account.
23
- abstract contract Allowance is CommandBase, AdminEvent, AllowanceHook {
22
+ abstract contract Allowance is AdminBase, AllowanceHook {
24
23
  uint internal immutable allowanceId = commandId(this.allowance.selector);
25
24
 
26
25
  constructor() {
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  /// @title Appoint
10
9
  /// @notice Admin command that grants guardian status to a list of account IDs.
11
10
  /// Each ACCOUNT block in the request is enabled as a guardian on the host.
12
11
  /// Only callable by the admin account.
13
- abstract contract Appoint is CommandBase, AdminEvent {
12
+ abstract contract Appoint is AdminBase {
14
13
  uint internal immutable appointId = commandId(this.appoint.selector);
15
14
 
16
15
  constructor() {
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  /// @title Authorize
10
9
  /// @notice Admin command that grants authorization to a list of node IDs.
11
10
  /// Each NODE block in the request is authorized on the host.
12
11
  /// Only callable by the admin account.
13
- abstract contract Authorize is CommandBase, AdminEvent {
12
+ abstract contract Authorize is AdminBase {
14
13
  uint internal immutable authorizeId = commandId(this.authorize.selector);
15
14
 
16
15
  constructor() {
@@ -0,0 +1,9 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {CommandBase, CommandContext, Keys} from "../Base.sol";
5
+ import {AdminEvent} from "../../events/Admin.sol";
6
+
7
+ /// @title AdminBase
8
+ /// @notice Shared base for admin commands.
9
+ abstract contract AdminBase is CommandBase, AdminEvent {}
@@ -1,9 +1,8 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  abstract contract DenyAssetsHook {
@@ -16,7 +15,7 @@ abstract contract DenyAssetsHook {
16
15
  /// @title DenyAssets
17
16
  /// @notice Admin command that blocks a list of assets via a virtual hook.
18
17
  /// Each ASSET block in the request calls `denyAsset`. Only callable by the admin account.
19
- abstract contract DenyAssets is CommandBase, AdminEvent, DenyAssetsHook {
18
+ abstract contract DenyAssets is AdminBase, DenyAssetsHook {
20
19
  uint internal immutable denyAssetsId = commandId(this.denyAssets.selector);
21
20
 
22
21
  constructor() {
@@ -1,9 +1,8 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
 
8
7
  using Cursors for Cur;
9
8
 
@@ -16,7 +15,7 @@ abstract contract DestroyHook {
16
15
  /// @title Destroy
17
16
  /// @notice Admin command that runs host teardown logic via a virtual hook.
18
17
  /// The full request is passed to `destroy` as a cursor. Only callable by the admin account.
19
- abstract contract Destroy is CommandBase, AdminEvent, DestroyHook {
18
+ abstract contract Destroy is AdminBase, DestroyHook {
20
19
  uint internal immutable destroyId = commandId(this.destroy.selector);
21
20
 
22
21
  constructor(string memory input) {
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  /// @title Dismiss
10
9
  /// @notice Admin command that revokes guardian status from a list of account IDs.
11
10
  /// Each ACCOUNT block in the request is disabled as a guardian on the host.
12
11
  /// Only callable by the admin account.
13
- abstract contract Dismiss is CommandBase, AdminEvent {
12
+ abstract contract Dismiss is AdminBase {
14
13
  uint internal immutable dismissId = commandId(this.dismiss.selector);
15
14
 
16
15
  constructor() {
@@ -1,10 +1,9 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {CommandBase, CommandContext, Keys} from "../Base.sol";
4
+ import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
5
  import {Payable} from "../../core/Payable.sol";
6
6
  import {Cursors, Cur, Schemas} from "../../Cursors.sol";
7
- import {AdminEvent} from "../../events/Admin.sol";
8
7
  import {Budget} from "../../utils/Value.sol";
9
8
  import {Nodes} from "../../utils/Nodes.sol";
10
9
 
@@ -15,7 +14,7 @@ using Cursors for Cur;
15
14
  /// Each CALL block specifies a target node ID, chain resources, and raw calldata payload.
16
15
  /// Only callable by the admin account.
17
16
  /// Unspent top-level `msg.value` remains on this host.
18
- abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
17
+ abstract contract ExecutePayable is AdminBase, Payable {
19
18
  uint internal immutable executePayableId = commandId(this.executePayable.selector);
20
19
 
21
20
  constructor() {
@@ -1,9 +1,8 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
 
8
7
  using Cursors for Cur;
9
8
 
@@ -16,7 +15,7 @@ abstract contract InitHook {
16
15
  /// @title Init
17
16
  /// @notice Admin command that runs host initialization logic via a virtual hook.
18
17
  /// The full request is passed to `init` as a cursor. Only callable by the admin account.
19
- abstract contract Init is CommandBase, AdminEvent, InitHook {
18
+ abstract contract Init is AdminBase, InitHook {
20
19
  uint internal immutable initId = commandId(this.init.selector);
21
20
 
22
21
  constructor(string memory input) {
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {CommandBase, CommandContext, Keys} from "../Base.sol";
4
+ import {AdminBase, CommandContext, Keys} from "./Base.sol";
5
5
  import {Cursors, Cur, Schemas} from "../../Cursors.sol";
6
- import {AdminEvent} from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  /// @title Label
10
9
  /// @notice Admin command that publishes namespaced labels for node IDs.
11
10
  /// Each LABEL block in the request emits one `Labeled` event. Only callable by
12
11
  /// the admin account.
13
- abstract contract Label is CommandBase, AdminEvent {
12
+ abstract contract Label is AdminBase {
14
13
  uint internal immutable labelId = commandId(this.label.selector);
15
14
 
16
15
  constructor() {
@@ -1,16 +1,15 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "../Base.sol";
4
+ import { AdminBase, CommandContext, Keys } from "./Base.sol";
5
5
  import { Cursors, Cur, Schemas } from "../../Cursors.sol";
6
- import { AdminEvent } from "../../events/Admin.sol";
7
6
  using Cursors for Cur;
8
7
 
9
8
  /// @title Unauthorize
10
9
  /// @notice Admin command that revokes authorization from a list of node IDs.
11
10
  /// Each NODE block in the request is deauthorized on the host.
12
11
  /// Only callable by the admin account.
13
- abstract contract Unauthorize is CommandBase, AdminEvent {
12
+ abstract contract Unauthorize is AdminBase {
14
13
  uint internal immutable unauthorizeId = commandId(this.unauthorize.selector);
15
14
 
16
15
  constructor() {
@@ -0,0 +1,19 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {CommitmentEvent} from "../events/Commitment.sol";
5
+
6
+ /// @title Commitments
7
+ /// @notice On-chain registry for account-scoped digest commitments.
8
+ abstract contract Commitments is CommitmentEvent {
9
+ /// @dev key -> committed digest.
10
+ mapping(bytes32 key => bytes32 digest) internal commitments;
11
+
12
+ /// @notice Clear the commitment under `key` and return the removed digest.
13
+ /// @param key Commitment lookup key.
14
+ /// @return digest Removed digest.
15
+ function uncommit(bytes32 key) internal returns (bytes32 digest) {
16
+ digest = commitments[key];
17
+ delete commitments[key];
18
+ }
19
+ }
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ /// @dev Thrown when a debit would reduce an escrow below zero.
5
+ error InsufficientEscrow();
6
+
7
+ /// @title Escrows
8
+ /// @notice On-chain ledger for amounts reserved outside normal spendable balances.
9
+ abstract contract Escrows {
10
+ /// @dev key -> escrowed amount.
11
+ mapping(bytes32 key => uint amount) internal escrows;
12
+
13
+ /// @notice Add `amount` to an escrow and return the new balance.
14
+ /// @param key Escrow key derived by the caller.
15
+ /// @param amount Amount to reserve.
16
+ /// @return balance New escrow balance after the credit.
17
+ function creditEscrow(bytes32 key, uint amount) internal returns (uint balance) {
18
+ balance = escrows[key] += amount;
19
+ }
20
+
21
+ /// @notice Deduct `amount` from an escrow and return the new balance.
22
+ /// Reverts with `InsufficientEscrow` if the current balance is less than `amount`.
23
+ /// @param key Escrow key derived by the caller.
24
+ /// @param amount Amount to release.
25
+ /// @return balance New escrow balance after the debit.
26
+ function debitEscrow(bytes32 key, uint amount) internal returns (uint balance) {
27
+ balance = escrows[key];
28
+ if (balance < amount) revert InsufficientEscrow();
29
+ unchecked {
30
+ balance -= amount;
31
+ }
32
+ escrows[key] = balance;
33
+ }
34
+ }
package/core/Runtime.sol CHANGED
@@ -4,11 +4,16 @@ pragma solidity ^0.8.33;
4
4
  import {Assets} from "../utils/Assets.sol";
5
5
  import {Nodes} from "../utils/Nodes.sol";
6
6
 
7
+ /// @title NativeAsset
8
+ /// @notice Shared native asset identity for host helpers.
9
+ abstract contract NativeAsset {
10
+ /// @dev Asset ID for the native chain coin/token, bound to the current chain at deployment.
11
+ bytes32 internal immutable nativeAsset = Assets.toNative();
12
+ }
13
+
7
14
  /// @title Runtime
8
15
  /// @notice Shared runtime for host identity and native asset identity.
9
- abstract contract Runtime {
16
+ abstract contract Runtime is NativeAsset {
10
17
  /// @dev This contract's host node ID, set to `Nodes.toHost(address(this))` at construction.
11
18
  uint public immutable host = Nodes.toHost(address(this));
12
- /// @dev Asset ID for the native chain coin/token, bound to the current chain at deployment.
13
- bytes32 internal immutable nativeAsset = Assets.toNative();
14
19
  }
@@ -0,0 +1,19 @@
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-scoped commitment is updated.
7
+ abstract contract CommitmentEvent is EventEmitter {
8
+ string private constant ABI = "event Commitment(bytes32 indexed account, bytes32 key, bytes32 digest, uint status)";
9
+
10
+ /// @param account Account associated with the commitment.
11
+ /// @param key Commitment lookup key.
12
+ /// @param digest Committed digest. Zero may be used when clearing without revealing the previous digest.
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);
15
+
16
+ constructor() {
17
+ emit EventAbi(ABI);
18
+ }
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootzero/contracts",
3
- "version": "1.5.0",
3
+ "version": "1.6.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",