@rootzero/contracts 1.4.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/Core.sol +4 -2
  3. package/Endpoints.sol +5 -3
  4. package/Events.sol +2 -1
  5. package/README.md +58 -31
  6. package/Utils.sol +4 -3
  7. package/blocks/Cursors.sol +107 -143
  8. package/blocks/Keys.sol +15 -15
  9. package/blocks/Schema.sol +27 -28
  10. package/blocks/Writers.sol +26 -33
  11. package/commands/Base.sol +2 -2
  12. package/commands/Burn.sol +3 -4
  13. package/commands/Credit.sol +3 -4
  14. package/commands/Debit.sol +4 -5
  15. package/commands/Deposit.sol +8 -10
  16. package/commands/Payout.sol +3 -6
  17. package/commands/Withdraw.sol +3 -4
  18. package/commands/admin/AllowAssets.sol +7 -9
  19. package/commands/admin/Allowance.sol +5 -7
  20. package/commands/admin/Appoint.sol +2 -3
  21. package/commands/admin/Authorize.sol +2 -3
  22. package/commands/admin/Base.sol +9 -0
  23. package/commands/admin/DenyAssets.sol +7 -9
  24. package/commands/admin/Destroy.sol +2 -3
  25. package/commands/admin/Dismiss.sol +2 -3
  26. package/commands/admin/Execute.sol +4 -5
  27. package/commands/admin/Init.sol +2 -3
  28. package/commands/admin/Label.sol +2 -3
  29. package/commands/admin/Unauthorize.sol +2 -3
  30. package/core/Access.sol +2 -2
  31. package/core/Balances.sol +10 -11
  32. package/core/Calls.sol +7 -7
  33. package/core/Commitments.sol +19 -0
  34. package/core/Escrows.sol +34 -0
  35. package/core/Host.sol +2 -2
  36. package/core/Runtime.sol +11 -6
  37. package/core/Types.sol +0 -14
  38. package/docs/Schema.md +29 -10
  39. package/events/Asset.sol +17 -3
  40. package/events/Balance.sol +2 -3
  41. package/events/Commitment.sol +19 -0
  42. package/events/Locked.sol +2 -3
  43. package/events/Position.sol +2 -3
  44. package/events/Received.sol +2 -3
  45. package/events/Spent.sol +2 -3
  46. package/events/Unlocked.sol +2 -3
  47. package/guards/Base.sol +4 -4
  48. package/package.json +1 -1
  49. package/peer/AllowAssets.sol +3 -3
  50. package/peer/Allowance.sol +2 -2
  51. package/peer/Base.sol +4 -4
  52. package/peer/Credit.sol +10 -10
  53. package/peer/Debit.sol +10 -10
  54. package/peer/DenyAssets.sol +3 -3
  55. package/peer/Recover.sol +51 -0
  56. package/peer/Redeem.sol +48 -0
  57. package/peer/Settle.sol +3 -3
  58. package/queries/Assets.sol +7 -8
  59. package/queries/Balances.sol +8 -9
  60. package/queries/Base.sol +4 -4
  61. package/queries/Positions.sol +4 -6
  62. package/utils/Accounts.sol +76 -58
  63. package/utils/Assets.sol +55 -115
  64. package/utils/Ids.sol +33 -233
  65. package/utils/Layout.sol +11 -17
  66. package/utils/Nodes.sol +263 -0
  67. package/utils/Utils.sol +9 -24
  68. package/peer/BalancePull.sol +0 -49
@@ -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,23 +1,21 @@
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 {
10
- /// @dev Override to deny a single asset/meta pair.
9
+ /// @dev Override to deny a single asset.
11
10
  /// Called once per ASSET block in the request.
12
11
  /// @param asset Asset identifier.
13
- /// @param meta Asset metadata slot.
14
- function denyAsset(bytes32 asset, bytes32 meta) internal virtual;
12
+ function denyAsset(bytes32 asset) internal virtual;
15
13
  }
16
14
 
17
15
  /// @title DenyAssets
18
- /// @notice Admin command that blocks a list of (asset, meta) pairs via a virtual hook.
16
+ /// @notice Admin command that blocks a list of assets via a virtual hook.
19
17
  /// Each ASSET block in the request calls `denyAsset`. Only callable by the admin account.
