@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.
- package/CHANGELOG.md +40 -0
- package/Core.sol +4 -2
- package/Endpoints.sol +5 -3
- package/Events.sol +2 -1
- package/README.md +58 -31
- package/Utils.sol +4 -3
- package/blocks/Cursors.sol +107 -143
- package/blocks/Keys.sol +15 -15
- package/blocks/Schema.sol +27 -28
- package/blocks/Writers.sol +26 -33
- package/commands/Base.sol +2 -2
- package/commands/Burn.sol +3 -4
- package/commands/Credit.sol +3 -4
- package/commands/Debit.sol +4 -5
- package/commands/Deposit.sol +8 -10
- package/commands/Payout.sol +3 -6
- package/commands/Withdraw.sol +3 -4
- package/commands/admin/AllowAssets.sol +7 -9
- package/commands/admin/Allowance.sol +5 -7
- package/commands/admin/Appoint.sol +2 -3
- package/commands/admin/Authorize.sol +2 -3
- package/commands/admin/Base.sol +9 -0
- package/commands/admin/DenyAssets.sol +7 -9
- package/commands/admin/Destroy.sol +2 -3
- package/commands/admin/Dismiss.sol +2 -3
- package/commands/admin/Execute.sol +4 -5
- package/commands/admin/Init.sol +2 -3
- package/commands/admin/Label.sol +2 -3
- package/commands/admin/Unauthorize.sol +2 -3
- package/core/Access.sol +2 -2
- package/core/Balances.sol +10 -11
- package/core/Calls.sol +7 -7
- package/core/Commitments.sol +19 -0
- package/core/Escrows.sol +34 -0
- package/core/Host.sol +2 -2
- package/core/Runtime.sol +11 -6
- package/core/Types.sol +0 -14
- package/docs/Schema.md +29 -10
- package/events/Asset.sol +17 -3
- package/events/Balance.sol +2 -3
- package/events/Commitment.sol +19 -0
- package/events/Locked.sol +2 -3
- package/events/Position.sol +2 -3
- package/events/Received.sol +2 -3
- package/events/Spent.sol +2 -3
- package/events/Unlocked.sol +2 -3
- package/guards/Base.sol +4 -4
- package/package.json +1 -1
- package/peer/AllowAssets.sol +3 -3
- package/peer/Allowance.sol +2 -2
- package/peer/Base.sol +4 -4
- package/peer/Credit.sol +10 -10
- package/peer/Debit.sol +10 -10
- package/peer/DenyAssets.sol +3 -3
- package/peer/Recover.sol +51 -0
- package/peer/Redeem.sol +48 -0
- package/peer/Settle.sol +3 -3
- package/queries/Assets.sol +7 -8
- package/queries/Balances.sol +8 -9
- package/queries/Base.sol +4 -4
- package/queries/Positions.sol +4 -6
- package/utils/Accounts.sol +76 -58
- package/utils/Assets.sol +55 -115
- package/utils/Ids.sol +33 -233
- package/utils/Layout.sol +11 -17
- package/utils/Nodes.sol +263 -0
- package/utils/Utils.sol +9 -24
- 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 {
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
38
|
-
denyAsset(asset
|
|
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 {
|
|
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
|
|
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 {
|
|
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
|
|
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 {
|
|
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 {
|
|
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
|
|
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 =
|
|
34
|
+
address addr = Nodes.addr(target);
|
|
36
35
|
callAddr(addr, useValue(budget, resources), data);
|
|
37
36
|
}
|
|
38
37
|
|
package/commands/admin/Init.sol
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
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
|
|
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) {
|
package/commands/admin/Label.sol
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
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
|
|
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 {
|
|
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
|
|
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 {
|
|
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[
|
|
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-
|
|
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 ->
|
|
14
|
-
mapping(bytes32 account => mapping(bytes32
|
|
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
|
|
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
|
|
22
|
-
balance = balances[account][
|
|
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
|
|
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
|
|
32
|
-
balance = balances[account][
|
|
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][
|
|
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 {
|
|
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
|
|
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` + `
|
|
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 =
|
|
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` + `
|
|
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 =
|
|
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 =
|
|
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
|
+
}
|
package/core/Escrows.sol
ADDED
|
@@ -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 {
|
|
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(
|
|
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 {
|
|
5
|
+
import {Nodes} from "../utils/Nodes.sol";
|
|
6
6
|
|
|
7
|
-
/// @title
|
|
8
|
-
/// @notice Shared
|
|
9
|
-
abstract contract
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
80
|
-
maybe #balance { bytes32 asset,
|
|
81
|
-
many #balance { bytes32 asset,
|
|
82
|
-
maybe many #balance { bytes32 asset,
|
|
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,
|
|
250
|
-
#balance { bytes32 asset,
|
|
251
|
-
#custody { uint host, bytes32 asset,
|
|
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,
|
|
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,
|
|
28
|
+
event AssetStatus(uint indexed host, bytes32 asset, uint status);
|
|
15
29
|
|
|
16
30
|
constructor() {
|
|
17
31
|
emit EventAbi(ABI);
|
package/events/Balance.sol
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
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,
|
|
15
|
+
event Locked(bytes32 indexed account, bytes32 asset, uint amount, uint32 action, uint context);
|
|
17
16
|
|
|
18
17
|
constructor() {
|
|
19
18
|
emit EventAbi(ABI);
|