@rootzero/contracts 0.8.0 → 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 +5 -10
- package/Core.sol +3 -4
- package/Cursors.sol +4 -6
- package/Events.sol +1 -1
- package/Queries.sol +1 -1
- package/README.md +18 -19
- package/Utils.sol +3 -3
- package/blocks/Cursors.sol +1437 -0
- package/blocks/Keys.sol +59 -34
- package/blocks/Schema.sol +109 -126
- package/blocks/Writers.sol +476 -301
- package/commands/Base.sol +32 -22
- package/commands/Burn.sol +3 -3
- package/commands/Credit.sol +6 -7
- package/commands/Debit.sol +3 -3
- package/commands/Deposit.sol +7 -7
- package/commands/Pipe.sol +3 -3
- package/commands/Provision.sol +19 -49
- package/commands/Transfer.sol +9 -19
- package/commands/Withdraw.sol +5 -6
- 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 +3 -3
- package/commands/admin/Execute.sol +38 -0
- package/commands/admin/Init.sol +3 -3
- 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 +10 -9
- 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 +1 -1
- package/peer/Base.sol +8 -4
- package/peer/DenyAssets.sol +1 -1
- package/peer/Settle.sol +3 -4
- package/queries/Assets.sol +8 -8
- package/queries/Balances.sol +11 -11
- package/queries/Base.sol +2 -3
- package/queries/Positions.sol +25 -19
- package/utils/Accounts.sol +14 -13
- package/utils/Assets.sol +77 -57
- package/utils/Ids.sol +4 -4
- package/utils/Layout.sol +1 -1
- package/utils/Utils.sol +10 -0
- package/blocks/cursors/Core.sol +0 -1121
- package/blocks/cursors/Erc1155.sol +0 -149
- package/blocks/cursors/Erc20.sol +0 -130
- package/blocks/cursors/Erc721.sol +0 -66
- package/commands/Create.sol +0 -44
- package/commands/Remove.sol +0 -44
- package/commands/Settle.sol +0 -38
- package/commands/Stake.sol +0 -49
- package/commands/Supply.sol +0 -43
- package/commands/admin/Allocate.sol +0 -43
- package/core/HostBound.sol +0 -14
- package/events/Erc721.sol +0 -20
- package/peer/Pull.sol +0 -41
- package/peer/Push.sol +0 -47
- package/utils/State.sol +0 -22
package/commands/Base.sol
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {NodeCalls} from "../core/Calls.sol";
|
|
5
5
|
import {Cur} from "../Cursors.sol";
|
|
6
6
|
import {CommandEvent} from "../events/Command.sol";
|
|
7
|
-
import {
|
|
7
|
+
import {Keys} from "../blocks/Keys.sol";
|
|
8
8
|
import {Ids, Selectors} from "../utils/Ids.sol";
|
|
9
9
|
import {Budget, Values} from "../utils/Value.sol";
|
|
10
10
|
|
|
11
11
|
/// @notice Execution context passed to every command invocation.
|
|
12
12
|
struct CommandContext {
|
|
13
|
-
/// @dev Destination command node ID; zero means "any command on this host".
|
|
14
|
-
uint target;
|
|
15
13
|
/// @dev Caller's account identifier.
|
|
16
14
|
bytes32 account;
|
|
17
15
|
/// @dev Current state block stream (previous command output or initial state).
|
|
@@ -20,22 +18,22 @@ struct CommandContext {
|
|
|
20
18
|
bytes request;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
/// @notice ABI-encode a command call from a
|
|
24
|
-
/// @dev Derives the function selector from `
|
|
25
|
-
/// Reverts if `
|
|
26
|
-
/// @param
|
|
21
|
+
/// @notice ABI-encode a command call from a command ID and execution context.
|
|
22
|
+
/// @dev Derives the function selector from `cid` via `Ids.commandSelector(cid)`.
|
|
23
|
+
/// Reverts if `cid` is not a valid command ID.
|
|
24
|
+
/// @param cid Command node ID embedding the target selector.
|
|
27
25
|
/// @param account Caller account identifier for the command context.
|
|
28
26
|
/// @param state Current state block stream passed to the command.
|
|
29
27
|
/// @param request Input block stream for the command invocation.
|
|
30
28
|
/// @return ABI-encoded calldata for the command entry point.
|
|
31
29
|
function encodeCommandCall(
|
|
32
|
-
uint
|
|
30
|
+
uint cid,
|
|
33
31
|
bytes32 account,
|
|
34
32
|
bytes memory state,
|
|
35
33
|
bytes calldata request
|
|
36
34
|
) pure returns (bytes memory) {
|
|
37
|
-
bytes4 selector = Ids.commandSelector(
|
|
38
|
-
CommandContext memory ctx = CommandContext(
|
|
35
|
+
bytes4 selector = Ids.commandSelector(cid);
|
|
36
|
+
CommandContext memory ctx = CommandContext(account, state, request);
|
|
39
37
|
return abi.encodeWithSelector(selector, ctx);
|
|
40
38
|
}
|
|
41
39
|
|
|
@@ -43,26 +41,31 @@ function encodeCommandCall(
|
|
|
43
41
|
/// @notice Abstract base for all rootzero command contracts.
|
|
44
42
|
/// Provides access control modifiers, event emission, and the `commandId`
|
|
45
43
|
/// helper used to derive stable identifiers for named commands.
|
|
46
|
-
abstract contract CommandBase is
|
|
44
|
+
abstract contract CommandBase is NodeCalls, CommandEvent {
|
|
47
45
|
/// @dev Thrown when `onlyActive` finds that `deadline` has already passed.
|
|
48
46
|
error Expired();
|
|
47
|
+
/// @dev Thrown when the raw active account word in calldata does not match the decoded context account.
|
|
48
|
+
error ActiveAccountMismatch();
|
|
49
49
|
/// @dev Thrown when `onlyAdmin` finds that `account` is not the admin account.
|
|
50
50
|
error NotAdmin();
|
|
51
|
-
/// @dev Thrown when `onlyCommand` finds that `target` does not match this command's ID.
|
|
52
|
-
error UnexpectedEndpoint();
|
|
53
51
|
|
|
54
|
-
/// @dev Restrict execution to
|
|
52
|
+
/// @dev Restrict execution to trusted callers whose decoded context account matches the active calldata account.
|
|
53
|
+
modifier onlyCommand(bytes32 account) {
|
|
54
|
+
if (activeAccount() != account) revert ActiveAccountMismatch();
|
|
55
|
+
enforceCaller(msg.sender);
|
|
56
|
+
_;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// @dev Restrict execution to trusted callers using the host's admin account.
|
|
55
60
|
modifier onlyAdmin(bytes32 account) {
|
|
61
|
+
if (activeAccount() != account) revert ActiveAccountMismatch();
|
|
56
62
|
if (account != adminAccount) revert NotAdmin();
|
|
63
|
+
enforceCaller(msg.sender);
|
|
57
64
|
_;
|
|
58
65
|
}
|
|
59
66
|
|
|
60
|
-
/// @dev Restrict execution to
|
|
61
|
-
|
|
62
|
-
/// @param cid This command's node ID (from `commandId`).
|
|
63
|
-
/// @param target Requested destination from the `CommandContext`.
|
|
64
|
-
modifier onlyCommand(uint cid, uint target) {
|
|
65
|
-
if (target != 0 && target != cid) revert UnexpectedEndpoint();
|
|
67
|
+
/// @dev Restrict execution to callers whose host node is trusted.
|
|
68
|
+
modifier onlyTrusted() {
|
|
66
69
|
enforceCaller(msg.sender);
|
|
67
70
|
_;
|
|
68
71
|
}
|
|
@@ -75,13 +78,20 @@ abstract contract CommandBase is OperationBase, CommandEvent {
|
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
/// @notice Derive the deterministic node ID for a named command on this contract.
|
|
78
|
-
/// The ID encodes the ABI selector of `name((
|
|
81
|
+
/// The ID encodes the ABI selector of `name((bytes32,bytes,bytes))` and
|
|
79
82
|
/// `address(this)`, making it unique per (function name, contract address) pair.
|
|
80
83
|
/// @param name Command function name (without argument list).
|
|
81
84
|
/// @return Command node ID.
|
|
82
85
|
function commandId(string memory name) internal view returns (uint) {
|
|
83
86
|
return Ids.toCommand(Selectors.command(name), address(this));
|
|
84
87
|
}
|
|
88
|
+
|
|
89
|
+
/// @notice Return the active command account directly from the fixed tuple head in calldata.
|
|
90
|
+
/// @dev Command entrypoints use the ABI shape `name((bytes32,bytes,bytes))`, so the tuple head
|
|
91
|
+
/// starts at byte 36 of `msg.data`, with the account field at bytes [36:68).
|
|
92
|
+
function activeAccount() internal pure returns (bytes32 account) {
|
|
93
|
+
account = bytes32(msg.data[36:68]);
|
|
94
|
+
}
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
/// @title CommandPayable
|
package/commands/Burn.sol
CHANGED
|
@@ -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 } from "../Cursors.sol";
|
|
6
6
|
using Cursors for Cur;
|
|
7
7
|
|
|
@@ -25,10 +25,10 @@ abstract contract Burn is CommandBase, BurnHook {
|
|
|
25
25
|
uint internal immutable burnId = commandId(NAME);
|
|
26
26
|
|
|
27
27
|
constructor() {
|
|
28
|
-
emit Command(host, NAME, "",
|
|
28
|
+
emit Command(host, burnId, NAME, "", Keys.Balance, Keys.Empty, false);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function burn(CommandContext calldata c) external onlyCommand(
|
|
31
|
+
function burn(CommandContext calldata c) external onlyCommand(c.account) returns (bytes memory) {
|
|
32
32
|
(Cur memory state, , ) = cursor(c.state, 1);
|
|
33
33
|
|
|
34
34
|
while (state.i < state.bound) {
|
package/commands/Credit.sol
CHANGED
|
@@ -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
|
string constant NAME = "creditAccount";
|
|
7
7
|
|
|
@@ -10,7 +10,7 @@ using Cursors for Cur;
|
|
|
10
10
|
abstract contract CreditAccountHook {
|
|
11
11
|
/// @notice Override to credit externally managed funds to `account`.
|
|
12
12
|
/// Called once per BALANCE block in state.
|
|
13
|
-
/// @param account
|
|
13
|
+
/// @param account Destination account identifier.
|
|
14
14
|
/// @param asset Asset identifier.
|
|
15
15
|
/// @param meta Asset metadata slot.
|
|
16
16
|
/// @param amount Amount to credit.
|
|
@@ -20,20 +20,19 @@ abstract contract CreditAccountHook {
|
|
|
20
20
|
/// @title CreditAccount
|
|
21
21
|
/// @notice Command that delivers BALANCE state blocks to an account via a virtual hook.
|
|
22
22
|
/// Use for internally recording credits that have already been settled externally.
|
|
23
|
-
/// An optional
|
|
23
|
+
/// An optional ACCOUNT block in the request overrides the default `c.account` destination.
|
|
24
24
|
abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
25
25
|
uint internal immutable creditAccountId = commandId(NAME);
|
|
26
26
|
|
|
27
27
|
constructor() {
|
|
28
|
-
emit Command(host, NAME, Schemas.
|
|
28
|
+
emit Command(host, creditAccountId, NAME, Schemas.Account, Keys.Balance, Keys.Empty, false);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function creditAccount(
|
|
32
32
|
CommandContext calldata c
|
|
33
|
-
) external onlyCommand(
|
|
33
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
34
34
|
(Cur memory state, , ) = cursor(c.state, 1);
|
|
35
|
-
|
|
36
|
-
bytes32 to = request.recipientAfter(c.account);
|
|
35
|
+
bytes32 to = Cursors.resolveAccount(c.request, c.account);
|
|
37
36
|
|
|
38
37
|
while (state.i < state.bound) {
|
|
39
38
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
package/commands/Debit.sol
CHANGED
|
@@ -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, CommandBase,
|
|
4
|
+
import { CommandContext, CommandBase, Keys } from "./Base.sol";
|
|
5
5
|
import { Cursors, Cur, Schemas, Writer, Writers } from "../Cursors.sol";
|
|
6
6
|
|
|
7
7
|
string constant NAME = "debitAccount";
|
|
@@ -27,7 +27,7 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
27
27
|
uint internal immutable debitAccountId = commandId(NAME);
|
|
28
28
|
|
|
29
29
|
constructor() {
|
|
30
|
-
emit Command(host, NAME, Schemas.Amount,
|
|
30
|
+
emit Command(host, debitAccountId, NAME, Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/// @notice Override to customize request parsing or batching for debits.
|
|
@@ -48,7 +48,7 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
48
48
|
|
|
49
49
|
function debitAccount(
|
|
50
50
|
CommandContext calldata c
|
|
51
|
-
) external onlyCommand(
|
|
51
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
52
52
|
return debitAccount(c.account, c.request);
|
|
53
53
|
}
|
|
54
54
|
}
|
package/commands/Deposit.sol
CHANGED
|
@@ -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, CommandBase, CommandPayable,
|
|
4
|
+
import { CommandContext, CommandBase, CommandPayable, Keys } from "./Base.sol";
|
|
5
5
|
import { Cursors, Cur, Schemas, Writer, Writers } from "../Cursors.sol";
|
|
6
6
|
import { Budget, Values } from "../utils/Value.sol";
|
|
7
7
|
|
|
@@ -15,7 +15,7 @@ abstract contract DepositHook {
|
|
|
15
15
|
/// @notice Override to receive externally sourced funds for `account`.
|
|
16
16
|
/// Called once per AMOUNT block. A matching BALANCE block is appended to the
|
|
17
17
|
/// output after each call.
|
|
18
|
-
/// @param account
|
|
18
|
+
/// @param account Destination account identifier.
|
|
19
19
|
/// @param asset Asset identifier.
|
|
20
20
|
/// @param meta Asset metadata slot.
|
|
21
21
|
/// @param amount Amount received.
|
|
@@ -26,7 +26,7 @@ abstract contract DepositPayableHook {
|
|
|
26
26
|
/// @notice Override to receive externally sourced funds for `account`.
|
|
27
27
|
/// Called once per AMOUNT block. A matching BALANCE block is appended to the
|
|
28
28
|
/// output after each call.
|
|
29
|
-
/// @param account
|
|
29
|
+
/// @param account Destination account identifier.
|
|
30
30
|
/// @param asset Asset identifier.
|
|
31
31
|
/// @param meta Asset metadata slot.
|
|
32
32
|
/// @param amount Amount received.
|
|
@@ -42,12 +42,12 @@ abstract contract Deposit is CommandBase, DepositHook {
|
|
|
42
42
|
uint internal immutable depositId = commandId(DEPOSIT);
|
|
43
43
|
|
|
44
44
|
constructor() {
|
|
45
|
-
emit Command(host, DEPOSIT, Schemas.Amount,
|
|
45
|
+
emit Command(host, depositId, DEPOSIT, Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
function deposit(
|
|
49
49
|
CommandContext calldata c
|
|
50
|
-
) external onlyCommand(
|
|
50
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
51
51
|
(Cur memory request, uint count, ) = cursor(c.request, 1);
|
|
52
52
|
Writer memory writer = Writers.allocBalances(count);
|
|
53
53
|
|
|
@@ -68,12 +68,12 @@ abstract contract DepositPayable is CommandPayable, DepositPayableHook {
|
|
|
68
68
|
uint internal immutable depositPayableId = commandId(DEPOSIT_PAYABLE);
|
|
69
69
|
|
|
70
70
|
constructor() {
|
|
71
|
-
emit Command(host, DEPOSIT_PAYABLE, Schemas.Amount,
|
|
71
|
+
emit Command(host, depositPayableId, DEPOSIT_PAYABLE, Schemas.Amount, Keys.Empty, Keys.Balance, true);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
function depositPayable(
|
|
75
75
|
CommandContext calldata c
|
|
76
|
-
) external payable onlyCommand(
|
|
76
|
+
) external payable onlyCommand(c.account) returns (bytes memory) {
|
|
77
77
|
(Cur memory request, uint count, ) = cursor(c.request, 1);
|
|
78
78
|
Writer memory writer = Writers.allocBalances(count);
|
|
79
79
|
Budget memory budget = Values.fromMsg();
|
package/commands/Pipe.sol
CHANGED
|
@@ -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, CommandPayable} from "./Base.sol";
|
|
4
|
+
import {CommandBase, CommandContext, CommandPayable, Keys} from "./Base.sol";
|
|
5
5
|
import {Cursors, Cur, Schemas} from "../Cursors.sol";
|
|
6
6
|
import {Accounts} from "../utils/Accounts.sol";
|
|
7
7
|
import {Budget, Values} from "../utils/Value.sol";
|
|
@@ -29,7 +29,7 @@ abstract contract PipePayable is CommandPayable, PipePayableHook {
|
|
|
29
29
|
uint internal immutable pipePayableId = commandId(NAME);
|
|
30
30
|
|
|
31
31
|
constructor() {
|
|
32
|
-
emit Command(host, NAME, Schemas.Step,
|
|
32
|
+
emit Command(host, pipePayableId, NAME, Schemas.Step, Keys.Empty, Keys.Empty, true);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function pipe(
|
|
@@ -54,7 +54,7 @@ abstract contract PipePayable is CommandPayable, PipePayableHook {
|
|
|
54
54
|
/// @notice Execute the pipePayable command.
|
|
55
55
|
function pipePayable(
|
|
56
56
|
CommandContext calldata c
|
|
57
|
-
) external payable onlyCommand(
|
|
57
|
+
) external payable onlyCommand(c.account) returns (bytes memory) {
|
|
58
58
|
if (Accounts.isAdmin(c.account)) revert Accounts.InvalidAccount();
|
|
59
59
|
Budget memory budget = Values.fromMsg();
|
|
60
60
|
return pipe(c.account, c.state, c.request, budget);
|
package/commands/Provision.sol
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {CommandContext, CommandBase, CommandPayable,
|
|
5
|
-
import {Cursors, Cur,
|
|
4
|
+
import {CommandContext, CommandBase, CommandPayable, Keys} from "./Base.sol";
|
|
5
|
+
import {HostAmount, Cursors, Cur, Schemas, Writer, Writers} from "../Cursors.sol";
|
|
6
6
|
import {Budget, Values} from "../utils/Value.sol";
|
|
7
7
|
using Cursors for Cur;
|
|
8
8
|
using Writers for Writer;
|
|
9
9
|
|
|
10
10
|
string constant PROVISION = "provision";
|
|
11
11
|
string constant PP = "provisionPayable";
|
|
12
|
-
string constant PFB = "provisionFromBalance";
|
|
13
12
|
|
|
14
|
-
/// @notice Shared provision hook used by
|
|
13
|
+
/// @notice Shared provision hook used by `Provision`.
|
|
15
14
|
abstract contract ProvisionHook {
|
|
16
15
|
/// @notice Override to send or provision a custody value.
|
|
17
16
|
/// Called once per provisioned asset. Implementations should perform only the
|
|
18
17
|
/// side effect (e.g. transfer or record); output blocks are written by the caller.
|
|
19
18
|
/// @param account Caller's account identifier.
|
|
20
|
-
/// @param
|
|
21
|
-
function provision(bytes32 account, HostAmount memory
|
|
19
|
+
/// @param allocation Host-scoped amount to provision.
|
|
20
|
+
function provision(bytes32 account, HostAmount memory allocation) internal virtual;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
/// @notice Shared provision hook used by `ProvisionPayable`.
|
|
@@ -27,29 +26,29 @@ abstract contract ProvisionPayableHook {
|
|
|
27
26
|
/// Called once per provisioned asset. Implementations should perform only the
|
|
28
27
|
/// side effect (e.g. transfer or record); output blocks are written by the caller.
|
|
29
28
|
/// @param account Caller's account identifier.
|
|
30
|
-
/// @param
|
|
29
|
+
/// @param allocation Host-scoped amount to provision.
|
|
31
30
|
/// @param budget Mutable native-value budget drawn from `msg.value`.
|
|
32
|
-
function provision(bytes32 account, HostAmount memory
|
|
31
|
+
function provision(bytes32 account, HostAmount memory allocation, Budget memory budget) internal virtual;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
/// @title Provision
|
|
36
|
-
/// @notice Command that provisions assets to remote hosts from
|
|
35
|
+
/// @notice Command that provisions assets to remote hosts from ALLOCATION request blocks.
|
|
37
36
|
/// Each request block supplies the target host plus an asset amount; the output is a CUSTODY state stream.
|
|
38
37
|
abstract contract Provision is CommandBase, ProvisionHook {
|
|
39
38
|
uint internal immutable provisionId = commandId(PROVISION);
|
|
40
39
|
|
|
41
40
|
constructor() {
|
|
42
|
-
emit Command(host, PROVISION, Schemas.
|
|
41
|
+
emit Command(host, provisionId, PROVISION, Schemas.Allocation, Keys.Empty, Keys.Custody, false);
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
function provision(CommandContext calldata c) external onlyCommand(
|
|
44
|
+
function provision(CommandContext calldata c) external onlyCommand(c.account) returns (bytes memory) {
|
|
46
45
|
(Cur memory request, uint count, ) = cursor(c.request, 1);
|
|
47
46
|
Writer memory writer = Writers.allocCustodies(count);
|
|
48
47
|
|
|
49
48
|
while (request.i < request.bound) {
|
|
50
|
-
HostAmount memory
|
|
51
|
-
provision(c.account,
|
|
52
|
-
writer.appendCustody(
|
|
49
|
+
HostAmount memory allocation = request.unpackAllocationValue();
|
|
50
|
+
provision(c.account, allocation);
|
|
51
|
+
writer.appendCustody(allocation);
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
return request.complete(writer);
|
|
@@ -57,27 +56,27 @@ abstract contract Provision is CommandBase, ProvisionHook {
|
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
/// @title ProvisionPayable
|
|
60
|
-
/// @notice Command that provisions assets to remote hosts from
|
|
59
|
+
/// @notice Command that provisions assets to remote hosts from ALLOCATION request blocks.
|
|
61
60
|
/// Each request block supplies the target host plus an asset amount; the output is a CUSTODY state stream.
|
|
62
61
|
/// The hook receives a mutable native-value budget drawn from `msg.value`.
|
|
63
62
|
abstract contract ProvisionPayable is CommandPayable, ProvisionPayableHook {
|
|
64
63
|
uint internal immutable provisionPayableId = commandId(PP);
|
|
65
64
|
|
|
66
65
|
constructor() {
|
|
67
|
-
emit Command(host, PP, Schemas.
|
|
66
|
+
emit Command(host, provisionPayableId, PP, Schemas.Allocation, Keys.Empty, Keys.Custody, true);
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
function provisionPayable(
|
|
71
70
|
CommandContext calldata c
|
|
72
|
-
) external payable onlyCommand(
|
|
71
|
+
) external payable onlyCommand(c.account) returns (bytes memory) {
|
|
73
72
|
(Cur memory request, uint count, ) = cursor(c.request, 1);
|
|
74
73
|
Writer memory writer = Writers.allocCustodies(count);
|
|
75
74
|
Budget memory budget = Values.fromMsg();
|
|
76
75
|
|
|
77
76
|
while (request.i < request.bound) {
|
|
78
|
-
HostAmount memory
|
|
79
|
-
provision(c.account,
|
|
80
|
-
writer.appendCustody(
|
|
77
|
+
HostAmount memory allocation = request.unpackAllocationValue();
|
|
78
|
+
provision(c.account, allocation, budget);
|
|
79
|
+
writer.appendCustody(allocation);
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
settleValue(c.account, budget);
|
|
@@ -85,32 +84,3 @@ abstract contract ProvisionPayable is CommandPayable, ProvisionPayableHook {
|
|
|
85
84
|
}
|
|
86
85
|
}
|
|
87
86
|
|
|
88
|
-
/// @title ProvisionFromBalance
|
|
89
|
-
/// @notice Command that converts BALANCE state into CUSTODY state for a destination host.
|
|
90
|
-
/// The destination node is read from an optional NODE trailing block; reverts if absent.
|
|
91
|
-
abstract contract ProvisionFromBalance is CommandBase, ProvisionHook {
|
|
92
|
-
uint internal immutable provisionFromBalanceId = commandId(PFB);
|
|
93
|
-
|
|
94
|
-
constructor() {
|
|
95
|
-
emit Command(host, PFB, Schemas.Node, provisionFromBalanceId, State.Balances, State.Custodies, false);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function provisionFromBalance(
|
|
99
|
-
CommandContext calldata c
|
|
100
|
-
) external onlyCommand(provisionFromBalanceId, c.target) returns (bytes memory) {
|
|
101
|
-
(Cur memory state, uint stateCount, ) = cursor(c.state, 1);
|
|
102
|
-
Cur memory request = cursor(c.request);
|
|
103
|
-
Writer memory writer = Writers.allocCustodies(stateCount);
|
|
104
|
-
uint peer = request.nodeAfter(0);
|
|
105
|
-
if (peer == 0) revert Cursors.ZeroNode();
|
|
106
|
-
|
|
107
|
-
while (state.i < state.bound) {
|
|
108
|
-
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
|
109
|
-
HostAmount memory custody = HostAmount(peer, asset, meta, amount);
|
|
110
|
-
provision(c.account, custody);
|
|
111
|
-
writer.appendCustody(custody);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return state.complete(writer);
|
|
115
|
-
}
|
|
116
|
-
}
|
package/commands/Transfer.sol
CHANGED
|
@@ -1,34 +1,33 @@
|
|
|
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, Tx } from "../Cursors.sol";
|
|
6
6
|
import { Accounts } from "../utils/Accounts.sol";
|
|
7
7
|
using Cursors for Cur;
|
|
8
8
|
|
|
9
9
|
string constant NAME = "transfer";
|
|
10
|
-
string constant INPUT = string.concat(Schemas.Amount, "&", Schemas.Recipient);
|
|
11
10
|
|
|
12
11
|
abstract contract TransferHook {
|
|
13
12
|
/// @notice Override to execute a single transfer record from the request pipeline.
|
|
14
|
-
/// Called once per
|
|
13
|
+
/// Called once per PAYOUT block in the request.
|
|
15
14
|
/// @param value Decoded transfer record (from, to, asset, meta, amount).
|
|
16
15
|
function transfer(Tx memory value) internal virtual;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
/// @title Transfer
|
|
20
19
|
/// @notice Command that transfers assets from a caller to recipients specified in
|
|
21
|
-
///
|
|
22
|
-
/// The virtual `transfer(value)` hook is called once per
|
|
20
|
+
/// PAYOUT request blocks. Produces no state output.
|
|
21
|
+
/// The virtual `transfer(value)` hook is called once per entry.
|
|
23
22
|
abstract contract Transfer is CommandBase, TransferHook {
|
|
24
23
|
uint internal immutable transferId = commandId(NAME);
|
|
25
24
|
|
|
26
25
|
constructor() {
|
|
27
|
-
emit Command(host,
|
|
26
|
+
emit Command(host, transferId, NAME, Schemas.Payout, Keys.Empty, Keys.Empty, false);
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
/// @notice Override to customize request parsing or batching for transfers.
|
|
31
|
-
/// The default implementation iterates
|
|
30
|
+
/// The default implementation iterates entry blocks and calls `transfer(value)` for each.
|
|
32
31
|
/// @param from Source account identifier.
|
|
33
32
|
/// @param request Full request bytes.
|
|
34
33
|
/// @return Empty bytes (transfers produce no state output).
|
|
@@ -38,11 +37,9 @@ abstract contract Transfer is CommandBase, TransferHook {
|
|
|
38
37
|
value.from = from;
|
|
39
38
|
|
|
40
39
|
while (input.i < input.bound) {
|
|
41
|
-
|
|
42
|
-
(value.
|
|
43
|
-
value.to = Accounts.ensure(input.unpackRecipient());
|
|
40
|
+
(value.to, value.asset, value.meta, value.amount) = input.unpackPayout();
|
|
41
|
+
Accounts.ensure(value.to);
|
|
44
42
|
transfer(value);
|
|
45
|
-
input.ensure(next);
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
input.complete();
|
|
@@ -51,14 +48,7 @@ abstract contract Transfer is CommandBase, TransferHook {
|
|
|
51
48
|
|
|
52
49
|
function transfer(
|
|
53
50
|
CommandContext calldata c
|
|
54
|
-
) external onlyCommand(
|
|
51
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
55
52
|
return transfer(c.account, c.request);
|
|
56
53
|
}
|
|
57
54
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
package/commands/Withdraw.sol
CHANGED
|
@@ -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, 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
|
|
|
@@ -10,7 +10,7 @@ string constant NAME = "withdraw";
|
|
|
10
10
|
abstract contract WithdrawHook {
|
|
11
11
|
/// @notice Override to send funds to `account`.
|
|
12
12
|
/// Called once per BALANCE block in state.
|
|
13
|
-
/// @param account Destination account identifier (resolved from
|
|
13
|
+
/// @param account Destination account identifier (resolved from ACCOUNT block or caller).
|
|
14
14
|
/// @param asset Asset identifier.
|
|
15
15
|
/// @param meta Asset metadata slot.
|
|
16
16
|
/// @param amount Amount to deliver.
|
|
@@ -25,15 +25,14 @@ abstract contract Withdraw is CommandBase, WithdrawHook {
|
|
|
25
25
|
uint internal immutable withdrawId = commandId(NAME);
|
|
26
26
|
|
|
27
27
|
constructor() {
|
|
28
|
-
emit Command(host, NAME, Schemas.
|
|
28
|
+
emit Command(host, withdrawId, NAME, Schemas.Account, Keys.Balance, Keys.Empty, false);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function withdraw(
|
|
32
32
|
CommandContext calldata c
|
|
33
|
-
) external onlyCommand(
|
|
33
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
34
34
|
(Cur memory state, , ) = cursor(c.state, 1);
|
|
35
|
-
|
|
36
|
-
bytes32 to = request.recipientAfter(c.account);
|
|
35
|
+
bytes32 to = Cursors.resolveAccount(c.request, c.account);
|
|
37
36
|
|
|
38
37
|
while (state.i < state.bound) {
|
|
39
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();
|