20
- abstract contract DenyAssets is CommandBase, AdminEvent, DenyAssetsHook {
18
+ abstract contract DenyAssets is AdminBase, DenyAssetsHook {
21
19
  uint internal immutable denyAssetsId = commandId(this.denyAssets.selector);
22
20
 
23
21
  constructor() {
@@ -34,8 +32,8 @@ abstract contract DenyAssets is CommandBase, AdminEvent, DenyAssetsHook {
34
32
  (Cur memory request, , ) = Cursors.init(c.request, 1);
35
33
 
36
34
  while (request.i < request.len) {
37
- (bytes32 asset, bytes32 meta) = request.unpackAsset();
38
- denyAsset(asset, meta);
35
+ bytes32 asset = request.unpackAsset();
36
+ denyAsset(asset);
39
37
  }
40
38
 
41
39
  request.complete();
@@ -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,12 +1,11 @@
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
- import {Ids} from "../../utils/Ids.sol";
8
+ import {Nodes} from "../../utils/Nodes.sol";
10
9
 
11
10
  using Cursors for Cur;
12
11
 
@@ -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() {
@@ -32,7 +31,7 @@ abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
32
31
 
33
32
  while (request.i < request.len) {
34
33
  (uint target, uint resources, bytes calldata data) = request.unpackCall();
35
- address addr = Ids.nodeAddr(target);
34
+ address addr = Nodes.addr(target);
36
35
  callAddr(addr, useValue(budget, resources), data);
37
36
  }
38
37
 
@@ -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() {
package/core/Access.sol CHANGED
@@ -5,7 +5,7 @@ import {NodeEvent} from "../events/Node.sol";
5
5
  import {GuardianEvent} from "../events/Guardian.sol";
6
6
  import {Runtime} from "./Runtime.sol";
7
7
  import {Accounts} from "../utils/Accounts.sol";
8
- import {Ids} from "../utils/Ids.sol";
8
+ import {Nodes} from "../utils/Nodes.sol";
9
9
  import {addrOr} from "../utils/Utils.sol";
10
10
 
11
11
  /// @title AccessControl
@@ -63,7 +63,7 @@ abstract contract AccessControl is Runtime, NodeEvent, GuardianEvent {
63
63
  /// whose host ID has been explicitly authorized.
64
64
  /// @param caller Address to check.
65
65
  function isTrusted(address caller) internal view returns (bool) {
66
- return caller == commander || caller == address(this) || nodes[Ids.toHost(caller)];
66
+ return caller == commander || caller == address(this) || nodes[Nodes.toHost(caller)];
67
67
  }
68
68
 
69
69
  /// @notice Assert that `node` is in the trusted set and return it.
package/core/Balances.sol CHANGED
@@ -7,33 +7,32 @@ import {BalanceEvent} from "../events/Balance.sol";
7
7
  error InsufficientFunds();
8
8
 
9
9
  /// @title Balances
10
- /// @notice On-chain ledger for per-account, per-slot balances.
11
- /// Higher-level modules decide how slots are derived and validated.
10
+ /// @notice On-chain ledger for per-account, per-asset balances.
12
11
  abstract contract Balances is BalanceEvent {
13
- /// @dev account -> slot -> balance.
14
- mapping(bytes32 account => mapping(bytes32 slot => uint amount)) internal balances;
12
+ /// @dev account -> asset -> balance.
13
+ mapping(bytes32 account => mapping(bytes32 asset => uint amount)) internal balances;
15
14
 
16
15
  /// @notice Add `amount` to an account balance and return the new balance.
17
16
  /// @param account Account identifier.
18
- /// @param slot Storage slot for the position being credited.
17
+ /// @param asset Unique asset identifier for the position being credited.
19
18
  /// @param amount Amount to credit.
20
19
  /// @return balance New balance after the credit.
21
- function creditTo(bytes32 account, bytes32 slot, uint amount) internal returns (uint balance) {
22
- balance = balances[account][slot] += amount;
20
+ function creditTo(bytes32 account, bytes32 asset, uint amount) internal returns (uint balance) {
21
+ balance = balances[account][asset] += amount;
23
22
  }
24
23
 
25
24
  /// @notice Deduct `amount` from an account balance and return the new balance.
26
25
  /// Reverts with `InsufficientFunds` if the current balance is less than `amount`.
27
26
  /// @param account Account identifier.
28
- /// @param slot Storage slot for the position being debited.
27
+ /// @param asset Unique asset identifier for the position being debited.
29
28
  /// @param amount Amount to deduct.
30
29
  /// @return balance New balance after the debit.
31
- function debitFrom(bytes32 account, bytes32 slot, uint amount) internal returns (uint balance) {
32
- balance = balances[account][slot];
30
+ function debitFrom(bytes32 account, bytes32 asset, uint amount) internal returns (uint balance) {
31
+ balance = balances[account][asset];
33
32
  if (balance < amount) revert InsufficientFunds();
34
33
  unchecked {
35
34
  balance -= amount;
36
35
  }
37
- balances[account][slot] = balance;
36
+ balances[account][asset] = balance;
38
37
  }
39
38
  }
package/core/Calls.sol CHANGED
@@ -3,7 +3,7 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import {AccessControl} from "./Access.sol";
5
5
  import {CommandContext} from "../commands/Base.sol";
6
- import {Ids} from "../utils/Ids.sol";
6
+ import {Nodes} from "../utils/Nodes.sol";
7
7
 
8
8
  /// @dev Emitted when a trusted inter-node call fails.
9
9
  /// @param addr Contract address that was called.
@@ -18,7 +18,7 @@ abstract contract NodeCalls is AccessControl {
18
18
  /// @dev Encodes `msg.sender` as a host ID using the local-chain host layout.
19
19
  /// @return Host node ID for `msg.sender`.
20
20
  function caller() internal view returns (uint) {
21
- return Ids.toHost(msg.sender);
21
+ return Nodes.toHost(msg.sender);
22
22
  }
23
23
 
24
24
  /// @notice Make a low-level call to an address.
@@ -47,7 +47,7 @@ abstract contract NodeCalls is AccessControl {
47
47
  }
48
48
 
49
49
  /// @notice Make a trusted call to another node in the network.
50
- /// Looks up the node's contract address via `ensureTrusted` + `Ids.nodeAddr`,
50
+ /// Looks up the node's contract address via `ensureTrusted` + `Nodes.addr`,
51
51
  /// then issues a low-level call forwarding `value` ETH and `data`.
52
52
  /// @param node Node ID of the callee (must be in the authorized set).
53
53
  /// @param value Native value to forward in wei.
@@ -55,19 +55,19 @@ abstract contract NodeCalls is AccessControl {
55
55
  /// @return out Return data from the successful call.
56
56
  function callTo(uint node, uint128 value, bytes memory data) internal returns (bytes memory out) {
57
57
  ensureTrusted(node);
58
- address addr = Ids.nodeAddr(node);
58
+ address addr = Nodes.addr(node);
59
59
  return callAddr(addr, value, data);
60
60
  }
61
61
 
62
62
  /// @notice Make a trusted query to another node in the network.
63
- /// Looks up the node's contract address via `ensureTrusted` + `Ids.nodeAddr`,
63
+ /// Looks up the node's contract address via `ensureTrusted` + `Nodes.addr`,
64
64
  /// then issues a low-level `staticcall` with `data`.
65
65
  /// @param node Node ID of the callee (must be in the authorized set).
66
66
  /// @param data Encoded calldata to send.
67
67
  /// @return out Return data from the successful query.
68
68
  function queryTo(uint node, bytes memory data) internal view returns (bytes memory out) {
69
69
  ensureTrusted(node);
70
- address addr = Ids.nodeAddr(node);
70
+ address addr = Nodes.addr(node);
71
71
  return queryAddr(addr, data);
72
72
  }
73
73
 
@@ -77,7 +77,7 @@ abstract contract NodeCalls is AccessControl {
77
77
  /// @param ctx Command execution context.
78
78
  /// @return Decoded command output block stream.
79
79
  function callCommand(uint id, uint128 value, CommandContext memory ctx) internal returns (bytes memory) {
80
- bytes4 selector = Ids.commandSelector(id);
80
+ bytes4 selector = Nodes.commandSelector(id);
81
81
  bytes memory data = abi.encodeWithSelector(selector, ctx);
82
82
  return abi.decode(callTo(id, value, data), (bytes));
83
83
  }
@@ -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/Host.sol CHANGED
@@ -10,7 +10,7 @@ import {ExecutePayable} from "../commands/admin/Execute.sol";
10
10
  import {Label} from "../commands/admin/Label.sol";
11
11
  import {Revoke} from "../guards/Revoke.sol";
12
12
  import {IntroductionEvent} from "../events/Introduction.sol";
13
- import {Ids} from "../utils/Ids.sol";
13
+ import {Nodes} from "../utils/Nodes.sol";
14
14
 
15
15
  /// @title IHostIntroduction
16
16
  /// @notice Interface implemented by hosts that accept introductions from other hosts.
@@ -51,7 +51,7 @@ abstract contract Host is
51
51
  /// @param peer Host node ID being introduced.
52
52
  /// @param blocknum Block number at which the host was deployed.
53
53
  function introduce(uint peer, uint blocknum) external {
54
- emit Introduction(Ids.matchHost(peer, msg.sender), blocknum);
54
+ emit Introduction(Nodes.matchHost(peer, msg.sender), blocknum);
55
55
  }
56
56
 
57
57
  /// @notice Accept native ETH transfers (e.g. from command value flows).
package/core/Runtime.sol CHANGED
@@ -2,13 +2,18 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {Assets} from "../utils/Assets.sol";
5
- import {Ids} from "../utils/Ids.sol";
5
+ import {Nodes} from "../utils/Nodes.sol";
6
6
 
7
- /// @title Runtime
8
- /// @notice Shared runtime for host identity and native asset identity.
9
- abstract contract Runtime {
10
- /// @dev This contract's host node ID, set to `Ids.toHost(address(this))` at construction.
11
- uint public immutable host = Ids.toHost(address(this));
7
+ /// @title NativeAsset
8
+ /// @notice Shared native asset identity for host helpers.
9
+ abstract contract NativeAsset {
12
10
  /// @dev Asset ID for the native chain coin/token, bound to the current chain at deployment.
13
11
  bytes32 internal immutable nativeAsset = Assets.toNative();
14
12
  }
13
+
14
+ /// @title Runtime
15
+ /// @notice Shared runtime for host identity and native asset identity.
16
+ abstract contract Runtime is NativeAsset {
17
+ /// @dev This contract's host node ID, set to `Nodes.toHost(address(this))` at construction.
18
+ uint public immutable host = Nodes.toHost(address(this));
19
+ }
package/core/Types.sol CHANGED
@@ -5,8 +5,6 @@ pragma solidity ^0.8.33;
5
5
  struct AssetAmount {
6
6
  /// @dev Asset identifier.
7
7
  bytes32 asset;
8
- /// @dev Asset metadata slot.
9
- bytes32 meta;
10
8
  /// @dev Token amount in the asset's native units.
11
9
  uint amount;
12
10
  }
@@ -17,8 +15,6 @@ struct AccountAsset {
17
15
  bytes32 account;
18
16
  /// @dev Asset identifier.
19
17
  bytes32 asset;
20
- /// @dev Asset metadata slot.
21
- bytes32 meta;
22
18
  }
23
19
 
24
20
  /// @notice Account-scoped amount shape for requests, responses, and reporting.
@@ -27,8 +23,6 @@ struct AccountAmount {
27
23
  bytes32 account;
28
24
  /// @dev Asset identifier.
29
25
  bytes32 asset;
30
- /// @dev Asset metadata slot.
31
- bytes32 meta;
32
26
  /// @dev Token amount in the asset's native units.
33
27
  uint amount;
34
28
  }
@@ -39,8 +33,6 @@ struct HostAmount {
39
33
  uint host;
40
34
  /// @dev Asset identifier.
41
35
  bytes32 asset;
42
- /// @dev Asset metadata slot.
43
- bytes32 meta;
44
36
  /// @dev Token amount in the asset's native units.
45
37
  uint amount;
46
38
  }
@@ -53,8 +45,6 @@ struct HostAccountAsset {
53
45
  bytes32 account;
54
46
  /// @dev Asset identifier.
55
47
  bytes32 asset;
56
- /// @dev Asset metadata slot.
57
- bytes32 meta;
58
48
  }
59
49
 
60
50
  /// @notice Host-scoped account amount shape.
@@ -65,8 +55,6 @@ struct HostAccountAmount {
65
55
  bytes32 account;
66
56
  /// @dev Asset identifier.
67
57
  bytes32 asset;
68
- /// @dev Asset metadata slot.
69
- bytes32 meta;
70
58
  /// @dev Token amount in the asset's native units.
71
59
  uint amount;
72
60
  }
@@ -79,8 +67,6 @@ struct Tx {
79
67
  bytes32 to;
80
68
  /// @dev Asset identifier.
81
69
  bytes32 asset;
82
- /// @dev Asset metadata slot.
83
- bytes32 meta;
84
70
  /// @dev Transfer amount in the asset's native units.
85
71
  uint amount;
86
72
  }
package/docs/Schema.md CHANGED
@@ -21,7 +21,7 @@ The block key is:
21
21
  bytes4(keccak256("#name"))
22
22
  ```
23
23
 
24
- For example, `#amount { bytes32 asset, bytes32 meta, uint amount }` uses the key
24
+ For example, `#amount { bytes32 asset, uint amount }` uses the key
25
25
  derived from `#amount`. Blocks must not be overloaded: one block name should have
26
26
  one protocol meaning.
27
27
 
@@ -30,7 +30,7 @@ one protocol meaning.
30
30
  A block starts with `#`. Fixed fields are written in braces:
31
31
 
32
32
  ```txt
33
- #amount { bytes32 asset, bytes32 meta, uint amount }
33
+ #amount { bytes32 asset, uint amount }
34
34
  #account { bytes32 account }
35
35
  ```
36
36
 
@@ -46,7 +46,7 @@ Empty braces are invalid. A zero-payload block must omit braces.
46
46
  A schema is a comma-separated list of items. Order is significant.
47
47
 
48
48
  ```txt
49
- #amount { bytes32 asset, bytes32 meta, uint amount },
49
+ #amount { bytes32 asset, uint amount },
50
50
  maybe #account { bytes32 account }
51
51
  ```
52
52
 
@@ -76,10 +76,10 @@ alias to give those bytes a presentation name:
76
76
  Cardinality is expressed with prefix keywords:
77
77
 
78
78
  ```txt
79
- #balance { bytes32 asset, bytes32 meta, uint amount }
80
- maybe #balance { bytes32 asset, bytes32 meta, uint amount }
81
- many #balance { bytes32 asset, bytes32 meta, uint amount }
82
- maybe many #balance { bytes32 asset, bytes32 meta, uint amount }
79
+ #balance { bytes32 asset, uint amount }
80
+ maybe #balance { bytes32 asset, uint amount }
81
+ many #balance { bytes32 asset, uint amount }
82
+ maybe many #balance { bytes32 asset, uint amount }
83
83
  ```
84
84
 
85
85
  - no prefix: one required item
@@ -190,6 +190,25 @@ types may pack these words differently, but a given chain type must use one
190
190
  stable format everywhere. For EVM chains, the low 128 bits are native value /
191
191
  endowment in wei; higher bits are reserved for execution resources such as gas.
192
192
 
193
+ ## Protocol IDs
194
+
195
+ Account, asset, and node ID fields use one 32-byte convention:
196
+
197
+ - first byte `0x00`: opaque ID, encoded as `0x00 || bytes31(hash)`. The full
198
+ preimage must come from a lookup table or witness data when native metadata is
199
+ needed.
200
+ - first byte nonzero: structured ID. The value may be deconstructed according
201
+ to its chain/runtime layout.
202
+
203
+ Opaque preimages must start with a one-byte format/hash tag; `0x01` means
204
+ keccak256. The remaining bytes are host/domain-specific until the protocol
205
+ standardizes a fuller preimage payload format.
206
+
207
+ The field name supplies the protocol role for opaque IDs. For example, a
208
+ `bytes32 asset` whose first byte is zero is still an asset in that block; it
209
+ just cannot be decoded without external context. Runtime helpers that inspect
210
+ the layout of an ID only apply to structured IDs.
211
+
193
212
  ## Identifiers
194
213
 
195
214
  Block names use lower camelCase ASCII identifiers. Field names and aliases use
@@ -246,9 +265,9 @@ expands to:
246
265
  Common protocol schemas live in `contracts/blocks/Schema.sol`:
247
266
 
248
267
  ```txt
249
- #amount { bytes32 asset, bytes32 meta, uint amount }
250
- #balance { bytes32 asset, bytes32 meta, uint amount }
251
- #custody { uint host, bytes32 asset, bytes32 meta, uint amount }
268
+ #amount { bytes32 asset, uint amount }
269
+ #balance { bytes32 asset, uint amount }
270
+ #custody { uint host, bytes32 asset, uint amount }
252
271
  #call { uint target, uint resources, #bytes as payload }
253
272
  #step { uint target, uint resources, #bytes as request }
254
273
  #context { bytes32 account, #bytes as state, #bytes as request }
package/events/Asset.sol CHANGED
@@ -3,15 +3,29 @@ pragma solidity ^0.8.33;
3
3
 
4
4
  import { EventEmitter } from "./Emitter.sol";
5
5
 
6
+ /// @notice Emitted when a host declares the preimage for an opaque asset ID.
7
+ abstract contract AssetEvent is EventEmitter {
8
+ string private constant ABI = "event Asset(uint indexed host, bytes32 asset, bytes preimage)";
9
+
10
+ /// @param host Host node ID that manages this asset declaration.
11
+ /// @param asset Asset identifier, typically `0x00 || bytes31(hash(preimage))`.
12
+ /// @param preimage Canonical preimage used to derive or resolve the opaque asset ID.
13
+ /// The first byte is a format/hash tag; `0x01` means keccak256.
14
+ event Asset(uint indexed host, bytes32 asset, bytes preimage);
15
+
16
+ constructor() {
17
+ emit EventAbi(ABI);
18
+ }
19
+ }
20
+
6
21
  /// @notice Emitted when an asset support status is updated on a host.
7
22
  abstract contract AssetStatusEvent is EventEmitter {
8
- string private constant ABI = "event AssetStatus(uint indexed host, bytes32 asset, bytes32 meta, uint status)";
23
+ string private constant ABI = "event AssetStatus(uint indexed host, bytes32 asset, uint status)";
9
24
 
10
25
  /// @param host Host node ID that manages this listing.
11
26
  /// @param asset Asset identifier.
12
- /// @param meta Asset metadata slot.
13
27
  /// @param status Asset support status. Zero means unsupported; nonzero means supported.
14
- event AssetStatus(uint indexed host, bytes32 asset, bytes32 meta, uint status);
28
+ event AssetStatus(uint indexed host, bytes32 asset, uint status);
15
29
 
16
30
  constructor() {
17
31
  emit EventAbi(ABI);
@@ -5,15 +5,14 @@ import { EventEmitter } from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted when an account balance changes.
7
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)";
8
+ string private constant ABI = "event Balance(bytes32 indexed account, bytes32 asset, uint balance, int change, uint access)";
9
9
 
10
10
  /// @param account Account identifier whose balance changed.
11
11
  /// @param asset Asset identifier.
12
- /// @param meta Asset metadata slot.
13
12
  /// @param balance New balance after the change.
14
13
  /// @param change Signed delta applied to the balance (positive = credit, negative = debit).
15
14
  /// @param access Command ID or context identifier associated with this change.
16
- event Balance(bytes32 indexed account, bytes32 asset, bytes32 meta, uint balance, int change, uint access);
15
+ event Balance(bytes32 indexed account, bytes32 asset, uint balance, int change, uint access);
17
16
 
18
17
  constructor() {
19
18
  emit EventAbi(ABI);
@@ -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/events/Locked.sol CHANGED
@@ -5,15 +5,14 @@ import { EventEmitter } from "./Emitter.sol";
5
5
 
6
6
  /// @notice Emitted when an account locks an asset in a protocol operation.
7
7
  abstract contract LockedEvent is EventEmitter {
8
- string private constant ABI = "event Locked(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint32 action, uint context)";
8
+ string private constant ABI = "event Locked(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context)";
9
9
 
10
10
  /// @param account Account identifier that locked the asset.
11
11
  /// @param asset Asset identifier.
12
- /// @param meta Asset metadata slot.
13
12
  /// @param amount Amount locked.
14
13
  /// @param action Primary operation hint from `Actions`.
15
14
  /// @param context Reserved context value for future use.
16
- event Locked(bytes32 indexed account, bytes32 asset, bytes32 meta, uint amount, uint32 action, uint context);
15
+ event Locked(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context);
17
16
 
18
17
  constructor() {
19
18
  emit EventAbi(ABI);