@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/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,22 +1,13 @@
|
|
|
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
|
|
|
8
8
|
string constant NAME = "burn";
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
/// @notice Command that irreversibly destroys each BALANCE state block via a virtual hook.
|
|
12
|
-
/// Produces no output state.
|
|
13
|
-
abstract contract Burn is CommandBase {
|
|
14
|
-
uint internal immutable burnId = commandId(NAME);
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
emit Command(host, NAME, "", burnId, State.Balances, State.Empty, false);
|
|
18
|
-
}
|
|
19
|
-
|
|
10
|
+
abstract contract BurnHook {
|
|
20
11
|
/// @notice Override to burn or consume the provided balance amount.
|
|
21
12
|
/// Called once per BALANCE block in state.
|
|
22
13
|
/// @param account Caller's account identifier.
|
|
@@ -25,8 +16,19 @@ abstract contract Burn is CommandBase {
|
|
|
25
16
|
/// @param amount Amount to burn.
|
|
26
17
|
/// @return Amount actually burned (may differ from `amount` for partial burns).
|
|
27
18
|
function burn(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual returns (uint);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @title Burn
|
|
22
|
+
/// @notice Command that irreversibly destroys each BALANCE state block via a virtual hook.
|
|
23
|
+
/// Produces no output state.
|
|
24
|
+
abstract contract Burn is CommandBase, BurnHook {
|
|
25
|
+
uint internal immutable burnId = commandId(NAME);
|
|
26
|
+
|
|
27
|
+
constructor() {
|
|
28
|
+
emit Command(host, burnId, NAME, "", Keys.Balance, Keys.Empty, false);
|
|
29
|
+
}
|
|
28
30
|
|
|
29
|
-
function burn(CommandContext calldata c) external onlyCommand(
|
|
31
|
+
function burn(CommandContext calldata c) external onlyCommand(c.account) returns (bytes memory) {
|
|
30
32
|
(Cur memory state, , ) = cursor(c.state, 1);
|
|
31
33
|
|
|
32
34
|
while (state.i < state.bound) {
|
package/commands/Credit.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 { 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
|
|
|
8
8
|
using Cursors for Cur;
|
|
9
9
|
|
|
10
|
+
abstract contract CreditAccountHook {
|
|
11
|
+
/// @notice Override to credit externally managed funds to `account`.
|
|
12
|
+
/// Called once per BALANCE block in state.
|
|
13
|
+
/// @param account Destination account identifier.
|
|
14
|
+
/// @param asset Asset identifier.
|
|
15
|
+
/// @param meta Asset metadata slot.
|
|
16
|
+
/// @param amount Amount to credit.
|
|
17
|
+
function creditAccount(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
/// @title CreditAccount
|
|
11
21
|
/// @notice Command that delivers BALANCE state blocks to an account via a virtual hook.
|
|
12
22
|
/// Use for internally recording credits that have already been settled externally.
|
|
13
|
-
/// An optional
|
|
14
|
-
abstract contract CreditAccount is CommandBase {
|
|
23
|
+
/// An optional ACCOUNT block in the request overrides the default `c.account` destination.
|
|
24
|
+
abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
15
25
|
uint internal immutable creditAccountId = commandId(NAME);
|
|
16
26
|
|
|
17
27
|
constructor() {
|
|
18
|
-
emit Command(host, NAME, Schemas.
|
|
28
|
+
emit Command(host, creditAccountId, NAME, Schemas.Account, Keys.Balance, Keys.Empty, false);
|
|
19
29
|
}
|
|
20
30
|
|
|
21
|
-
/// @notice Override to credit externally managed funds to `account`.
|
|
22
|
-
/// Called once per BALANCE block in state.
|
|
23
|
-
/// @param account Recipient account identifier.
|
|
24
|
-
/// @param asset Asset identifier.
|
|
25
|
-
/// @param meta Asset metadata slot.
|
|
26
|
-
/// @param amount Amount to credit.
|
|
27
|
-
function creditAccount(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
28
|
-
|
|
29
31
|
function creditAccount(
|
|
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();
|
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";
|
|
@@ -9,25 +9,27 @@ string constant NAME = "debitAccount";
|
|
|
9
9
|
using Cursors for Cur;
|
|
10
10
|
using Writers for Writer;
|
|
11
11
|
|
|
12
|
+
abstract contract DebitAccountHook {
|
|
13
|
+
/// @notice Override to debit externally managed funds from `account`.
|
|
14
|
+
/// Called once per AMOUNT block before a matching BALANCE is emitted.
|
|
15
|
+
/// @param account Source account identifier.
|
|
16
|
+
/// @param asset Asset identifier.
|
|
17
|
+
/// @param meta Asset metadata slot.
|
|
18
|
+
/// @param amount Amount to debit.
|
|
19
|
+
function debitAccount(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
/// @title DebitAccount
|
|
13
23
|
/// @notice Command that deducts AMOUNT blocks from an account and emits matching BALANCE state.
|
|
14
24
|
/// Use for internally recording debits. The virtual `debitAccount` hook is called once per
|
|
15
25
|
/// AMOUNT block; the default batch implementation handles the full request loop.
|
|
16
|
-
abstract contract DebitAccount is CommandBase {
|
|
26
|
+
abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
17
27
|
uint internal immutable debitAccountId = commandId(NAME);
|
|
18
28
|
|
|
19
29
|
constructor() {
|
|
20
|
-
emit Command(host, NAME, Schemas.Amount,
|
|
30
|
+
emit Command(host, debitAccountId, NAME, Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
21
31
|
}
|
|
22
32
|
|
|
23
|
-
/// @notice Override to debit externally managed funds from `account`.
|
|
24
|
-
/// Called once per AMOUNT block before a matching BALANCE is emitted.
|
|
25
|
-
/// @param account Source account identifier.
|
|
26
|
-
/// @param asset Asset identifier.
|
|
27
|
-
/// @param meta Asset metadata slot.
|
|
28
|
-
/// @param amount Amount to debit.
|
|
29
|
-
function debitAccount(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
30
|
-
|
|
31
33
|
/// @notice Override to customize request parsing or batching for debits.
|
|
32
34
|
/// The default implementation iterates AMOUNT blocks, calls
|
|
33
35
|
/// `debitAccount`, and emits matching BALANCE blocks.
|
|
@@ -46,7 +48,7 @@ abstract contract DebitAccount is CommandBase {
|
|
|
46
48
|
|
|
47
49
|
function debitAccount(
|
|
48
50
|
CommandContext calldata c
|
|
49
|
-
) external onlyCommand(
|
|
51
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
50
52
|
return debitAccount(c.account, c.request);
|
|
51
53
|
}
|
|
52
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
|
|
|
@@ -11,34 +11,43 @@ string constant DEPOSIT_PAYABLE = "depositPayable";
|
|
|
11
11
|
using Cursors for Cur;
|
|
12
12
|
using Writers for Writer;
|
|
13
13
|
|
|
14
|
+
abstract contract DepositHook {
|
|
15
|
+
/// @notice Override to receive externally sourced funds for `account`.
|
|
16
|
+
/// Called once per AMOUNT block. A matching BALANCE block is appended to the
|
|
17
|
+
/// output after each call.
|
|
18
|
+
/// @param account Destination account identifier.
|
|
19
|
+
/// @param asset Asset identifier.
|
|
20
|
+
/// @param meta Asset metadata slot.
|
|
21
|
+
/// @param amount Amount received.
|
|
22
|
+
function deposit(bytes32 account, bytes32 asset, bytes32 meta, uint amount) internal virtual;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
abstract contract DepositPayableHook {
|
|
26
|
+
/// @notice Override to receive externally sourced funds for `account`.
|
|
27
|
+
/// Called once per AMOUNT block. A matching BALANCE block is appended to the
|
|
28
|
+
/// output after each call.
|
|
29
|
+
/// @param account Destination account identifier.
|
|
30
|
+
/// @param asset Asset identifier.
|
|
31
|
+
/// @param meta Asset metadata slot.
|
|
32
|
+
/// @param amount Amount received.
|
|
33
|
+
/// @param budget Mutable native-value budget drawn from `msg.value`.
|
|
34
|
+
function deposit(bytes32 account, bytes32 asset, bytes32 meta, uint amount, Budget memory budget) internal virtual;
|
|
35
|
+
}
|
|
36
|
+
|
|
14
37
|
/// @title Deposit
|
|
15
38
|
/// @notice Command that receives externally sourced assets and records them as BALANCE state.
|
|
16
39
|
/// Use `deposit` for assets arriving from outside the protocol (e.g. ERC-20 transfers, ETH).
|
|
17
40
|
/// For internal balance deductions, use `debitAccount` instead.
|
|
18
|
-
abstract contract Deposit is CommandBase {
|
|
41
|
+
abstract contract Deposit is CommandBase, DepositHook {
|
|
19
42
|
uint internal immutable depositId = commandId(DEPOSIT);
|
|
20
43
|
|
|
21
44
|
constructor() {
|
|
22
|
-
emit Command(host, DEPOSIT, Schemas.Amount,
|
|
45
|
+
emit Command(host, depositId, DEPOSIT, Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
23
46
|
}
|
|
24
47
|
|
|
25
|
-
/// @notice Override to receive externally sourced funds for `account`.
|
|
26
|
-
/// Called once per AMOUNT block. A matching BALANCE block is appended to the
|
|
27
|
-
/// output after each call.
|
|
28
|
-
/// @param account Recipient account identifier.
|
|
29
|
-
/// @param asset Asset identifier.
|
|
30
|
-
/// @param meta Asset metadata slot.
|
|
31
|
-
/// @param amount Amount received.
|
|
32
|
-
function deposit(
|
|
33
|
-
bytes32 account,
|
|
34
|
-
bytes32 asset,
|
|
35
|
-
bytes32 meta,
|
|
36
|
-
uint amount
|
|
37
|
-
) internal virtual;
|
|
38
|
-
|
|
39
48
|
function deposit(
|
|
40
49
|
CommandContext calldata c
|
|
41
|
-
) external onlyCommand(
|
|
50
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
42
51
|
(Cur memory request, uint count, ) = cursor(c.request, 1);
|
|
43
52
|
Writer memory writer = Writers.allocBalances(count);
|
|
44
53
|
|
|
@@ -55,32 +64,16 @@ abstract contract Deposit is CommandBase {
|
|
|
55
64
|
/// @title DepositPayable
|
|
56
65
|
/// @notice Command that receives externally sourced assets and records them as BALANCE state.
|
|
57
66
|
/// Use `depositPayable` when the hook needs tracked access to `msg.value` via a mutable budget.
|
|
58
|
-
abstract contract DepositPayable is CommandPayable {
|
|
67
|
+
abstract contract DepositPayable is CommandPayable, DepositPayableHook {
|
|
59
68
|
uint internal immutable depositPayableId = commandId(DEPOSIT_PAYABLE);
|
|
60
69
|
|
|
61
70
|
constructor() {
|
|
62
|
-
emit Command(host, DEPOSIT_PAYABLE, Schemas.Amount,
|
|
71
|
+
emit Command(host, depositPayableId, DEPOSIT_PAYABLE, Schemas.Amount, Keys.Empty, Keys.Balance, true);
|
|
63
72
|
}
|
|
64
73
|
|
|
65
|
-
/// @notice Override to receive externally sourced funds for `account`.
|
|
66
|
-
/// Called once per AMOUNT block. A matching BALANCE block is appended to the
|
|
67
|
-
/// output after each call.
|
|
68
|
-
/// @param account Recipient account identifier.
|
|
69
|
-
/// @param asset Asset identifier.
|
|
70
|
-
/// @param meta Asset metadata slot.
|
|
71
|
-
/// @param amount Amount received.
|
|
72
|
-
/// @param budget Mutable native-value budget drawn from `msg.value`.
|
|
73
|
-
function deposit(
|
|
74
|
-
bytes32 account,
|
|
75
|
-
bytes32 asset,
|
|
76
|
-
bytes32 meta,
|
|
77
|
-
uint amount,
|
|
78
|
-
Budget memory budget
|
|
79
|
-
) internal virtual;
|
|
80
|
-
|
|
81
74
|
function depositPayable(
|
|
82
75
|
CommandContext calldata c
|
|
83
|
-
) external payable onlyCommand(
|
|
76
|
+
) external payable onlyCommand(c.account) returns (bytes memory) {
|
|
84
77
|
(Cur memory request, uint count, ) = cursor(c.request, 1);
|
|
85
78
|
Writer memory writer = Writers.allocBalances(count);
|
|
86
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";
|
|
@@ -10,34 +10,28 @@ using Cursors for Cur;
|
|
|
10
10
|
|
|
11
11
|
string constant NAME = "pipePayable";
|
|
12
12
|
|
|
13
|
+
abstract contract PipePayableHook {
|
|
14
|
+
function dispatchStep(
|
|
15
|
+
uint target,
|
|
16
|
+
bytes32 account,
|
|
17
|
+
bytes memory state,
|
|
18
|
+
bytes calldata request,
|
|
19
|
+
uint value
|
|
20
|
+
) internal virtual returns (bytes memory);
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
/// @title PipePayable
|
|
14
24
|
/// @notice Command that sequences multiple sub-command STEP invocations in a single transaction.
|
|
15
25
|
/// Each STEP block carries a target node, native value to forward, and an embedded request.
|
|
16
26
|
/// State threads through the steps: each step's output becomes the next step's state.
|
|
17
27
|
/// Admin accounts are not permitted to use `pipePayable`.
|
|
18
|
-
abstract contract PipePayable is CommandPayable {
|
|
28
|
+
abstract contract PipePayable is CommandPayable, PipePayableHook {
|
|
19
29
|
uint internal immutable pipePayableId = commandId(NAME);
|
|
20
30
|
|
|
21
31
|
constructor() {
|
|
22
|
-
emit Command(host, NAME, Schemas.Step,
|
|
32
|
+
emit Command(host, pipePayableId, NAME, Schemas.Step, Keys.Empty, Keys.Empty, true);
|
|
23
33
|
}
|
|
24
34
|
|
|
25
|
-
/// @notice Override to execute a single STEP and return the resulting state.
|
|
26
|
-
/// The returned state is passed as the `state` argument of the next STEP.
|
|
27
|
-
/// @param target Destination command node ID from the STEP block.
|
|
28
|
-
/// @param account Caller's account identifier.
|
|
29
|
-
/// @param state Current threaded state from the previous step.
|
|
30
|
-
/// @param request Embedded request bytes from the STEP block.
|
|
31
|
-
/// @param value Native value forwarded with this step.
|
|
32
|
-
/// @return Next state to thread into the following step.
|
|
33
|
-
function dispatchStep(
|
|
34
|
-
uint target,
|
|
35
|
-
bytes32 account,
|
|
36
|
-
bytes memory state,
|
|
37
|
-
bytes calldata request,
|
|
38
|
-
uint value
|
|
39
|
-
) internal virtual returns (bytes memory);
|
|
40
|
-
|
|
41
35
|
function pipe(
|
|
42
36
|
bytes32 account,
|
|
43
37
|
bytes memory state,
|
|
@@ -60,7 +54,7 @@ abstract contract PipePayable is CommandPayable {
|
|
|
60
54
|
/// @notice Execute the pipePayable command.
|
|
61
55
|
function pipePayable(
|
|
62
56
|
CommandContext calldata c
|
|
63
|
-
) external payable onlyCommand(
|
|
57
|
+
) external payable onlyCommand(c.account) returns (bytes memory) {
|
|
64
58
|
if (Accounts.isAdmin(c.account)) revert Accounts.InvalidAccount();
|
|
65
59
|
Budget memory budget = Values.fromMsg();
|
|
66
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,9 +37,8 @@ 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(bundle.unpackRecipient());
|
|
40
|
+
(value.to, value.asset, value.meta, value.amount) = input.unpackPayout();
|
|
41
|
+
Accounts.ensure(value.to);
|
|
44
42
|
transfer(value);
|
|
45
43
|
}
|
|
46
44
|
|
|
@@ -50,14 +48,7 @@ abstract contract Transfer is CommandBase, TransferHook {
|
|
|
50
48
|
|
|
51
49
|
function transfer(
|
|
52
50
|
CommandContext calldata c
|
|
53
|
-
) external onlyCommand(
|
|
51
|
+
) external onlyCommand(c.account) returns (bytes memory) {
|
|
54
52
|
return transfer(c.account, c.request);
|
|
55
53
|
}
|
|
56
54
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|