@rootzero/contracts 0.9.2 → 0.9.4
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 +4 -3
- package/Core.sol +3 -0
- package/Cursors.sol +1 -1
- package/README.md +18 -24
- package/blocks/Cursors.sol +332 -335
- package/blocks/Keys.sol +38 -57
- package/blocks/Schema.sol +55 -114
- package/blocks/Writers.sol +361 -255
- package/commands/Base.sol +6 -48
- package/commands/Burn.sol +4 -4
- package/commands/Credit.sol +5 -4
- package/commands/Debit.sol +6 -5
- package/commands/Deposit.sol +17 -14
- package/commands/Provision.sol +17 -14
- package/commands/Transfer.sol +4 -4
- package/commands/Withdraw.sol +5 -4
- package/commands/admin/AllowAssets.sol +3 -3
- package/commands/admin/Allowance.sol +3 -3
- package/commands/admin/Authorize.sol +3 -3
- package/commands/admin/DenyAssets.sol +3 -3
- package/commands/admin/Destroy.sol +1 -1
- package/commands/admin/Execute.sol +9 -8
- package/commands/admin/Init.sol +1 -1
- package/commands/admin/Unauthorize.sol +3 -3
- package/core/Access.sol +11 -0
- package/core/Context.sol +11 -13
- package/core/Payable.sol +57 -0
- package/core/Pipeline.sol +55 -0
- package/docs/Schema.md +194 -0
- package/events/Admin.sol +5 -1
- package/events/Command.sol +6 -2
- package/events/Listing.sol +3 -4
- package/events/Peer.sol +5 -3
- package/events/Query.sol +5 -2
- package/package.json +2 -2
- package/peer/AllowAssets.sol +3 -3
- package/peer/Allowance.sol +3 -3
- package/peer/BalancePull.sol +43 -0
- package/peer/DenyAssets.sol +3 -3
- package/peer/Pipe.sol +38 -0
- package/peer/Settle.sol +3 -3
- package/queries/Assets.sol +7 -6
- package/queries/Balances.sol +5 -4
- package/queries/Positions.sol +14 -14
- package/utils/Value.sol +8 -14
- package/commands/Pipe.sol +0 -67
- package/docs/GETTING_STARTED.md +0 -294
- package/peer/AssetPull.sol +0 -43
package/commands/Base.sol
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import {NodeCalls} from "../core/Calls.sol";
|
|
5
|
-
import {Cur} from "../Cursors.sol";
|
|
6
5
|
import {CommandEvent} from "../events/Command.sol";
|
|
7
6
|
import {Keys} from "../blocks/Keys.sol";
|
|
8
7
|
import {Ids, Selectors} from "../utils/Ids.sol";
|
|
9
|
-
import {Budget, Values} from "../utils/Value.sol";
|
|
10
8
|
|
|
11
9
|
/// @notice Execution context passed to every command invocation.
|
|
12
10
|
struct CommandContext {
|
|
@@ -25,22 +23,18 @@ struct CommandContext {
|
|
|
25
23
|
abstract contract CommandBase is NodeCalls, CommandEvent {
|
|
26
24
|
/// @dev Thrown when `onlyActive` finds that `deadline` has already passed.
|
|
27
25
|
error Expired();
|
|
28
|
-
/// @dev Thrown when the raw active account word in calldata does not match the decoded context account.
|
|
29
|
-
error ActiveAccountMismatch();
|
|
30
26
|
/// @dev Thrown when `onlyAdmin` finds that `account` is not the admin account.
|
|
31
27
|
error NotAdmin();
|
|
32
28
|
|
|
33
|
-
/// @dev Restrict execution to
|
|
34
|
-
modifier
|
|
35
|
-
if (
|
|
36
|
-
|
|
29
|
+
/// @dev Restrict execution to the commander using the host's admin account.
|
|
30
|
+
modifier onlyAdmin(bytes32 account) {
|
|
31
|
+
if (account != adminAccount) revert NotAdmin();
|
|
32
|
+
enforceCommander(msg.sender);
|
|
37
33
|
_;
|
|
38
34
|
}
|
|
39
35
|
|
|
40
|
-
/// @dev Restrict execution to trusted callers
|
|
41
|
-
modifier
|
|
42
|
-
if (activeAccount() != account) revert ActiveAccountMismatch();
|
|
43
|
-
if (account != adminAccount) revert NotAdmin();
|
|
36
|
+
/// @dev Restrict execution to trusted callers.
|
|
37
|
+
modifier onlyCommand() {
|
|
44
38
|
enforceCaller(msg.sender);
|
|
45
39
|
_;
|
|
46
40
|
}
|
|
@@ -66,40 +60,4 @@ abstract contract CommandBase is NodeCalls, CommandEvent {
|
|
|
66
60
|
function commandId(string memory name) internal view returns (uint) {
|
|
67
61
|
return Ids.toCommand(Selectors.command(name), address(this));
|
|
68
62
|
}
|
|
69
|
-
|
|
70
|
-
/// @notice Return the active command account directly from the fixed tuple head in calldata.
|
|
71
|
-
/// @dev Command entrypoints use the ABI shape `name((bytes32,bytes,bytes))`, so the tuple head
|
|
72
|
-
/// starts at byte 36 of `msg.data`, with the account field at bytes [36:68).
|
|
73
|
-
function activeAccount() internal pure returns (bytes32 account) {
|
|
74
|
-
account = bytes32(msg.data[36:68]);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/// @title CommandPayable
|
|
79
|
-
/// @notice Abstract base for commands that accept native value (`msg.value`).
|
|
80
|
-
/// Provides a shared settlement hook for any unspent value remaining in the
|
|
81
|
-
/// command's mutable budget after execution completes.
|
|
82
|
-
abstract contract CommandPayable is CommandBase {
|
|
83
|
-
/// @dev Thrown when a payable command completes with unspent native value.
|
|
84
|
-
/// Override `settleValue` to implement refund or forwarding behavior instead.
|
|
85
|
-
error UnusedValue(uint remaining);
|
|
86
|
-
|
|
87
|
-
/// @notice Drains the command budget and settles any remaining native value.
|
|
88
|
-
/// @dev Calls the amount-based `settleValue` hook only when some value remains.
|
|
89
|
-
/// @param account Caller's account identifier for the current invocation.
|
|
90
|
-
/// @param budget Mutable native-value budget used during command execution.
|
|
91
|
-
function settleValue(bytes32 account, Budget memory budget) internal {
|
|
92
|
-
uint remaining = Values.drain(budget);
|
|
93
|
-
if (remaining != 0) settleValue(account, remaining);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/// @notice Handles leftover native value after a payable command has finished.
|
|
97
|
-
/// @dev Override this hook to refund or redirect unused value for a command.
|
|
98
|
-
/// The default implementation rejects any leftover amount.
|
|
99
|
-
/// @param account Caller's account identifier for the current invocation.
|
|
100
|
-
/// @param remaining Unspent native value left in the budget, in wei.
|
|
101
|
-
function settleValue(bytes32 account, uint remaining) internal virtual {
|
|
102
|
-
account;
|
|
103
|
-
revert UnusedValue(remaining);
|
|
104
|
-
}
|
|
105
63
|
}
|
package/commands/Burn.sol
CHANGED
|
@@ -25,18 +25,18 @@ abstract contract Burn is CommandBase, BurnHook {
|
|
|
25
25
|
uint internal immutable burnId = commandId(NAME);
|
|
26
26
|
|
|
27
27
|
constructor() {
|
|
28
|
-
emit Command(host, burnId, NAME, "", Keys.Balance, Keys.Empty, false);
|
|
28
|
+
emit Command(host, burnId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function burn(CommandContext calldata c) external onlyCommand
|
|
32
|
-
(Cur memory state,
|
|
31
|
+
function burn(CommandContext calldata c) external onlyCommand returns (bytes memory) {
|
|
32
|
+
(Cur memory state, ) = cursor(c.state, 1);
|
|
33
33
|
|
|
34
34
|
while (state.i < state.bound) {
|
|
35
35
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
|
36
36
|
burn(c.account, asset, meta, amount);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
state.
|
|
39
|
+
state.close();
|
|
40
40
|
return "";
|
|
41
41
|
}
|
|
42
42
|
}
|
package/commands/Credit.sol
CHANGED
|
@@ -22,17 +22,18 @@ abstract contract CreditAccountHook {
|
|
|
22
22
|
/// An optional ACCOUNT block in the request overrides the default `c.account` destination.
|
|
23
23
|
abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
24
24
|
string private constant NAME = "creditAccount";
|
|
25
|
+
string private constant REQUEST = string.concat(Schemas.Unit, ", maybe ", Schemas.Account);
|
|
25
26
|
|
|
26
27
|
uint internal immutable creditAccountId = commandId(NAME);
|
|
27
28
|
|
|
28
29
|
constructor() {
|
|
29
|
-
emit Command(host, creditAccountId, NAME,
|
|
30
|
+
emit Command(host, creditAccountId, NAME, "0:1:0", REQUEST, Keys.Balance, Keys.Empty, false);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
function creditAccount(
|
|
33
34
|
CommandContext calldata c
|
|
34
|
-
) external onlyCommand
|
|
35
|
-
(Cur memory state,
|
|
35
|
+
) external onlyCommand returns (bytes memory) {
|
|
36
|
+
(Cur memory state, ) = cursor(c.state, 1);
|
|
36
37
|
bytes32 to = Cursors.resolveAccount(c.request, c.account);
|
|
37
38
|
|
|
38
39
|
while (state.i < state.bound) {
|
|
@@ -40,7 +41,7 @@ abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
|
40
41
|
creditAccount(to, asset, meta, amount);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
state.
|
|
44
|
+
state.close();
|
|
44
45
|
return "";
|
|
45
46
|
}
|
|
46
47
|
}
|
package/commands/Debit.sol
CHANGED
|
@@ -27,15 +27,15 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
27
27
|
uint internal immutable debitAccountId = commandId(NAME);
|
|
28
28
|
|
|
29
29
|
constructor() {
|
|
30
|
-
emit Command(host, debitAccountId, NAME, Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
30
|
+
emit Command(host, debitAccountId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/// @notice Override to customize request parsing or batching for debits.
|
|
34
34
|
/// The default implementation iterates AMOUNT blocks, calls
|
|
35
35
|
/// `debitAccount`, and emits matching BALANCE blocks.
|
|
36
36
|
function debitAccount(bytes32 account, bytes calldata request) internal virtual returns (bytes memory) {
|
|
37
|
-
(Cur memory input, uint
|
|
38
|
-
Writer memory writer = Writers.allocBalances(
|
|
37
|
+
(Cur memory input, uint groups) = cursor(request, 1);
|
|
38
|
+
Writer memory writer = Writers.allocBalances(groups);
|
|
39
39
|
|
|
40
40
|
while (input.i < input.bound) {
|
|
41
41
|
(bytes32 asset, bytes32 meta, uint amount) = input.unpackAmount();
|
|
@@ -43,12 +43,13 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
43
43
|
writer.appendBalance(asset, meta, amount);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
input.close();
|
|
47
|
+
return writer.finish();
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
function debitAccount(
|
|
50
51
|
CommandContext calldata c
|
|
51
|
-
) external onlyCommand
|
|
52
|
+
) external onlyCommand returns (bytes memory) {
|
|
52
53
|
return debitAccount(c.account, c.request);
|
|
53
54
|
}
|
|
54
55
|
}
|
package/commands/Deposit.sol
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
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
|
+
import { Payable } from "../core/Payable.sol";
|
|
5
6
|
import { Cursors, Cur, Schemas, Writer, Writers } from "../Cursors.sol";
|
|
6
|
-
import { Budget
|
|
7
|
+
import { Budget } from "../utils/Value.sol";
|
|
7
8
|
|
|
8
9
|
using Cursors for Cur;
|
|
9
10
|
using Writers for Writer;
|
|
@@ -41,14 +42,14 @@ abstract contract Deposit is CommandBase, DepositHook {
|
|
|
41
42
|
uint internal immutable depositId = commandId(NAME);
|
|
42
43
|
|
|
43
44
|
constructor() {
|
|
44
|
-
emit Command(host, depositId, NAME, Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
45
|
+
emit Command(host, depositId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
function deposit(
|
|
48
49
|
CommandContext calldata c
|
|
49
|
-
) external onlyCommand
|
|
50
|
-
(Cur memory request, uint
|
|
51
|
-
Writer memory writer = Writers.allocBalances(
|
|
50
|
+
) external onlyCommand returns (bytes memory) {
|
|
51
|
+
(Cur memory request, uint groups) = cursor(c.request, 1);
|
|
52
|
+
Writer memory writer = Writers.allocBalances(groups);
|
|
52
53
|
|
|
53
54
|
while (request.i < request.bound) {
|
|
54
55
|
(bytes32 asset, bytes32 meta, uint amount) = request.unpackAmount();
|
|
@@ -56,28 +57,29 @@ abstract contract Deposit is CommandBase, DepositHook {
|
|
|
56
57
|
writer.appendBalance(asset, meta, amount);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
request.close();
|
|
61
|
+
return writer.finish();
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
/// @title DepositPayable
|
|
64
66
|
/// @notice Command that receives externally sourced assets and records them as BALANCE state.
|
|
65
67
|
/// Use `depositPayable` when the hook needs tracked access to `msg.value` via a mutable budget.
|
|
66
|
-
abstract contract DepositPayable is
|
|
68
|
+
abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
|
|
67
69
|
string private constant NAME = "depositPayable";
|
|
68
70
|
|
|
69
71
|
uint internal immutable depositPayableId = commandId(NAME);
|
|
70
72
|
|
|
71
73
|
constructor() {
|
|
72
|
-
emit Command(host, depositPayableId, NAME, Schemas.Amount, Keys.Empty, Keys.Balance, true);
|
|
74
|
+
emit Command(host, depositPayableId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, true);
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
function depositPayable(
|
|
76
78
|
CommandContext calldata c
|
|
77
|
-
) external payable onlyCommand
|
|
78
|
-
(Cur memory request, uint
|
|
79
|
-
Writer memory writer = Writers.allocBalances(
|
|
80
|
-
Budget memory budget =
|
|
79
|
+
) external payable onlyCommand returns (bytes memory) {
|
|
80
|
+
(Cur memory request, uint groups) = cursor(c.request, 1);
|
|
81
|
+
Writer memory writer = Writers.allocBalances(groups);
|
|
82
|
+
Budget memory budget = valueBudget();
|
|
81
83
|
|
|
82
84
|
while (request.i < request.bound) {
|
|
83
85
|
(bytes32 asset, bytes32 meta, uint amount) = request.unpackAmount();
|
|
@@ -86,7 +88,8 @@ abstract contract DepositPayable is CommandPayable, DepositPayableHook {
|
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
settleValue(c.account, budget);
|
|
89
|
-
|
|
91
|
+
request.close();
|
|
92
|
+
return writer.finish();
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
95
|
|
package/commands/Provision.sol
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
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
|
+
import {Payable} from "../core/Payable.sol";
|
|
5
6
|
import {HostAmount, Cursors, Cur, Schemas, Writer, Writers} from "../Cursors.sol";
|
|
6
|
-
import {Budget
|
|
7
|
+
import {Budget} from "../utils/Value.sol";
|
|
7
8
|
using Cursors for Cur;
|
|
8
9
|
using Writers for Writer;
|
|
9
10
|
|
|
@@ -37,12 +38,12 @@ abstract contract Provision is CommandBase, ProvisionHook {
|
|
|
37
38
|
uint internal immutable provisionId = commandId(NAME);
|
|
38
39
|
|
|
39
40
|
constructor() {
|
|
40
|
-
emit Command(host, provisionId, NAME, Schemas.Allocation, Keys.Empty, Keys.Custody, false);
|
|
41
|
+
emit Command(host, provisionId, NAME, "1:0:1", Schemas.Allocation, Keys.Empty, Keys.Custody, false);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
function provision(CommandContext calldata c) external onlyCommand
|
|
44
|
-
(Cur memory request, uint
|
|
45
|
-
Writer memory writer = Writers.allocCustodies(
|
|
44
|
+
function provision(CommandContext calldata c) external onlyCommand returns (bytes memory) {
|
|
45
|
+
(Cur memory request, uint groups) = cursor(c.request, 1);
|
|
46
|
+
Writer memory writer = Writers.allocCustodies(groups);
|
|
46
47
|
|
|
47
48
|
while (request.i < request.bound) {
|
|
48
49
|
HostAmount memory allocation = request.unpackAllocationValue();
|
|
@@ -50,7 +51,8 @@ abstract contract Provision is CommandBase, ProvisionHook {
|
|
|
50
51
|
writer.appendCustody(allocation);
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
request.close();
|
|
55
|
+
return writer.finish();
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -58,21 +60,21 @@ abstract contract Provision is CommandBase, ProvisionHook {
|
|
|
58
60
|
/// @notice Command that provisions assets to peer hosts from ALLOCATION request blocks.
|
|
59
61
|
/// Each request block supplies the target host plus an asset amount; the output is a CUSTODY state stream.
|
|
60
62
|
/// The hook receives a mutable native-value budget drawn from `msg.value`.
|
|
61
|
-
abstract contract ProvisionPayable is
|
|
63
|
+
abstract contract ProvisionPayable is CommandBase, Payable, ProvisionPayableHook {
|
|
62
64
|
string private constant NAME = "provisionPayable";
|
|
63
65
|
|
|
64
66
|
uint internal immutable provisionPayableId = commandId(NAME);
|
|
65
67
|
|
|
66
68
|
constructor() {
|
|
67
|
-
emit Command(host, provisionPayableId, NAME, Schemas.Allocation, Keys.Empty, Keys.Custody, true);
|
|
69
|
+
emit Command(host, provisionPayableId, NAME, "1:0:1", Schemas.Allocation, Keys.Empty, Keys.Custody, true);
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
function provisionPayable(
|
|
71
73
|
CommandContext calldata c
|
|
72
|
-
) external payable onlyCommand
|
|
73
|
-
(Cur memory request, uint
|
|
74
|
-
Writer memory writer = Writers.allocCustodies(
|
|
75
|
-
Budget memory budget =
|
|
74
|
+
) external payable onlyCommand returns (bytes memory) {
|
|
75
|
+
(Cur memory request, uint groups) = cursor(c.request, 1);
|
|
76
|
+
Writer memory writer = Writers.allocCustodies(groups);
|
|
77
|
+
Budget memory budget = valueBudget();
|
|
76
78
|
|
|
77
79
|
while (request.i < request.bound) {
|
|
78
80
|
HostAmount memory allocation = request.unpackAllocationValue();
|
|
@@ -81,7 +83,8 @@ abstract contract ProvisionPayable is CommandPayable, ProvisionPayableHook {
|
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
settleValue(c.account, budget);
|
|
84
|
-
|
|
86
|
+
request.close();
|
|
87
|
+
return writer.finish();
|
|
85
88
|
}
|
|
86
89
|
}
|
|
87
90
|
|
package/commands/Transfer.sol
CHANGED
|
@@ -23,7 +23,7 @@ abstract contract Transfer is CommandBase, TransferHook {
|
|
|
23
23
|
uint internal immutable transferId = commandId(NAME);
|
|
24
24
|
|
|
25
25
|
constructor() {
|
|
26
|
-
emit Command(host, transferId, NAME, Schemas.Payout, Keys.Empty, Keys.Empty, false);
|
|
26
|
+
emit Command(host, transferId, NAME, "1:0:0", Schemas.Payout, Keys.Empty, Keys.Empty, false);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/// @notice Override to customize request parsing or batching for transfers.
|
|
@@ -32,7 +32,7 @@ abstract contract Transfer is CommandBase, TransferHook {
|
|
|
32
32
|
/// @param request Full request bytes.
|
|
33
33
|
/// @return Empty bytes (transfers produce no state output).
|
|
34
34
|
function transfer(bytes32 from, bytes calldata request) internal virtual returns (bytes memory) {
|
|
35
|
-
(Cur memory input,
|
|
35
|
+
(Cur memory input, ) = cursor(request, 1);
|
|
36
36
|
Tx memory value;
|
|
37
37
|
value.from = from;
|
|
38
38
|
|
|
@@ -42,13 +42,13 @@ abstract contract Transfer is CommandBase, TransferHook {
|
|
|
42
42
|
transfer(value);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
input.
|
|
45
|
+
input.close();
|
|
46
46
|
return "";
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function transfer(
|
|
50
50
|
CommandContext calldata c
|
|
51
|
-
) external onlyCommand
|
|
51
|
+
) external onlyCommand returns (bytes memory) {
|
|
52
52
|
return transfer(c.account, c.request);
|
|
53
53
|
}
|
|
54
54
|
}
|
package/commands/Withdraw.sol
CHANGED
|
@@ -21,17 +21,18 @@ abstract contract WithdrawHook {
|
|
|
21
21
|
/// For internal balance credits, use `creditAccount` instead.
|
|
22
22
|
abstract contract Withdraw is CommandBase, WithdrawHook {
|
|
23
23
|
string private constant NAME = "withdraw";
|
|
24
|
+
string private constant REQUEST = string.concat(Schemas.Unit, ", maybe ", Schemas.Account);
|
|
24
25
|
|
|
25
26
|
uint internal immutable withdrawId = commandId(NAME);
|
|
26
27
|
|
|
27
28
|
constructor() {
|
|
28
|
-
emit Command(host, withdrawId, NAME,
|
|
29
|
+
emit Command(host, withdrawId, NAME, "0:1:0", REQUEST, Keys.Balance, Keys.Empty, false);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
function withdraw(
|
|
32
33
|
CommandContext calldata c
|
|
33
|
-
) external onlyCommand
|
|
34
|
-
(Cur memory state,
|
|
34
|
+
) external onlyCommand returns (bytes memory) {
|
|
35
|
+
(Cur memory state, ) = cursor(c.state, 1);
|
|
35
36
|
bytes32 to = Cursors.resolveAccount(c.request, c.account);
|
|
36
37
|
|
|
37
38
|
while (state.i < state.bound) {
|
|
@@ -39,7 +40,7 @@ abstract contract Withdraw is CommandBase, WithdrawHook {
|
|
|
39
40
|
withdraw(to, asset, meta, amount);
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
state.
|
|
43
|
+
state.close();
|
|
43
44
|
return "";
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -21,20 +21,20 @@ abstract contract AllowAssets is CommandBase, AdminEvent, AllowAssetsHook {
|
|
|
21
21
|
uint internal immutable allowAssetsId = commandId(NAME);
|
|
22
22
|
|
|
23
23
|
constructor() {
|
|
24
|
-
emit Admin(host, allowAssetsId, NAME, Schemas.Asset, Keys.Empty, Keys.Empty, false);
|
|
24
|
+
emit Admin(host, allowAssetsId, NAME, "1:0:0", Schemas.Asset, Keys.Empty, Keys.Empty, false);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function allowAssets(
|
|
28
28
|
CommandContext calldata c
|
|
29
29
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
30
|
-
(Cur memory request,
|
|
30
|
+
(Cur memory request, ) = cursor(c.request, 1);
|
|
31
31
|
|
|
32
32
|
while (request.i < request.bound) {
|
|
33
33
|
(bytes32 asset, bytes32 meta) = request.unpackAsset();
|
|
34
34
|
allowAsset(asset, meta);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
request.
|
|
37
|
+
request.close();
|
|
38
38
|
return "";
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -26,18 +26,18 @@ abstract contract Allowance is CommandBase, AdminEvent, AllowanceHook {
|
|
|
26
26
|
uint internal immutable allowanceId = commandId(NAME);
|
|
27
27
|
|
|
28
28
|
constructor() {
|
|
29
|
-
emit Admin(host, allowanceId, NAME, Schemas.Allowance, Keys.Empty, Keys.Empty, false);
|
|
29
|
+
emit Admin(host, allowanceId, NAME, "1:0:0", Schemas.Allowance, Keys.Empty, Keys.Empty, false);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function allowance(CommandContext calldata c) external onlyAdmin(c.account) returns (bytes memory) {
|
|
33
|
-
(Cur memory request,
|
|
33
|
+
(Cur memory request, ) = cursor(c.request, 1);
|
|
34
34
|
|
|
35
35
|
while (request.i < request.bound) {
|
|
36
36
|
(uint peer, bytes32 asset, bytes32 meta, uint amount) = request.unpackAllowance();
|
|
37
37
|
allowance(peer, asset, meta, amount);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
request.
|
|
40
|
+
request.close();
|
|
41
41
|
return "";
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -16,20 +16,20 @@ abstract contract Authorize is CommandBase, AdminEvent {
|
|
|
16
16
|
uint internal immutable authorizeId = commandId(NAME);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
|
-
emit Admin(host, authorizeId, NAME, Schemas.Node, Keys.Empty, Keys.Empty, false);
|
|
19
|
+
emit Admin(host, authorizeId, NAME, "1:0:0", Schemas.Node, Keys.Empty, Keys.Empty, false);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function authorize(
|
|
23
23
|
CommandContext calldata c
|
|
24
24
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
25
|
-
(Cur memory request,
|
|
25
|
+
(Cur memory request, ) = cursor(c.request, 1);
|
|
26
26
|
|
|
27
27
|
while (request.i < request.bound) {
|
|
28
28
|
uint node = request.unpackNode();
|
|
29
29
|
authorize(node);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
request.
|
|
32
|
+
request.close();
|
|
33
33
|
return "";
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -21,20 +21,20 @@ abstract contract DenyAssets is CommandBase, AdminEvent, DenyAssetsHook {
|
|
|
21
21
|
uint internal immutable denyAssetsId = commandId(NAME);
|
|
22
22
|
|
|
23
23
|
constructor() {
|
|
24
|
-
emit Admin(host, denyAssetsId, NAME, Schemas.Asset, Keys.Empty, Keys.Empty, false);
|
|
24
|
+
emit Admin(host, denyAssetsId, NAME, "1:0:0", Schemas.Asset, Keys.Empty, Keys.Empty, false);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function denyAssets(
|
|
28
28
|
CommandContext calldata c
|
|
29
29
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
30
|
-
(Cur memory request,
|
|
30
|
+
(Cur memory request, ) = cursor(c.request, 1);
|
|
31
31
|
|
|
32
32
|
while (request.i < request.bound) {
|
|
33
33
|
(bytes32 asset, bytes32 meta) = request.unpackAsset();
|
|
34
34
|
denyAsset(asset, meta);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
request.
|
|
37
|
+
request.close();
|
|
38
38
|
return "";
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -22,7 +22,7 @@ abstract contract Destroy is CommandBase, AdminEvent, DestroyHook {
|
|
|
22
22
|
uint internal immutable destroyId = commandId(NAME);
|
|
23
23
|
|
|
24
24
|
constructor(string memory input) {
|
|
25
|
-
emit Admin(host, destroyId, NAME, input, Keys.Empty, Keys.Empty, false);
|
|
25
|
+
emit Admin(host, destroyId, NAME, "1:0:0", input, Keys.Empty, Keys.Empty, false);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function destroy(
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {CommandBase, CommandContext, Keys} from "../Base.sol";
|
|
5
|
+
import {Payable} from "../../core/Payable.sol";
|
|
5
6
|
import {Cursors, Cur, Schemas} from "../../Cursors.sol";
|
|
6
7
|
import {AdminEvent} from "../../events/Admin.sol";
|
|
7
|
-
import {Budget
|
|
8
|
+
import {Budget} from "../../utils/Value.sol";
|
|
8
9
|
import {Ids} from "../../utils/Ids.sol";
|
|
9
10
|
|
|
10
11
|
using Cursors for Cur;
|
|
@@ -13,26 +14,26 @@ using Cursors for Cur;
|
|
|
13
14
|
/// @notice Admin command that forwards raw calldata to one or more target nodes.
|
|
14
15
|
/// Each CALL block specifies a target node ID, native value, and raw calldata payload.
|
|
15
16
|
/// Only callable by the admin account.
|
|
16
|
-
abstract contract ExecutePayable is
|
|
17
|
+
abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
|
|
17
18
|
string private constant NAME = "executePayable";
|
|
18
19
|
|
|
19
20
|
uint internal immutable executePayableId = commandId(NAME);
|
|
20
21
|
|
|
21
22
|
constructor() {
|
|
22
|
-
emit Admin(host, executePayableId, NAME, Schemas.Call, Keys.Empty, Keys.Empty, true);
|
|
23
|
+
emit Admin(host, executePayableId, NAME, "1:0:0", Schemas.Call, Keys.Empty, Keys.Empty, true);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
function executePayable(CommandContext calldata c) external payable onlyAdmin(c.account) returns (bytes memory) {
|
|
26
|
-
(Cur memory request,
|
|
27
|
-
Budget memory budget =
|
|
27
|
+
(Cur memory request, ) = cursor(c.request, 1);
|
|
28
|
+
Budget memory budget = valueBudget();
|
|
28
29
|
|
|
29
30
|
while (request.i < request.bound) {
|
|
30
31
|
(uint target, uint value, bytes calldata data) = request.unpackCall();
|
|
31
32
|
address addr = Ids.nodeAddr(target);
|
|
32
|
-
callAddr(addr,
|
|
33
|
+
callAddr(addr, useValue(budget, value), data);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
request.
|
|
36
|
+
request.close();
|
|
36
37
|
settleValue(c.account, budget);
|
|
37
38
|
return "";
|
|
38
39
|
}
|
package/commands/admin/Init.sol
CHANGED
|
@@ -22,7 +22,7 @@ abstract contract Init is CommandBase, AdminEvent, InitHook {
|
|
|
22
22
|
uint internal immutable initId = commandId(NAME);
|
|
23
23
|
|
|
24
24
|
constructor(string memory input) {
|
|
25
|
-
emit Admin(host, initId, NAME, input, Keys.Empty, Keys.Empty, false);
|
|
25
|
+
emit Admin(host, initId, NAME, "1:0:0", input, Keys.Empty, Keys.Empty, false);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function init(
|
|
@@ -16,20 +16,20 @@ abstract contract Unauthorize is CommandBase, AdminEvent {
|
|
|
16
16
|
uint internal immutable unauthorizeId = commandId(NAME);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
|
-
emit Admin(host, unauthorizeId, NAME, Schemas.Node, Keys.Empty, Keys.Empty, false);
|
|
19
|
+
emit Admin(host, unauthorizeId, NAME, "1:0:0", Schemas.Node, Keys.Empty, Keys.Empty, false);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function unauthorize(
|
|
23
23
|
CommandContext calldata c
|
|
24
24
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
25
|
-
(Cur memory request,
|
|
25
|
+
(Cur memory request, ) = cursor(c.request, 1);
|
|
26
26
|
|
|
27
27
|
while (request.i < request.bound) {
|
|
28
28
|
uint node = request.unpackNode();
|
|
29
29
|
unauthorize(node);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
request.
|
|
32
|
+
request.close();
|
|
33
33
|
return "";
|
|
34
34
|
}
|
|
35
35
|
}
|
package/core/Access.sol
CHANGED
|
@@ -78,4 +78,15 @@ abstract contract AccessControl is RootZeroContext, AccessEvent {
|
|
|
78
78
|
}
|
|
79
79
|
return caller;
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
/// @notice Assert that `caller` is the commander and return it.
|
|
83
|
+
/// Used by admin modifiers to keep governance authority separate from peer trust.
|
|
84
|
+
/// @param caller Address to validate.
|
|
85
|
+
/// @return The same `caller` value if it is the commander.
|
|
86
|
+
function enforceCommander(address caller) internal view returns (address) {
|
|
87
|
+
if (caller == address(0) || caller != commander) {
|
|
88
|
+
revert UnauthorizedCaller(caller);
|
|
89
|
+
}
|
|
90
|
+
return caller;
|
|
91
|
+
}
|
|
81
92
|
}
|
package/core/Context.sol
CHANGED
|
@@ -27,23 +27,21 @@ abstract contract RootZeroContext {
|
|
|
27
27
|
/// @param source Calldata slice to parse.
|
|
28
28
|
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
29
29
|
/// @return cur Cursor with `bound` set to the end of the first run.
|
|
30
|
-
/// @return
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
cur = Cursors.open(source);
|
|
34
|
-
(, count, quotient) = cur.primeRun(group);
|
|
30
|
+
/// @return groups Number of block groups in the run (`prime block count / group`).
|
|
31
|
+
function cursor(bytes calldata source, uint group) internal pure returns (Cur memory cur, uint groups) {
|
|
32
|
+
return Cursors.init(source, group);
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
/// @notice Open a cursor, prime it, and assert that its
|
|
38
|
-
/// Equivalent to `open(source)` followed by `primeRun(group)` and a direct
|
|
39
|
-
/// Reverts with `Cursors.BadRatio` when the
|
|
35
|
+
/// @notice Open a cursor, prime it, and assert that its group count matches `expectedGroups`.
|
|
36
|
+
/// Equivalent to `open(source)` followed by `primeRun(group)` and a direct group-count equality check.
|
|
37
|
+
/// Reverts with `Cursors.BadRatio` when the group count does not match.
|
|
40
38
|
/// @param source Calldata slice to parse.
|
|
41
39
|
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
42
|
-
/// @param
|
|
40
|
+
/// @param expectedGroups Required number of groups in the first run.
|
|
43
41
|
/// @return cur Cursor with `bound` set to the end of the first run.
|
|
44
|
-
function cursor(bytes calldata source, uint group, uint
|
|
45
|
-
|
|
46
|
-
(,
|
|
47
|
-
if (
|
|
42
|
+
function cursor(bytes calldata source, uint group, uint expectedGroups) internal pure returns (Cur memory cur) {
|
|
43
|
+
uint groups;
|
|
44
|
+
(cur, groups) = Cursors.init(source, group);
|
|
45
|
+
if (groups != expectedGroups) revert Cursors.BadRatio();
|
|
48
46
|
}
|
|
49
47
|
}
|