@rootzero/contracts 1.13.0 → 1.15.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.
Files changed (86) hide show
  1. package/CHANGELOG.md +87 -3
  2. package/Codec.sol +21 -0
  3. package/Commands.sol +14 -0
  4. package/Core.sol +8 -6
  5. package/Endpoints.sol +2 -7
  6. package/Events.sol +1 -2
  7. package/README.md +70 -37
  8. package/Utils.sol +2 -4
  9. package/annotations/Action.sol +17 -0
  10. package/annotations/Label.sol +23 -0
  11. package/annotations/Schema.sol +53 -0
  12. package/codec/Blocks.sol +1643 -0
  13. package/codec/Buffers.sol +165 -0
  14. package/codec/Decoders.sol +570 -0
  15. package/codec/Descriptors.sol +124 -0
  16. package/{blocks → codec}/Keys.sol +10 -18
  17. package/codec/Readers.sol +114 -0
  18. package/{blocks → codec}/Schema.sol +43 -80
  19. package/codec/Specs.sol +240 -0
  20. package/codec/Writers.sol +485 -0
  21. package/commands/Allocate.sol +21 -20
  22. package/commands/Base.sol +83 -45
  23. package/commands/Burn.sol +23 -14
  24. package/commands/Credit.sol +21 -20
  25. package/commands/Debit.sol +25 -28
  26. package/commands/Deposit.sol +41 -36
  27. package/commands/Payout.sol +26 -16
  28. package/commands/Provision.sol +37 -38
  29. package/commands/Recover.sol +20 -19
  30. package/commands/Relay.sol +24 -22
  31. package/commands/Withdraw.sol +20 -19
  32. package/commands/admin/AllowAssets.sol +19 -16
  33. package/commands/admin/Allowance.sol +18 -13
  34. package/commands/admin/Annotate.sol +36 -0
  35. package/commands/admin/Appoint.sol +19 -16
  36. package/commands/admin/Authorize.sol +23 -14
  37. package/commands/admin/Base.sol +9 -2
  38. package/commands/admin/DenyAssets.sol +19 -16
  39. package/commands/admin/Dismiss.sol +19 -16
  40. package/commands/admin/Execute.sol +21 -19
  41. package/commands/admin/Unauthorize.sol +23 -14
  42. package/core/Access.sol +91 -49
  43. package/core/Calls.sol +30 -33
  44. package/core/Endpoint.sol +46 -143
  45. package/core/Host.sol +63 -21
  46. package/core/Pipeline.sol +16 -15
  47. package/core/Types.sol +1 -1
  48. package/docs/Schema.md +48 -31
  49. package/events/Annotation.sol +24 -0
  50. package/events/Endpoint.sol +2 -2
  51. package/events/Guardian.sol +2 -2
  52. package/events/Introduction.sol +3 -2
  53. package/execution/Budget.sol +40 -0
  54. package/execution/Execution.sol +1104 -0
  55. package/guards/Base.sol +11 -12
  56. package/guards/Revoke.sol +11 -9
  57. package/package.json +1 -1
  58. package/ports/AllowAssets.sol +12 -15
  59. package/ports/Allowance.sol +11 -9
  60. package/ports/Base.sol +35 -16
  61. package/ports/Credit.sol +11 -9
  62. package/ports/Debit.sol +11 -9
  63. package/ports/DenyAssets.sol +10 -13
  64. package/ports/Dispatch.sol +13 -15
  65. package/ports/Pipe.sol +14 -12
  66. package/ports/Redeem.sol +12 -9
  67. package/ports/Settle.sol +16 -10
  68. package/queries/Assets.sol +15 -15
  69. package/queries/Balances.sol +17 -17
  70. package/queries/Base.sol +26 -12
  71. package/utils/Accounts.sol +0 -23
  72. package/utils/Actions.sol +1 -0
  73. package/utils/Cursors.sol +367 -0
  74. package/utils/Lanes.sol +14 -0
  75. package/utils/Layout.sol +0 -2
  76. package/utils/Selectors.sol +2 -2
  77. package/utils/Utils.sol +46 -0
  78. package/Cursors.sol +0 -16
  79. package/blocks/Cursors.sol +0 -1529
  80. package/blocks/Writers.sol +0 -1036
  81. package/commands/admin/Label.sol +0 -32
  82. package/commands/admin/Schemas.sol +0 -32
  83. package/core/Payable.sol +0 -53
  84. package/events/Labeled.sol +0 -21
  85. package/events/Schema.sol +0 -23
  86. package/utils/Value.sol +0 -43
