@rootzero/contracts 0.7.2 → 0.9.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/Commands.sol +15 -20
- package/Core.sol +3 -4
- package/Cursors.sol +3 -2
- package/Events.sol +1 -1
- package/Queries.sol +3 -3
- package/README.md +18 -19
- package/Utils.sol +3 -3
- package/blocks/Cursors.sol +937 -551
- package/blocks/Keys.sol +60 -34
- package/blocks/Schema.sol +112 -122
- package/blocks/Writers.sol +476 -301
- package/commands/Base.sol +32 -22
- package/commands/Burn.sol +14 -12
- package/commands/Credit.sol +16 -15
- package/commands/Debit.sol +14 -12
- package/commands/Deposit.sol +30 -37
- package/commands/Pipe.sol +14 -20
- package/commands/Provision.sol +19 -49
- package/commands/Transfer.sol +9 -18
- package/commands/Withdraw.sol +15 -14
- package/commands/admin/AllowAssets.sol +3 -3
- package/commands/admin/Allowance.sol +43 -0
- package/commands/admin/Authorize.sol +4 -4
- package/commands/admin/DenyAssets.sol +3 -3
- package/commands/admin/Destroy.sol +10 -8
- package/commands/admin/Execute.sol +38 -0
- package/commands/admin/Init.sol +10 -8
- package/commands/admin/Relocate.sol +5 -5
- package/commands/admin/Unauthorize.sol +4 -4
- package/core/Access.sol +38 -34
- package/core/Balances.sol +17 -18
- package/core/{Operation.sol → Calls.sol} +5 -8
- package/core/{CursorBase.sol → Context.sol} +11 -5
- package/core/Host.sol +11 -10
- package/core/Types.sol +86 -0
- package/docs/GETTING_STARTED.md +37 -29
- package/events/Asset.sol +1 -1
- package/events/Command.sol +10 -10
- package/events/Deposit.sol +3 -4
- package/events/Listing.sol +1 -1
- package/events/Peer.sol +3 -3
- package/events/Position.sol +21 -0
- package/events/Query.sol +3 -3
- package/events/Withdraw.sol +2 -3
- package/package.json +1 -1
- package/peer/AllowAssets.sol +1 -1
- package/peer/Allowance.sol +36 -0
- package/peer/AssetPull.sol +33 -31
- package/peer/Base.sol +8 -4
- package/peer/DenyAssets.sol +1 -1
- package/peer/Settle.sol +3 -4
- package/queries/Assets.sol +18 -16
- package/queries/Balances.sol +21 -19
- package/queries/Base.sol +2 -3
- package/queries/Positions.sol +32 -24
- package/utils/Accounts.sol +14 -13
- package/utils/Assets.sol +137 -62
- package/utils/Ids.sol +9 -9
- package/utils/Layout.sol +5 -3
- package/utils/Utils.sol +10 -0
- package/commands/Create.sol +0 -42
- package/commands/Remove.sol +0 -42
- package/commands/Settle.sol +0 -38
- package/commands/Stake.sol +0 -47
- package/commands/Supply.sol +0 -41
- package/commands/admin/Allocate.sol +0 -41
- package/core/HostBound.sol +0 -14
- package/events/Erc721.sol +0 -20
- package/peer/Pull.sol +0 -39
- package/peer/Push.sol +0 -45
- package/utils/State.sol +0 -22
package/commands/Withdraw.sol
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import { CommandContext, CommandBase,
|
|
4
|
+
import { CommandContext, CommandBase, Keys } from "./Base.sol";
|
|
5
5
|
import { Cursors, Cur, Schemas } from "../Cursors.sol";
|
|
6
6
|
using Cursors for Cur;
|
|
7
7
|
|
|
8
8
|
string constant NAME = "withdraw";
|
|
9
9
|
|
|
10
|
+
abstract contract WithdrawHook {
|
|
11
|
+
/// @notice Override to send funds to `account`.
|
|
12
|
+
/// Called once per BALANCE block in state.
|
|
13
|
+
/// @param account Destination account identifier (resolved from ACCOUNT block or caller).
|
|
14
|
+
/// @param asset Asset identifier.
|
|
15
|
+
/// @param meta Asset metadata slot.
|
|
16
|
+
/// @param amount Amount to deliver.
|
|
17
|
+
function withdraw(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
/// @title Withdraw
|
|
11
21
|
/// @notice Command that delivers BALANCE state blocks to an external destination.
|
|
12
22
|
/// Use `withdraw` for assets being sent outside the protocol (e.g. ERC-20 transfers, ETH sends).
|
|
13
23
|
/// For internal balance credits, use `creditAccount` instead.
|
|
14
|
-
abstract contract Withdraw is CommandBase {
|
|
24
|
+
abstract contract Withdraw is CommandBase, WithdrawHook {
|
|
15
25
|
uint internal immutable withdrawId = commandId(NAME);
|
|
16
26
|
|
|
17
27
|
constructor() {
|
|
18
|
-
emit Command(host, NAME, Schemas.
|
|
28
|
+
emit Command(host, withdrawId, NAME, Schemas.Account, Keys.Balance, Keys.Empty, false);
|
|
19
29
|
}
|
|
20
30
|
|
|
21
|
-
/// @notice Override to send funds to `account`.
|
|
22
|
-
/// Called once per BALANCE block in state.
|
|
23
|
-
/// @param account Destination account identifier (resolved from RECIPIENT block or caller).
|
|
24
|
-
/// @param asset Asset identifier.
|
|
25
|
-
/// @param meta Asset metadata slot.
|
|
26
|
-
/// @param amount Amount to deliver.
|
|
27
|
-
function withdraw(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
28
|
-
|
|
29
31
|
function withdraw(
|
|
30
32
|
CommandContext calldata c
|
|
31
|
-
) external onlyCommand(
|
|
33
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
32
34
|
(Cur memory state, , ) = cursor(c.state, 1);
|
|
33
|
-
|
|
34
|
-
bytes32 to = request.recipientAfter(c.account);
|
|
35
|
+
bytes32 to = Cursors.resolveAccount(c.request, c.account);
|
|
35
36
|
|
|
36
37
|
while (state.i < state.bound) {
|
|
37
38
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import { CommandBase, CommandContext,
|
|
4
|
+
import { CommandBase, CommandContext, Keys } from "../Base.sol";
|
|
5
5
|
import { Cursors, Cur, Schemas } from "../../Cursors.sol";
|
|
6
6
|
using Cursors for Cur;
|
|
7
7
|
|
|
@@ -20,12 +20,12 @@ abstract contract AllowAssets is CommandBase, AllowAssetsHook {
|
|
|
20
20
|
uint internal immutable allowAssetsId = commandId(NAME);
|
|
21
21
|
|
|
22
22
|
constructor() {
|
|
23
|
-
emit Command(host, NAME, Schemas.Asset,
|
|
23
|
+
emit Command(host, allowAssetsId, NAME, Schemas.Asset, Keys.Empty, Keys.Empty, false);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function allowAssets(
|
|
27
27
|
CommandContext calldata c
|
|
28
|
-
) external onlyAdmin(c.account)
|
|
28
|
+
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
29
29
|
(Cur memory request, , ) = cursor(c.request, 1);
|
|
30
30
|
|
|
31
31
|
while (request.i < request.bound) {
|
|
@@ -0,0 +1,43 @@
|
|
|
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 { Cursors, Cur, Schemas } from "../../Cursors.sol";
|
|
6
|
+
using Cursors for Cur;
|
|
7
|
+
|
|
8
|
+
string constant NAME = "allowance";
|
|
9
|
+
|
|
10
|
+
abstract contract AllowanceHook {
|
|
11
|
+
/// @notice Apply or revoke one host-scoped allowance.
|
|
12
|
+
/// Called once per ALLOWANCE block in the request. Implementations decide
|
|
13
|
+
/// how the allowance is represented, e.g. ERC-20 approval, an internal cap,
|
|
14
|
+
/// or another host-specific authorization record.
|
|
15
|
+
/// @param peer Host node receiving the allowed cap.
|
|
16
|
+
/// @param asset Asset identifier.
|
|
17
|
+
/// @param meta Asset metadata slot.
|
|
18
|
+
/// @param amount Allowed cap amount.
|
|
19
|
+
function allowance(uint peer, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/// @title Allowance
|
|
23
|
+
/// @notice Admin command that applies cross-host allowance entries via a virtual hook.
|
|
24
|
+
/// Each ALLOWANCE block grants or updates a host-scoped asset cap. Only callable by the admin account.
|
|
25
|
+
abstract contract Allowance is CommandBase, AllowanceHook {
|
|
26
|
+
uint internal immutable allowanceId = commandId(NAME);
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
emit Command(host, allowanceId, NAME, Schemas.Allowance, Keys.Empty, Keys.Empty, false);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function allowance(CommandContext calldata c) external onlyAdmin(c.account) returns (bytes memory) {
|
|
33
|
+
(Cur memory request, , ) = cursor(c.request, 1);
|
|
34
|
+
|
|
35
|
+
while (request.i < request.bound) {
|
|
36
|
+
(uint peer, bytes32 asset, bytes32 meta, uint amount) = request.unpackAllowance();
|
|
37
|
+
allowance(peer, asset, meta, amount);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
request.complete();
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import { CommandBase, CommandContext,
|
|
4
|
+
import { CommandBase, CommandContext, Keys } from "../Base.sol";
|
|
5
5
|
import { Cursors, Cur, Schemas } from "../../Cursors.sol";
|
|
6
6
|
using Cursors for Cur;
|
|
7
7
|
|
|
@@ -15,17 +15,17 @@ abstract contract Authorize is CommandBase {
|
|
|
15
15
|
uint internal immutable authorizeId = commandId(NAME);
|
|
16
16
|
|
|
17
17
|
constructor() {
|
|
18
|
-
emit Command(host, NAME, Schemas.Node,
|
|
18
|
+
emit Command(host, authorizeId, NAME, Schemas.Node, Keys.Empty, Keys.Empty, false);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function authorize(
|
|
22
22
|
CommandContext calldata c
|
|
23
|
-
) external onlyAdmin(c.account)
|
|
23
|
+
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
24
24
|
(Cur memory request, , ) = cursor(c.request, 1);
|
|
25
25
|
|
|
26
26
|
while (request.i < request.bound) {
|
|
27
27
|
uint node = request.unpackNode();
|
|
28
|
-
|
|
28
|
+
authorize(node);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
request.complete();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import { CommandBase, CommandContext,
|
|
4
|
+
import { CommandBase, CommandContext, Keys } from "../Base.sol";
|
|
5
5
|
import { Cursors, Cur, Schemas } from "../../Cursors.sol";
|
|
6
6
|
using Cursors for Cur;
|
|
7
7
|
|
|
@@ -20,12 +20,12 @@ abstract contract DenyAssets is CommandBase, DenyAssetsHook {
|
|
|
20
20
|
uint internal immutable denyAssetsId = commandId(NAME);
|
|
21
21
|
|
|
22
22
|
constructor() {
|
|
23
|
-
emit Command(host, NAME, Schemas.Asset,
|
|
23
|
+
emit Command(host, denyAssetsId, NAME, Schemas.Asset, Keys.Empty, Keys.Empty, false);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function denyAssets(
|
|
27
27
|
CommandContext calldata c
|
|
28
|
-
) external onlyAdmin(c.account)
|
|
28
|
+
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
29
29
|
(Cur memory request, , ) = cursor(c.request, 1);
|
|
30
30
|
|
|
31
31
|
while (request.i < request.bound) {
|
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import { CommandBase, CommandContext,
|
|
4
|
+
import { CommandBase, CommandContext, Keys } from "../Base.sol";
|
|
5
5
|
import { Cursors, Cur } from "../../Cursors.sol";
|
|
6
6
|
|
|
7
7
|
string constant NAME = "destroy";
|
|
8
8
|
|
|
9
9
|
using Cursors for Cur;
|
|
10
10
|
|
|
11
|
+
abstract contract DestroyHook {
|
|
12
|
+
/// @notice Override to run host teardown or destruction logic.
|
|
13
|
+
/// @param input Cursor over the full request byte stream.
|
|
14
|
+
function destroy(Cur memory input) internal virtual;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
/// @title Destroy
|
|
12
18
|
/// @notice Admin command that runs host teardown logic via a virtual hook.
|
|
13
19
|
/// The full request is passed to `destroy` as a cursor. Only callable by the admin account.
|
|
14
|
-
abstract contract Destroy is CommandBase {
|
|
20
|
+
abstract contract Destroy is CommandBase, DestroyHook {
|
|
15
21
|
uint internal immutable destroyId = commandId(NAME);
|
|
16
22
|
|
|
17
23
|
constructor(string memory input) {
|
|
18
|
-
emit Command(host, NAME, input,
|
|
24
|
+
emit Command(host, destroyId, NAME, input, Keys.Empty, Keys.Empty, false);
|
|
19
25
|
}
|
|
20
26
|
|
|
21
|
-
/// @notice Override to run host teardown or destruction logic.
|
|
22
|
-
/// @param input Cursor over the full request byte stream.
|
|
23
|
-
function destroy(Cur memory input) internal virtual;
|
|
24
|
-
|
|
25
27
|
function destroy(
|
|
26
28
|
CommandContext calldata c
|
|
27
|
-
) external onlyAdmin(c.account)
|
|
29
|
+
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
28
30
|
Cur memory input = cursor(c.request);
|
|
29
31
|
destroy(input);
|
|
30
32
|
return "";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {CommandContext, CommandPayable, Keys} from "../Base.sol";
|
|
5
|
+
import {Cursors, Cur, Schemas} from "../../Cursors.sol";
|
|
6
|
+
import {Budget, Values} from "../../utils/Value.sol";
|
|
7
|
+
import {Ids} from "../../utils/Ids.sol";
|
|
8
|
+
|
|
9
|
+
using Cursors for Cur;
|
|
10
|
+
|
|
11
|
+
string constant NAME = "executePayable";
|
|
12
|
+
|
|
13
|
+
/// @title ExecutePayable
|
|
14
|
+
/// @notice Admin command that forwards raw calldata to one or more target nodes.
|
|
15
|
+
/// Each CALL block specifies a target node ID, native value, and raw calldata payload.
|
|
16
|
+
/// Only callable by the admin account.
|
|
17
|
+
abstract contract ExecutePayable is CommandPayable {
|
|
18
|
+
uint internal immutable executePayableId = commandId(NAME);
|
|
19
|
+
|
|
20
|
+
constructor() {
|
|
21
|
+
emit Command(host, executePayableId, NAME, Schemas.Call, Keys.Empty, Keys.Empty, true);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function executePayable(CommandContext calldata c) external payable onlyAdmin(c.account) returns (bytes memory) {
|
|
25
|
+
(Cur memory request, , ) = cursor(c.request, 1);
|
|
26
|
+
Budget memory budget = Values.fromMsg();
|
|
27
|
+
|
|
28
|
+
while (request.i < request.bound) {
|
|
29
|
+
(uint target, uint value, bytes calldata data) = request.unpackCall();
|
|
30
|
+
address addr = Ids.nodeAddr(target);
|
|
31
|
+
callAddr(addr, Values.use(budget, value), data);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
request.complete();
|
|
35
|
+
settleValue(c.account, budget);
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
}
|
package/commands/admin/Init.sol
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import { CommandBase, CommandContext,
|
|
4
|
+
import { CommandBase, CommandContext, Keys } from "../Base.sol";
|
|
5
5
|
import { Cursors, Cur } from "../../Cursors.sol";
|
|
6
6
|
|
|
7
7
|
string constant NAME = "init";
|
|
8
8
|
|
|
9
9
|
using Cursors for Cur;
|
|
10
10
|
|
|
11
|
+
abstract contract InitHook {
|
|
12
|
+
/// @notice Override to run host initialization logic.
|
|
13
|
+
/// @param input Cursor over the full request byte stream.
|
|
14
|
+
function init(Cur memory input) internal virtual;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
/// @title Init
|
|
12
18
|
/// @notice Admin command that runs host initialization logic via a virtual hook.
|
|
13
19
|
/// The full request is passed to `init` as a cursor. Only callable by the admin account.
|
|
14
|
-
abstract contract Init is CommandBase {
|
|
20
|
+
abstract contract Init is CommandBase, InitHook {
|
|
15
21
|
uint internal immutable initId = commandId(NAME);
|
|
16
22
|
|
|
17
23
|
constructor(string memory input) {
|
|
18
|
-
emit Command(host, NAME, input,
|
|
24
|
+
emit Command(host, initId, NAME, input, Keys.Empty, Keys.Empty, false);
|
|
19
25
|
}
|
|
20
26
|
|
|
21
|
-
/// @notice Override to run host initialization logic.
|
|
22
|
-
/// @param input Cursor over the full request byte stream.
|
|
23
|
-
function init(Cur memory input) internal virtual;
|
|
24
|
-
|
|
25
27
|
function init(
|
|
26
28
|
CommandContext calldata c
|
|
27
|
-
) external onlyAdmin(c.account)
|
|
29
|
+
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
28
30
|
Cur memory input = cursor(c.request);
|
|
29
31
|
init(input);
|
|
30
32
|
return "";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import { CommandContext, CommandPayable,
|
|
4
|
+
import { CommandContext, CommandPayable, Keys } from "../Base.sol";
|
|
5
5
|
import { Cursors, Cur, Schemas } from "../../Cursors.sol";
|
|
6
6
|
import { Budget, Values } from "../../utils/Value.sol";
|
|
7
7
|
using Cursors for Cur;
|
|
@@ -10,23 +10,23 @@ string constant NAME = "relocatePayable";
|
|
|
10
10
|
|
|
11
11
|
/// @title RelocatePayable
|
|
12
12
|
/// @notice Admin command that forwards native value (ETH) to one or more destination hosts.
|
|
13
|
-
/// Each
|
|
13
|
+
/// Each RELOCATION block in the request specifies a target host node ID and an amount to forward.
|
|
14
14
|
/// Only callable by the admin account.
|
|
15
15
|
abstract contract RelocatePayable is CommandPayable {
|
|
16
16
|
uint internal immutable relocatePayableId = commandId(NAME);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
|
-
emit Command(host, NAME, Schemas.
|
|
19
|
+
emit Command(host, relocatePayableId, NAME, Schemas.Relocation, Keys.Empty, Keys.Empty, true);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function relocatePayable(
|
|
23
23
|
CommandContext calldata c
|
|
24
|
-
) external payable onlyAdmin(c.account)
|
|
24
|
+
) external payable onlyAdmin(c.account) returns (bytes memory) {
|
|
25
25
|
(Cur memory request, , ) = cursor(c.request, 1);
|
|
26
26
|
Budget memory budget = Values.fromMsg();
|
|
27
27
|
|
|
28
28
|
while (request.i < request.bound) {
|
|
29
|
-
(uint peer, uint amount) = request.
|
|
29
|
+
(uint peer, uint amount) = request.unpackRelocation();
|
|
30
30
|
callTo(peer, Values.use(budget, amount), "");
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import { CommandBase, CommandContext,
|
|
4
|
+
import { CommandBase, CommandContext, Keys } from "../Base.sol";
|
|
5
5
|
import { Cursors, Cur, Schemas } from "../../Cursors.sol";
|
|
6
6
|
using Cursors for Cur;
|
|
7
7
|
|
|
@@ -15,17 +15,17 @@ abstract contract Unauthorize is CommandBase {
|
|
|
15
15
|
uint internal immutable unauthorizeId = commandId(NAME);
|
|
16
16
|
|
|
17
17
|
constructor() {
|
|
18
|
-
emit Command(host, NAME, Schemas.Node,
|
|
18
|
+
emit Command(host, unauthorizeId, NAME, Schemas.Node, Keys.Empty, Keys.Empty, false);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function unauthorize(
|
|
22
22
|
CommandContext calldata c
|
|
23
|
-
) external onlyAdmin(c.account)
|
|
23
|
+
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
24
24
|
(Cur memory request, , ) = cursor(c.request, 1);
|
|
25
25
|
|
|
26
26
|
while (request.i < request.bound) {
|
|
27
27
|
uint node = request.unpackNode();
|
|
28
|
-
|
|
28
|
+
unauthorize(node);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
request.complete();
|
package/core/Access.sol
CHANGED
|
@@ -1,46 +1,53 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
4
|
+
import {AccessEvent} from "../events/Access.sol";
|
|
5
|
+
import {RootZeroContext} from "./Context.sol";
|
|
6
|
+
import {Accounts} from "../utils/Accounts.sol";
|
|
7
|
+
import {Ids} from "../utils/Ids.sol";
|
|
8
|
+
import {addrOr} from "../utils/Utils.sol";
|
|
9
9
|
|
|
10
10
|
/// @title AccessControl
|
|
11
11
|
/// @notice Host access control layer.
|
|
12
12
|
/// Tracks an immutable trusted commander, the host's own node ID, and a
|
|
13
|
-
/// mapping of externally
|
|
14
|
-
///
|
|
13
|
+
/// mapping of externally trusted node IDs. Inbound trust is host-based:
|
|
14
|
+
/// trusted hosts, the commander, and this contract itself may interact
|
|
15
15
|
/// with the host through the guarded command and peer entrypoints.
|
|
16
|
-
abstract contract AccessControl is
|
|
16
|
+
abstract contract AccessControl is RootZeroContext, AccessEvent {
|
|
17
17
|
/// @dev Trusted commander address. All calls from this address are implicitly trusted.
|
|
18
18
|
/// Defaults to `address(this)` when no external commander is provided.
|
|
19
19
|
address internal immutable commander;
|
|
20
20
|
/// @dev Admin account ID derived from the commander address at construction time.
|
|
21
21
|
bytes32 internal immutable adminAccount;
|
|
22
22
|
|
|
23
|
-
/// @dev Mapping from node ID to
|
|
24
|
-
|
|
25
|
-
mapping(uint => bool) internal authorized;
|
|
23
|
+
/// @dev Mapping from node ID to trust status.
|
|
24
|
+
mapping(uint node => bool) internal trusted;
|
|
26
25
|
|
|
27
|
-
/// @dev Thrown when `ensureTrusted` is called with a node that is not authorized.
|
|
28
|
-
error UnauthorizedNode(uint node);
|
|
29
26
|
/// @dev Thrown when `enforceCaller` is called by an address that is not trusted.
|
|
30
27
|
error UnauthorizedCaller(address addr);
|
|
31
28
|
|
|
29
|
+
/// @dev Thrown when a required trusted node is missing from the trusted set.
|
|
30
|
+
error UnauthorizedNode(uint node);
|
|
31
|
+
|
|
32
32
|
constructor(address cmdr) {
|
|
33
33
|
commander = addrOr(cmdr, address(this));
|
|
34
34
|
adminAccount = Accounts.toAdmin(commander);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/// @notice Grant
|
|
38
|
-
///
|
|
39
|
-
/// @param node Node ID to authorize
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
/// @notice Grant authorization for a node.
|
|
38
|
+
/// Accepts any node ID that should be trusted by this contract.
|
|
39
|
+
/// @param node Node ID to authorize.
|
|
40
|
+
function authorize(uint node) internal {
|
|
41
|
+
trusted[node] = true;
|
|
42
|
+
emit Access(host, node, true);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// @notice Revoke authorization for a node.
|
|
46
|
+
/// Accepts any node ID that should no longer be trusted by this contract.
|
|
47
|
+
/// @param node Node ID to unauthorize.
|
|
48
|
+
function unauthorize(uint node) internal {
|
|
49
|
+
trusted[node] = false;
|
|
50
|
+
emit Access(host, node, false);
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
/// @notice Return true if `caller` is an implicitly trusted address.
|
|
@@ -48,7 +55,17 @@ abstract contract AccessControl is HostBound, AccessEvent {
|
|
|
48
55
|
/// whose host ID has been explicitly authorized.
|
|
49
56
|
/// @param caller Address to check.
|
|
50
57
|
function isTrusted(address caller) internal view returns (bool) {
|
|
51
|
-
return caller == commander || caller == address(this) ||
|
|
58
|
+
return caller == commander || caller == address(this) || trusted[Ids.toHost(caller)];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// @notice Assert that `node` is in the trusted set and return it.
|
|
62
|
+
/// @param node Node ID to validate.
|
|
63
|
+
/// @return The same `node` value if trusted.
|
|
64
|
+
function ensureTrusted(uint node) internal view returns (uint) {
|
|
65
|
+
if (node == 0 || !trusted[node]) {
|
|
66
|
+
revert UnauthorizedNode(node);
|
|
67
|
+
}
|
|
68
|
+
return node;
|
|
52
69
|
}
|
|
53
70
|
|
|
54
71
|
/// @notice Assert that `caller` is trusted and return it.
|
|
@@ -61,17 +78,4 @@ abstract contract AccessControl is HostBound, AccessEvent {
|
|
|
61
78
|
}
|
|
62
79
|
return caller;
|
|
63
80
|
}
|
|
64
|
-
|
|
65
|
-
/// @notice Assert that `node` is in the authorized set and return it.
|
|
66
|
-
/// Used for outbound trust checks before calling another node.
|
|
67
|
-
/// Accepts any authorized node ID (host or command).
|
|
68
|
-
/// Inbound caller authentication is host-only via `enforceCaller(msg.sender)`.
|
|
69
|
-
/// @param node Node ID to validate.
|
|
70
|
-
/// @return The same `node` value if authorized.
|
|
71
|
-
function ensureTrusted(uint node) internal view returns (uint) {
|
|
72
|
-
if (node == 0 || !authorized[node]) {
|
|
73
|
-
revert UnauthorizedNode(node);
|
|
74
|
-
}
|
|
75
|
-
return node;
|
|
76
|
-
}
|
|
77
81
|
}
|
package/core/Balances.sol
CHANGED
|
@@ -7,34 +7,33 @@ 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
|
-
///
|
|
12
|
-
/// value returned by `Assets.key(asset, meta)`.
|
|
10
|
+
/// @notice On-chain ledger for per-account, per-slot balances.
|
|
11
|
+
/// Higher-level modules decide how slots are derived and validated.
|
|
13
12
|
abstract contract Balances is BalanceEvent {
|
|
14
|
-
/// @dev account ->
|
|
15
|
-
mapping(bytes32 account => mapping(bytes32
|
|
13
|
+
/// @dev account -> slot -> balance.
|
|
14
|
+
mapping(bytes32 account => mapping(bytes32 slot => uint amount)) internal balances;
|
|
15
|
+
|
|
16
|
+
/// @notice Add `amount` to an account balance and return the new balance.
|
|
17
|
+
/// @param account Account identifier.
|
|
18
|
+
/// @param slot Storage slot for the position being credited.
|
|
19
|
+
/// @param amount Amount to credit.
|
|
20
|
+
/// @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;
|
|
23
|
+
}
|
|
16
24
|
|
|
17
25
|
/// @notice Deduct `amount` from an account balance and return the new balance.
|
|
18
26
|
/// Reverts with `InsufficientFunds` if the current balance is less than `amount`.
|
|
19
27
|
/// @param account Account identifier.
|
|
20
|
-
/// @param
|
|
28
|
+
/// @param slot Storage slot for the position being debited.
|
|
21
29
|
/// @param amount Amount to deduct.
|
|
22
30
|
/// @return balance New balance after the debit.
|
|
23
|
-
function debitFrom(bytes32 account, bytes32
|
|
24
|
-
balance = balances[account][
|
|
31
|
+
function debitFrom(bytes32 account, bytes32 slot, uint amount) internal returns (uint balance) {
|
|
32
|
+
balance = balances[account][slot];
|
|
25
33
|
if (balance < amount) revert InsufficientFunds();
|
|
26
34
|
unchecked {
|
|
27
35
|
balance -= amount;
|
|
28
36
|
}
|
|
29
|
-
balances[account][
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/// @notice Add `amount` to an account balance and return the new balance.
|
|
33
|
-
/// @param account Account identifier.
|
|
34
|
-
/// @param assetKey Storage key for the (asset, meta) pair.
|
|
35
|
-
/// @param amount Amount to credit.
|
|
36
|
-
/// @return balance New balance after the credit.
|
|
37
|
-
function creditTo(bytes32 account, bytes32 assetKey, uint amount) internal returns (uint balance) {
|
|
38
|
-
balance = balances[account][assetKey] += amount;
|
|
37
|
+
balances[account][slot] = balance;
|
|
39
38
|
}
|
|
40
39
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { Ids } from "../utils/Ids.sol";
|
|
4
|
+
import {AccessControl} from "./Access.sol";
|
|
5
|
+
import {Ids} from "../utils/Ids.sol";
|
|
7
6
|
|
|
8
7
|
/// @dev Emitted when a trusted inter-node call fails.
|
|
9
8
|
/// @param addr Contract address that was called.
|
|
@@ -11,11 +10,9 @@ import { Ids } from "../utils/Ids.sol";
|
|
|
11
10
|
/// @param err Revert data returned by the failed call.
|
|
12
11
|
error FailedCall(address addr, bytes4 selector, bytes err);
|
|
13
12
|
|
|
14
|
-
/// @title
|
|
15
|
-
/// @notice Shared
|
|
16
|
-
|
|
17
|
-
/// and trusted inter-node calls. Inherits access control from `AccessControl`.
|
|
18
|
-
abstract contract OperationBase is CursorBase, AccessControl {
|
|
13
|
+
/// @title NodeCalls
|
|
14
|
+
/// @notice Shared trusted inter-node call helpers for contracts that can talk to other nodes.
|
|
15
|
+
abstract contract NodeCalls is AccessControl {
|
|
19
16
|
/// @notice Return the host node ID corresponding to the current caller.
|
|
20
17
|
/// @dev Encodes `msg.sender` as a host ID using the local-chain host layout.
|
|
21
18
|
/// @return Host node ID for `msg.sender`.
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {Cur, Cursors} from "../Cursors.sol";
|
|
5
|
+
import {Assets} from "../utils/Assets.sol";
|
|
6
|
+
import {Ids} from "../utils/Ids.sol";
|
|
5
7
|
|
|
6
8
|
using Cursors for Cur;
|
|
7
9
|
|
|
8
|
-
/// @title
|
|
9
|
-
/// @notice Shared
|
|
10
|
-
abstract contract
|
|
10
|
+
/// @title RootZeroContext
|
|
11
|
+
/// @notice Shared rootzero contract context for host identity, native value identity, and block-stream cursors.
|
|
12
|
+
abstract contract RootZeroContext {
|
|
13
|
+
/// @dev This contract's host node ID, set to `Ids.toHost(address(this))` at construction.
|
|
14
|
+
uint public immutable host = Ids.toHost(address(this));
|
|
15
|
+
/// @dev Asset ID for the native chain value (ETH), bound to the current chain at deployment.
|
|
16
|
+
bytes32 internal immutable valueAsset = Assets.toValue();
|
|
17
|
+
|
|
11
18
|
/// @notice Open a cursor over a calldata block stream.
|
|
12
19
|
/// @param source Calldata slice to parse.
|
|
13
20
|
/// @return cur Cursor positioned at the beginning of `source`.
|
|
@@ -39,5 +46,4 @@ abstract contract CursorBase {
|
|
|
39
46
|
(, , uint quotient) = cur.primeRun(group);
|
|
40
47
|
if (quotient != expectedQuotient) revert Cursors.BadRatio();
|
|
41
48
|
}
|
|
42
|
-
|
|
43
49
|
}
|
package/core/Host.sol
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
4
|
+
import {AccessControl} from "./Access.sol";
|
|
5
|
+
import {Authorize} from "../commands/admin/Authorize.sol";
|
|
6
|
+
import {Unauthorize} from "../commands/admin/Unauthorize.sol";
|
|
7
|
+
import {ExecutePayable} from "../commands/admin/Execute.sol";
|
|
8
|
+
import {RelocatePayable} from "../commands/admin/Relocate.sol";
|
|
9
|
+
import {HostAnnouncedEvent} from "../events/Host.sol";
|
|
10
|
+
import {IHostDiscovery} from "../interfaces/IHostDiscovery.sol";
|
|
11
|
+
import {Ids} from "../utils/Ids.sol";
|
|
11
12
|
|
|
12
13
|
/// @notice Mixin that allows a contract to act as a host discovery registry.
|
|
13
14
|
/// Hosts call `announceHost` on a discovery contract to register themselves.
|
|
@@ -19,16 +20,16 @@ abstract contract HostDiscovery is HostAnnouncedEvent, IHostDiscovery {
|
|
|
19
20
|
/// @param version Protocol version the host implements.
|
|
20
21
|
/// @param namespace Human-readable namespace string for the host.
|
|
21
22
|
function announceHost(uint id, uint blocknum, uint16 version, string calldata namespace) external {
|
|
22
|
-
emit HostAnnounced(Ids.
|
|
23
|
+
emit HostAnnounced(Ids.matchHost(id, msg.sender), blocknum, version, namespace);
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/// @title Host
|
|
27
28
|
/// @notice Abstract base contract for rootzero host implementations.
|
|
28
|
-
/// Inherits admin command support (authorize, unauthorize, relocatePayable) and
|
|
29
|
+
/// Inherits admin command support (authorize, unauthorize, executePayable, relocatePayable) and
|
|
29
30
|
/// optionally announces itself to a discovery contract at deployment.
|
|
30
31
|
/// Accepts native ETH payments via the `receive` function.
|
|
31
|
-
abstract contract Host is Authorize, Unauthorize, RelocatePayable {
|
|
32
|
+
abstract contract Host is Authorize, Unauthorize, ExecutePayable, RelocatePayable {
|
|
32
33
|
/// @param cmdr Commander address; passed to `AccessControl`.
|
|
33
34
|
/// If `cmdr` is a deployed contract, the host calls `announceHost`
|
|
34
35
|
/// on it during construction to register with the discovery registry.
|