package/commands/Base.sol CHANGED
@@ -1,37 +1,28 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {NodeCalls} from "../core/Calls.sol";
5
- import {EndpointBase, Lane} from "../core/Endpoint.sol";
6
- import {Cur} from "../Cursors.sol";
7
- import {Keys} from "../blocks/Keys.sol";
4
+ import {CallerAccess} from "../core/Access.sol";
5
+ import {EndpointBase} from "../core/Endpoint.sol";
6
+ import {Blocks} from "../codec/Blocks.sol";
7
+ import {Specs} from "../codec/Specs.sol";
8
+ import {HostAmount} from "../core/Types.sol";
9
+ import {Execution, Executions, Lanes} from "../execution/Execution.sol";
10
+ import {ReceivedEvent} from "../events/Received.sol";
11
+ import {Actions} from "../utils/Actions.sol";
12
+ import {Descriptors} from "../codec/Descriptors.sol";
8
13
  import {Nodes} from "../utils/Nodes.sol";
9
14
  import {Selectors} from "../utils/Selectors.sol";
15
+ import {Cursors} from "../utils/Cursors.sol";
10
16
 
11
- /// @notice Execution context passed to every command invocation.
12
- struct CommandContext {
13
- /// @dev Caller's account identifier.
14
- bytes32 account;
15
- /// @dev Current state block stream (previous command output or initial state).
16
- bytes state;
17
- /// @dev Input block stream for this invocation.
18
- bytes input;
19
- }
17
+ using Executions for Execution;
20
18
 
21
19
  /// @title CommandBase
22
20
  /// @notice Abstract base for all rootzero command contracts.
23
21
  /// Provides access control modifiers and command endpoint metadata helpers.
24
- abstract contract CommandBase is NodeCalls, EndpointBase {
22
+ abstract contract CommandBase is CallerAccess, EndpointBase, ReceivedEvent {
25
23
  /// @dev Thrown when `onlyActive` finds that `deadline` has already passed.
26
24
  error Expired();
27
25
 
28
- /// @dev Restrict execution to the commander using the host's admin account.
29
- modifier onlyAdmin(bytes32 account) {
30
- if (account != admin) revert AccessDenied();
31
- enforceCommander(msg.sender);
32
- _;
33
- }
34
-
35
26
  /// @dev Restrict execution to trusted callers.
36
27
  modifier onlyCommand() {
37
28
  enforceCaller(msg.sender);
@@ -46,41 +37,88 @@ abstract contract CommandBase is NodeCalls, EndpointBase {
46
37
  }
47
38
 
48
39
  /// @notice Publish command metadata and a default label.
49
- /// @param name Default human-readable command label and selector name.
50
- /// @param state Packed state lane plus optional group byte.
51
- /// @param input Packed input lane plus optional group byte.
52
- /// @param output Packed output lane plus optional group byte.
53
- /// @param selector Command ABI selector, or zero to derive it from `name`.
40
+ /// @param name Command entrypoint name and default label. It must exactly
41
+ /// match the Solidity command function name used by the canonical ABI.
42
+ /// @param state State block specification.
43
+ /// @param input Input block specification.
44
+ /// @param output Output block specification.
45
+ /// @param transactions Number of transaction blocks produced per batch, or zero for none.
54
46
  /// @param funded Whether the command accepts nonzero native value.
55
47
  /// @param admin Whether the command is restricted to the admin account.
56
48
  /// @return id Command node ID.
57
49
  /// @return descriptor Packed endpoint lane metadata and flags.
58
50
  function command(
59
51
  string memory name,
60
- bytes9 state,
61
- bytes9 input,
62
- bytes9 output,
63
- bytes4 selector,
52
+ uint state,
53
+ uint input,
54
+ uint output,
55
+ uint8 transactions,
64
56
  bool funded,
65
57
  bool admin
66
- ) internal returns (uint id, bytes32 descriptor) {
67
- selector = selector == bytes4(0) ? Selectors.command(name) : selector;
68
- id = Nodes.toCommand(selector, address(this));
69
- descriptor = endpoint(id, name, state, input, output, funded, admin);
58
+ ) internal returns (uint id, uint descriptor) {
59
+ uint8 flags = 0;
60
+ if (funded) flags |= Descriptors.Funded;
61
+ if (admin) flags |= Descriptors.Admin;
62
+ descriptor = Descriptors.create(state, input, output, transactions, flags);
63
+ return command(name, descriptor);
64
+ }
65
+
66
+ /// @notice Publish an already constructed command descriptor and default label.
67
+ /// @param name Command entrypoint name and default label. It must exactly
68
+ /// match the Solidity command function name used by the canonical ABI.
69
+ /// @param descriptor Packed command endpoint descriptor.
70
+ /// @return id Command node ID.
71
+ /// @return published Published endpoint descriptor.
72
+ function command(string memory name, uint descriptor) internal returns (uint id, uint published) {
73
+ id = Nodes.toCommand(Selectors.command(name), address(this));
74
+ published = endpoint(id, name, descriptor);
70
75
  }
71
76
 
72
- /// @notice Open input/state cursors and return the expected output block count.
73
- /// @param c Command invocation context.
77
+ /// @notice Open a command state stream and return the expected output block count.
78
+ /// @param source State block stream to open.
74
79
  /// @param descriptor Packed command endpoint descriptor.
75
- /// @return input Cursor scoped to the command input lane.
76
- /// @return state Cursor scoped to the command state lane.
77
- /// @return outputs Number of output blocks implied by the matched group count.
80
+ /// @param batches Required batch count, or zero to accept the state count.
81
+ /// @return exec Execution with its output buffer metadata initialized for the state batch count.
82
+ function openState(
83
+ bytes calldata source,
84
+ uint descriptor,
85
+ uint batches
86
+ ) internal view returns (Execution memory exec) {
87
+ return Executions.openState(source, descriptor, batches);
88
+ }
89
+
90
+ /// @notice Open a command execution with batches derived from its input and state lanes.
91
+ /// @param state Current command state block stream.
92
+ /// @param input Command input block stream.
93
+ /// @param descriptor Packed command endpoint descriptor.
94
+ /// @param batches Required batch count, or zero to reconcile the lane counts.
95
+ /// @return exec Execution with its output buffer metadata initialized for the reconciled batch count.
78
96
  function openCommand(
79
- CommandContext calldata c,
80
- bytes32 descriptor
81
- ) internal pure returns (Cur memory input, Cur memory state, uint outputs) {
82
- uint groups;
83
- (input, groups, ) = openLane(c.input, descriptor, Lane.Input, 0);
84
- (state, , outputs) = openLane(c.state, descriptor, Lane.State, groups);
97
+ bytes calldata state,
98
+ bytes calldata input,
99
+ uint descriptor,
100
+ uint batches
101
+ ) internal view returns (Execution memory exec) {
102
+ return Executions.open(state, input, descriptor, batches);
103
+ }
104
+
105
+ /// @notice Close a command execution and refund unspent value to `account`.
106
+ /// @param exec Command execution to close.
107
+ /// @param account Account that should receive any unspent value.
108
+ /// @return output Final encoded output block stream.
109
+ /// @return transactions Final encoded transaction block stream.
110
+ function close(
111
+ Execution memory exec,
112
+ bytes32 account
113
+ ) internal returns (bytes memory output, bytes memory transactions) {
114
+ if (exec.budget == 0 && Cursors.initial(exec.writers)) return ("", "");
115
+
116
+ output = close(exec);
117
+ uint amount = exec.refundValue(account, nativeAsset);
118
+ if (amount != 0) {
119
+ emit Received(account, nativeAsset, amount, Actions.Refund, 0);
120
+ }
121
+
122
+ transactions = exec.finishTransactions();
85
123
  }
86
124
  }
package/commands/Burn.sol CHANGED
@@ -1,10 +1,12 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "./Base.sol";
5
- import { Cursors, Cur } from "../Cursors.sol";
6
- using Cursors for Cur;
4
+ import { Execution, Executions, CommandBase, Lanes, Specs } from "./Base.sol";
5
+ import {Action} from "../annotations/Action.sol";
6
+ import {Actions} from "../utils/Actions.sol";
7
+ using Executions for Execution;
7
8
 
9
+ /// @notice Hook implemented by hosts that burn account assets.
8
10
  abstract contract BurnHook {
9
11
  /// @notice Override to burn or consume the provided balance amount.
10
12
  /// Called once per BALANCE block in state.
@@ -18,25 +20,32 @@ abstract contract BurnHook {
18
20
  /// @title Burn
19
21
  /// @notice Command that irreversibly destroys each BALANCE state block via a virtual hook.
20
22
  /// Produces no output state.
21
- abstract contract Burn is CommandBase, BurnHook {
22
- bytes32 private immutable descriptor;
23
+ abstract contract Burn is CommandBase, BurnHook, Action {
24
+ uint private immutable descriptor;
23
25
 
24
26
  constructor() {
25
- (, descriptor) = command("burn", Keys.Balance, Keys.Empty, Keys.Empty, 0, false, false);
27
+ uint id;
28
+ (id, descriptor) = command("burn", Specs.Balance, Specs.Empty, Specs.Empty, 0, false, false);
29
+ action(id, Actions.Burn);
26
30
  }
27
31
 
28
32
  /// @notice Burn each BALANCE block from the command state.
29
- /// @param c Command context; `c.state` must contain BALANCE blocks.
33
+ /// @param state BALANCE block stream.
30
34
  /// @return Empty output state.
31
35
  /// @return Empty transaction stream.
32
- function burn(CommandContext calldata c) external onlyCommand returns (bytes memory, bytes memory) {
33
- (Cur memory state, ) = openState(c.state, descriptor);
34
-
35
- while (state.i < state.len) {
36
- (bytes32 asset, uint amount) = state.unpackBalance();
37
- burn(c.account, asset, amount);
36
+ function burn(
37
+ bytes32 account,
38
+ bytes calldata state,
39
+ bytes calldata
40
+ ) external onlyCommand returns (bytes memory, bytes memory) {
41
+ Execution memory exec = openState(state, descriptor, 0);
42
+
43
+ while (exec.more()) {
44
+ (bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
45
+ burn(account, asset, amount);
38
46
  }
39
- return ("", "");
47
+
48
+ return close(exec, account);
40
49
  }
41
50
  }
42
51
 
@@ -1,42 +1,43 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandBase, CommandContext, Keys } from "./Base.sol";
5
- import { Cursors, Cur } from "../Cursors.sol";
6
- import { CreditAccountHook } from "../core/Settlement.sol";
4
+ import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
5
+ import {CreditAccountHook} from "../core/Settlement.sol";
7
6
 
8
- using Cursors for Cur;
7
+ using Executions for Execution;
9
8
 
10
9
  /// @title CreditAccount
11
10
  /// @notice Command that delivers BALANCE state blocks to an account via a virtual hook.
12
11
  /// Use for internally recording credits that have already been settled externally.
13
12
  abstract contract CreditAccount is CommandBase, CreditAccountHook {
14
- bytes32 private immutable descriptor;
15
- uint internal immutable creditAccountId;
13
+ uint private immutable descriptor;
14
+ uint private immutable id;
16
15
 
17
16
  constructor() {
18
- (creditAccountId, descriptor) = command("creditAccount", Keys.Balance, Keys.Empty, Keys.Empty, 0, false, false);
17
+ (id, descriptor) = command("creditAccount", Specs.Balance, Specs.Empty, Specs.Empty, 0, false, false);
18
+ }
19
+
20
+ /// @notice Return the registered CREDIT_ACCOUNT command ID.
21
+ function creditAccountId() internal view returns (uint) {
22
+ return id;
19
23
  }
20
24
 
21
25
  /// @notice Credit each BALANCE block from the command state to the command account.
22
- /// @param c Command context; `c.state` must contain BALANCE blocks.
26
+ /// @param state BALANCE block stream.
23
27
  /// @return Empty output state.
24
28
  /// @return Empty transaction stream.
25
29
  function creditAccount(
26
- CommandContext calldata c
30
+ bytes32 account,
31
+ bytes calldata state,
32
+ bytes calldata
27
33
  ) external onlyCommand returns (bytes memory, bytes memory) {
28
- (Cur memory state, ) = openState(c.state, descriptor);
34
+ Execution memory exec = openState(state, descriptor, 0);
29
35
 
30
- while (state.i < state.len) {
31
- (bytes32 asset, uint amount) = state.unpackBalance();
32
- creditAccount(c.account, asset, amount);
36
+ while (exec.more()) {
37
+ (bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
38
+ creditAccount(account, asset, amount);
33
39
  }
34
- return ("", "");
40
+
41
+ return close(exec, account);
35
42
  }
36
43
  }
37
-
38
-
39
-
40
-
41
-
42
-
@@ -1,55 +1,52 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandContext, CommandBase, Keys } from "./Base.sol";
5
- import { Cursors, Cur, Writer, Writers } from "../Cursors.sol";
6
- import { DebitAccountHook } from "../core/Settlement.sol";
4
+ import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
5
+ import {DebitAccountHook} from "../core/Settlement.sol";
7
6
 
8
- using Cursors for Cur;
9
- using Writers for Writer;
7
+ using Executions for Execution;
10
8
 
11
9
  /// @title DebitAccount
12
10
  /// @notice Command that deducts AMOUNT blocks from an account and emits matching BALANCE state.
13
11
  /// Use for internally recording debits. The virtual `debitAccount` hook is called once per
14
- /// AMOUNT block; the default batch implementation handles the full request loop.
12
+ /// AMOUNT block; the default batch implementation handles the full input loop.
15
13
  abstract contract DebitAccount is CommandBase, DebitAccountHook {
16
- bytes32 private immutable descriptor;
17
- uint internal immutable debitAccountId;
14
+ uint private immutable descriptor;
15
+ uint private immutable id;
18
16
 
19
17
  constructor() {
20
- (debitAccountId, descriptor) = command("debitAccount", Keys.Empty, Keys.Amount, Keys.Balance, 0, false, false);
18
+ (id, descriptor) = command("debitAccount", Specs.Empty, Specs.Amount, Specs.Balance, 0, false, false);
21
19
  }
22
20
 
23
- /// @notice Override to customize request parsing or batching for debits.
21
+ /// @notice Return the registered DEBIT_ACCOUNT command ID.
22
+ function debitAccountId() internal view returns (uint) {
23
+ return id;
24
+ }
25
+
26
+ /// @notice Override to customize input parsing or batching for debits.
24
27
  /// The default implementation iterates AMOUNT blocks, calls
25
28
  /// `debitAccount`, and emits matching BALANCE blocks.
26
- function debitAccount(bytes32 account, bytes calldata request) internal virtual returns (bytes memory) {
27
- (Cur memory input, uint outputs) = openInput(request, descriptor);
28
- Writer memory output = Writers.allocBalances(outputs);
29
+ function debitAccount(bytes32 account, bytes calldata input) internal virtual returns (bytes memory, bytes memory) {
30
+ Execution memory exec = openInput(input, descriptor, 0);
29
31
 
30
- while (input.i < input.len) {
31
- (bytes32 asset, uint amount) = input.unpackAmount();
32
+ while (exec.more()) {
33
+ (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
32
34
  debitAccount(account, asset, amount);
33
- output.appendBalance(asset, amount);
35
+ exec.outputBalance(asset, amount);
34
36
  }
35
37
 
36
- return output.finish();
38
+ return close(exec, account);
37
39
  }
38
40
 
39
- /// @notice Debit AMOUNT request blocks from the command account and output matching BALANCE blocks.
40
- /// @param c Command context; `c.input` must contain AMOUNT blocks.
41
+ /// @notice Debit AMOUNT input blocks from the command account and output matching BALANCE blocks.
42
+ /// @param input AMOUNT block stream.
41
43
  /// @return BALANCE block stream matching the debited amounts.
42
44
  /// @return Empty transaction stream.
43
45
  function debitAccount(
44
- CommandContext calldata c
46
+ bytes32 account,
47
+ bytes calldata,
48
+ bytes calldata input
45
49
  ) external onlyCommand returns (bytes memory, bytes memory) {
46
- return (debitAccount(c.account, c.input), "");
50
+ return debitAccount(account, input);
47
51
  }
48
52
  }
49
-
50
-
51
-
52
-
53
-
54
-
55
-
@@ -1,14 +1,13 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import { CommandContext, CommandBase, Keys } from "./Base.sol";
5
- import { Payable } from "../core/Payable.sol";
6
- import { Cursors, Cur, Writer, Writers } from "../Cursors.sol";
7
- import { Budget } from "../utils/Value.sol";
4
+ import { Execution, Executions, CommandBase, Lanes, Specs } from "./Base.sol";
5
+ import {Action} from "../annotations/Action.sol";
6
+ import {Actions} from "../utils/Actions.sol";
8
7
 
9
- using Cursors for Cur;
10
- using Writers for Writer;
8
+ using Executions for Execution;
11
9
 
10
+ /// @notice Hook implemented by hosts that accept account deposits.
12
11
  abstract contract DepositHook {
13
12
  /// @notice Override to receive externally sourced funds for `account`.
14
13
  /// Called once per AMOUNT block. A matching BALANCE block is appended to the
@@ -19,6 +18,7 @@ abstract contract DepositHook {
19
18
  function deposit(bytes32 account, bytes32 asset, uint amount) internal virtual;
20
19
  }
21
20
 
21
+ /// @notice Hook implemented by hosts that accept value-funded deposits.
22
22
  abstract contract DepositPayableHook {
23
23
  /// @notice Override to receive externally sourced funds for `account`.
24
24
  /// Called once per AMOUNT block. A matching BALANCE block is appended to the
@@ -26,69 +26,74 @@ abstract contract DepositPayableHook {
26
26
  /// @param account Destination account identifier.
27
27
  /// @param asset Asset identifier.
28
28
  /// @param amount Amount received.
29
- /// @param budget Mutable native-value budget drawn from `msg.value`.
30
- function deposit(bytes32 account, bytes32 asset, uint amount, Budget memory budget) internal virtual;
29
+ /// @param funds Mutable execution used only for its remaining native-value budget.
30
+ function deposit(bytes32 account, bytes32 asset, uint amount, Execution memory funds) internal virtual;
31
31
  }
32
32
 
33
33
  /// @title Deposit
34
34
  /// @notice Command that receives externally sourced assets and records them as BALANCE state.
35
35
  /// Use `deposit` for assets arriving from outside the protocol (e.g. ERC-20 transfers, ETH).
36
36
  /// For internal balance deductions, use `debitAccount` instead.
37
- abstract contract Deposit is CommandBase, DepositHook {
38
- bytes32 private immutable descriptor;
37
+ abstract contract Deposit is CommandBase, DepositHook, Action {
38
+ uint private immutable descriptor;
39
39
 
40
40
  constructor() {
41
- (, descriptor) = command("deposit", Keys.Empty, Keys.Amount, Keys.Balance, 0, false, false);
41
+ uint id;
42
+ (id, descriptor) = command("deposit", Specs.Empty, Specs.Amount, Specs.Balance, 0, false, false);
43
+ action(id, Actions.Deposit);
42
44
  }
43
45
 
44
- /// @notice Deposit AMOUNT request blocks into the command account and output matching BALANCE blocks.
45
- /// @param c Command context; `c.input` must contain AMOUNT blocks.
46
+ /// @notice Deposit AMOUNT input blocks into the command account and output matching BALANCE blocks.
47
+ /// @param input AMOUNT block stream.
46
48
  /// @return BALANCE block stream matching the deposited amounts.
47
49
  /// @return Empty transaction stream.
48
50
  function deposit(
49
- CommandContext calldata c
51
+ bytes32 account,
52
+ bytes calldata,
53
+ bytes calldata input
50
54
  ) external onlyCommand returns (bytes memory, bytes memory) {
51
- (Cur memory input, uint outputs) = openInput(c.input, descriptor);
52
- Writer memory output = Writers.allocBalances(outputs);
55
+ Execution memory exec = openInput(input, descriptor, 0);
53
56
 
54
- while (input.i < input.len) {
55
- (bytes32 asset, uint amount) = input.unpackAmount();
56
- deposit(c.account, asset, amount);
57
- output.appendBalance(asset, amount);
57
+ while (exec.more()) {
58
+ (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
59
+ deposit(account, asset, amount);
60
+ exec.outputBalance(asset, amount);
58
61
  }
59
62
 
60
- return (output.finish(), "");
63
+ return close(exec, account);
61
64
  }
62
65
  }
63
66
 
64
67
  /// @title DepositPayable
65
68
  /// @notice Command that receives externally sourced assets and records them as BALANCE state.
66
69
  /// Use `depositPayable` when the hook needs tracked access to `msg.value` via a mutable budget.
67
- abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
68
- bytes32 private immutable descriptor;
70
+ abstract contract DepositPayable is CommandBase, DepositPayableHook, Action {
71
+ uint private immutable descriptor;
69
72
 
70
73
  constructor() {
71
- (, descriptor) = command("depositPayable", Keys.Empty, Keys.Amount, Keys.Balance, 0, true, false);
74
+ uint id;
75
+ (id, descriptor) = command("depositPayable", Specs.Empty, Specs.Amount, Specs.Balance, 0, true, false);
76
+ action(id, Actions.Deposit);
72
77
  }
73
78
 
74
- /// @notice Deposit AMOUNT request blocks with access to a mutable native-value budget.
75
- /// @param c Command context; `c.input` must contain AMOUNT blocks.
79
+ /// @notice Deposit AMOUNT input blocks with access to a mutable native-value budget.
80
+ /// @param input AMOUNT block stream.
76
81
  /// @return BALANCE block stream matching the deposited amounts.
77
82
  /// @return Remaining native value as a refund transaction stream.
78
83
  function depositPayable(
79
- CommandContext calldata c
84
+ bytes32 account,
85
+ bytes calldata,
86
+ bytes calldata input
80
87
  ) external payable onlyCommand returns (bytes memory, bytes memory) {
81
- (Cur memory input, uint outputs) = openInput(c.input, descriptor);
82
- Writer memory output = Writers.allocBalances(outputs);
83
- Budget memory budget = openValue();
84
-
85
- while (input.i < input.len) {
86
- (bytes32 asset, uint amount) = input.unpackAmount();
87
- deposit(c.account, asset, amount, budget);
88
- output.appendBalance(asset, amount);
88
+ Execution memory exec = openInput(input, descriptor, 0);
89
+
90
+ while (exec.more()) {
91
+ (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
92
+ deposit(account, asset, amount, exec);
93
+ exec.outputBalance(asset, amount);
89
94
  }
90
95
 
91
- return (output.finish(), closeValue(budget, c.account));
96
+ return close(exec, account);
92
97
  }
93
98
  }
94
99
 
@@ -1,14 +1,16 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {CommandContext, CommandBase, Keys} from "./Base.sol";
5
- import {Cursors, Cur} from "../Cursors.sol";
4
+ import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
5
+ import {Action} from "../annotations/Action.sol";
6
+ import {Actions} from "../utils/Actions.sol";
6
7
 
7
- using Cursors for Cur;
8
+ using Executions for Execution;
8
9
 
10
+ /// @notice Hook implemented by hosts that pay balances to accounts.
9
11
  abstract contract PayoutHook {
10
12
  /// @notice Override to pay `amount` from `account` to `to`.
11
- /// Called once per paired BALANCE state block and ACCOUNT request block.
13
+ /// Called once per paired BALANCE state block and ACCOUNT input block.
12
14
  /// @param account Source account identifier.
13
15
  /// @param to Destination account identifier.
14
16
  /// @param asset Asset identifier.
@@ -17,26 +19,34 @@ abstract contract PayoutHook {
17
19
  }
18
20
 
19
21
  /// @title Payout
20
- /// @notice Command that sinks BALANCE state blocks to matching ACCOUNT request blocks.
22
+ /// @notice Command that sinks BALANCE state blocks to matching ACCOUNT input blocks.
21
23
  /// Each BALANCE block is paired with one ACCOUNT block at the same position.
22
- abstract contract Payout is CommandBase, PayoutHook {
23
- bytes32 private immutable descriptor;
24
+ abstract contract Payout is CommandBase, PayoutHook, Action {
25
+ uint private immutable descriptor;
24
26
 
25
27
  constructor() {
26
- (, descriptor) = command("payout", Keys.Balance, Keys.Account, Keys.Empty, 0, false, false);
28
+ uint id;
29
+ (id, descriptor) = command("payout", Specs.Balance, Specs.Account, Specs.Empty, 0, false, false);
30
+ action(id, Actions.Payout);
27
31
  }
28
32
 
29
- /// @notice Pay out BALANCE state blocks to matching ACCOUNT request blocks.
30
- /// @param c Command context; `c.state` must contain BALANCE blocks and `c.input` matching ACCOUNT blocks.
33
+ /// @notice Pay out BALANCE state blocks to matching ACCOUNT input blocks.
34
+ /// @param state BALANCE block stream.
35
+ /// @param input Matching ACCOUNT block stream.
31
36
  /// @return Empty output state.
32
37
  /// @return Empty transaction stream.
33
- function payout(CommandContext calldata c) external onlyCommand returns (bytes memory, bytes memory) {
34
- (Cur memory input, Cur memory state, ) = openCommand(c, descriptor);
38
+ function payout(
39
+ bytes32 account,
40
+ bytes calldata state,
41
+ bytes calldata input
42
+ ) external onlyCommand returns (bytes memory, bytes memory) {
43
+ Execution memory exec = openCommand(state, input, descriptor, 0);
35
44
 
36
- while (state.i < state.len) {
37
- (bytes32 asset, uint amount) = state.unpackBalance();
38
- payout(c.account, input.unpackAccount(), asset, amount);
45
+ while (exec.more()) {
46
+ (bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
47
+ payout(account, exec.unpackAccount(Lanes.Input), asset, amount);
39
48
  }
40
- return ("", "");
49
+
50
+ return close(exec, account);
41
51
  }
42
52
  }