@rootzero/contracts 1.15.0 → 1.16.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 (51) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/Codec.sol +1 -1
  3. package/Commands.sol +1 -1
  4. package/Core.sol +2 -2
  5. package/Endpoints.sol +5 -4
  6. package/Events.sol +0 -1
  7. package/README.md +82 -28
  8. package/codec/Blocks.sol +79 -21
  9. package/codec/Buffers.sol +3 -3
  10. package/codec/Decoders.sol +31 -10
  11. package/codec/Descriptors.sol +0 -1
  12. package/codec/Keys.sol +2 -2
  13. package/codec/Readers.sol +13 -0
  14. package/codec/Schema.sol +5 -1
  15. package/codec/Specs.sol +4 -2
  16. package/codec/Writers.sol +19 -2
  17. package/commands/Base.sol +6 -15
  18. package/commands/Burn.sol +2 -2
  19. package/commands/Credit.sol +35 -3
  20. package/commands/Debit.sol +46 -13
  21. package/commands/Deposit.sol +4 -4
  22. package/commands/Provision.sol +4 -4
  23. package/commands/Recover.sol +15 -8
  24. package/commands/Relay.sol +37 -12
  25. package/commands/Settle.sol +77 -0
  26. package/commands/Withdraw.sol +2 -2
  27. package/commands/admin/AllowAssets.sol +2 -2
  28. package/commands/admin/Allowance.sol +2 -2
  29. package/commands/admin/Annotate.sol +2 -2
  30. package/commands/admin/Appoint.sol +2 -2
  31. package/commands/admin/Authorize.sol +2 -2
  32. package/commands/admin/DenyAssets.sol +2 -2
  33. package/commands/admin/Dismiss.sol +2 -2
  34. package/commands/admin/Execute.sol +3 -3
  35. package/commands/admin/Unauthorize.sol +2 -2
  36. package/core/Endpoint.sol +15 -13
  37. package/core/Pipeline.sol +6 -6
  38. package/core/Settlement.sol +37 -8
  39. package/core/Types.sol +13 -1
  40. package/docs/Schema.md +52 -2
  41. package/execution/Budget.sol +12 -4
  42. package/execution/Execution.sol +85 -11
  43. package/guards/Base.sol +2 -2
  44. package/package.json +1 -1
  45. package/ports/Base.sol +2 -2
  46. package/ports/Dispatch.sol +6 -6
  47. package/ports/{Settle.sol → Post.sol} +10 -10
  48. package/queries/Base.sol +2 -2
  49. package/utils/Actions.sol +1 -0
  50. package/utils/Cursors.sol +16 -30
  51. package/events/Position.sol +0 -22
@@ -22,10 +22,10 @@ abstract contract Dismiss is GuardianAccess, AdminBase {
22
22
  /// @return Empty transaction stream.
23
23
  function dismiss(
24
24
  bytes32 account,
25
- bytes calldata,
25
+ bytes calldata state,
26
26
  bytes calldata input
27
27
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
28
- Execution memory exec = openInput(input, descriptor, 0);
28
+ Execution memory exec = openCommand(state, input, descriptor, 0);
29
29
 
30
30
  while (exec.more()) {
31
31
  bytes32 guardian = exec.unpackAccount(Lanes.Input);
@@ -24,14 +24,14 @@ abstract contract ExecutePayable is RawNodeCalls, AdminBase {
24
24
  /// @return Remaining native value as a refund transaction stream.
25
25
  function executePayable(
26
26
  bytes32 account,
27
- bytes calldata,
27
+ bytes calldata state,
28
28
  bytes calldata input
29
29
  ) external payable onlyAdmin(account) returns (bytes memory, bytes memory) {
30
- Execution memory exec = openInput(input, descriptor, 0);
30
+ Execution memory exec = openCommand(state, input, descriptor, 0);
31
31
 
32
32
  while (exec.more()) {
33
33
  (uint target, uint resources, bytes calldata data) = exec.unpackCall(Lanes.Input);
34
- rawCall(target, exec.useValue(resources), data);
34
+ rawCall(target, exec.useResourceValue(resources), data);
35
35
  }
36
36
 
37
37
  return close(exec, account);
@@ -27,10 +27,10 @@ abstract contract Unauthorize is AdminBase {
27
27
  /// @return Empty transaction stream.
28
28
  function unauthorize(
29
29
  bytes32 account,
30
- bytes calldata,
30
+ bytes calldata state,
31
31
  bytes calldata input
32
32
  ) external onlyAdmin(account) returns (bytes memory, bytes memory) {
33
- Execution memory exec = openInput(input, descriptor, 0);
33
+ Execution memory exec = openCommand(state, input, descriptor, 0);
34
34
 
35
35
  while (exec.more()) {
36
36
  uint node = exec.unpackNode(Lanes.Input);
package/core/Endpoint.sol CHANGED
@@ -43,19 +43,6 @@ abstract contract EndpointBase is EndpointEvent, Label, Schema {
43
43
  return descriptor;
44
44
  }
45
45
 
46
- /// @notice Open an endpoint input stream with an expected batch count.
47
- /// @param source Input block stream to open.
48
- /// @param descriptor Packed endpoint descriptor.
49
- /// @param batches Required batch count, or zero to accept the input count.
50
- /// @return exec Execution with its output buffer metadata initialized for the input batch count.
51
- function openInput(
52
- bytes calldata source,
53
- uint descriptor,
54
- uint batches
55
- ) internal view returns (Execution memory exec) {
56
- return Executions.openInput(source, descriptor, batches);
57
- }
58
-
59
46
  /// @notice Finalize an execution output and return its encoded block stream.
60
47
  /// @param exec Completed endpoint execution.
61
48
  /// @return Encoded output block stream.
@@ -63,3 +50,18 @@ abstract contract EndpointBase is EndpointEvent, Label, Schema {
63
50
  return Executions.finish(exec);
64
51
  }
65
52
  }
53
+
54
+ /// @title InputEndpointBase
55
+ /// @notice Shared input opening for endpoint families that have only an input lane.
56
+ /// Commands intentionally do not inherit this base because they must open state
57
+ /// and input together through `openCommand`.
58
+ abstract contract InputEndpointBase is EndpointBase {
59
+ /// @notice Open an endpoint input stream with an expected batch count.
60
+ function openInput(
61
+ bytes calldata input,
62
+ uint descriptor,
63
+ uint batches
64
+ ) internal view returns (Execution memory exec) {
65
+ return Executions.openInput(input, descriptor, batches);
66
+ }
67
+ }
package/core/Pipeline.sol CHANGED
@@ -2,7 +2,7 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {Decoders, Cur, Readers, Reader} from "../Codec.sol";
5
- import {Settlement} from "./Settlement.sol";
5
+ import {PostHook} from "./Settlement.sol";
6
6
  import {Budget, Budgets} from "../execution/Budget.sol";
7
7
 
8
8
  using Decoders for Cur;
@@ -11,14 +11,14 @@ using Budgets for Budget;
11
11
 
12
12
  /// @title Pipeline
13
13
  /// @notice Core pipeline functionality shared by higher-level surfaces.
14
- abstract contract Pipeline is Settlement {
14
+ abstract contract Pipeline is PostHook {
15
15
  /// @dev Thrown when the pipeline finishes with non-empty threaded state.
16
16
  error UnexpectedState();
17
17
 
18
18
  /// @notice Override to dispatch one piped step.
19
19
  /// Called once per STEP block. The returned state becomes the state passed to
20
20
  /// the next step, and the final returned state must be empty. Returned
21
- /// transactions are decoded and passed individually to `settle` before the next step runs.
21
+ /// transactions are decoded and passed individually to `post` before the next step runs.
22
22
  /// @param cmd Command node ID to invoke or handle.
23
23
  /// @param account Account identifier for the piped context.
24
24
  /// @param state Current threaded state block stream.
@@ -42,16 +42,16 @@ abstract contract Pipeline is Settlement {
42
42
  /// @param steps STEP block stream to execute.
43
43
  /// @param budget Mutable native-value budget shared across all steps.
44
44
  function pipe(bytes32 account, bytes memory state, bytes calldata steps, Budget memory budget) internal {
45
- Cur memory cur = Decoders.open(steps, 1);
45
+ Cur memory cur = Decoders.open(steps);
46
46
 
47
47
  while (cur.more()) {
48
48
  (uint cmd, uint resources, bytes calldata input) = cur.unpackStep();
49
49
  Reader memory txs;
50
- (state, txs.source) = dispatch(cmd, account, state, input, budget.use(resources));
50
+ (state, txs.source) = dispatch(cmd, account, state, input, budget.useResourceValue(resources));
51
51
 
52
52
  while (txs.more()) {
53
53
  (bytes32 from, bytes32 to, bytes32 asset, uint amount) = txs.unpackTransaction();
54
- settle(from, to, asset, amount);
54
+ post(from, to, asset, amount);
55
55
  }
56
56
  }
57
57
 
@@ -21,19 +21,48 @@ abstract contract CreditAccountHook {
21
21
  function creditAccount(bytes32 account, bytes32 asset, uint amount) internal virtual;
22
22
  }
23
23
 
24
+ /// @title PostHook
25
+ /// @notice Hook for posting one transaction between accounts.
26
+ abstract contract PostHook {
27
+ /// @notice Override to post one transaction.
28
+ function post(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal virtual;
29
+ }
30
+
31
+ /// @title SettleHook
32
+ /// @notice Hook for settling one asset-liability position.
33
+ abstract contract SettleHook {
34
+ /// @notice Override to settle one position for `account`.
35
+ function settle(
36
+ bytes32 account,
37
+ bytes32 asset,
38
+ uint amount,
39
+ bytes32 liability,
40
+ uint debt
41
+ ) internal virtual;
42
+ }
43
+
24
44
  /// @title Settlement
25
- /// @notice Settles decoded transactions through debit and credit account hooks.
26
- abstract contract Settlement is DebitAccountHook, CreditAccountHook {
27
- /// @notice Settle one transaction by debiting its source and crediting its destination.
45
+ /// @notice Default account-hook implementation for transaction posting and position settlement.
46
+ abstract contract Settlement is PostHook, SettleHook, DebitAccountHook, CreditAccountHook {
47
+ /// @notice Post one transaction by debiting its source and crediting its destination.
28
48
  /// Returns without calling either hook when `amount` is zero and skips either
29
49
  /// operation when the corresponding account is zero.
30
- /// @param from Source account identifier.
31
- /// @param to Destination account identifier.
32
- /// @param asset Asset identifier.
33
- /// @param amount Token amount.
34
- function settle(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal {
50
+ function post(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal virtual override {
35
51
  if (amount == 0) return;
36
52
  if (from != 0) debitAccount(from, asset, amount);
37
53
  if (to != 0) creditAccount(to, asset, amount);
38
54
  }
55
+
56
+ /// @notice Settle one position by crediting its asset and debiting its liability.
57
+ /// Skips either operation when its corresponding amount is zero.
58
+ function settle(
59
+ bytes32 account,
60
+ bytes32 asset,
61
+ uint amount,
62
+ bytes32 liability,
63
+ uint debt
64
+ ) internal virtual override {
65
+ if (amount != 0) creditAccount(account, asset, amount);
66
+ if (debt != 0) debitAccount(account, liability, debt);
67
+ }
39
68
  }
package/core/Types.sol CHANGED
@@ -59,7 +59,19 @@ struct HostAccountAmount {
59
59
  uint amount;
60
60
  }
61
61
 
62
- /// @notice Transfer payload used by transaction blocks and peer settlement.
62
+ /// @notice Asset and liability pair threaded as live pipeline state.
63
+ struct Position {
64
+ /// @dev Identifier for the asset side.
65
+ bytes32 asset;
66
+ /// @dev Quantity on the asset side.
67
+ uint amount;
68
+ /// @dev Identifier for the liability side.
69
+ bytes32 liability;
70
+ /// @dev Quantity owed on the liability side.
71
+ uint debt;
72
+ }
73
+
74
+ /// @notice Transfer payload used by transaction blocks and peer posting.
63
75
  struct Tx {
64
76
  /// @dev Sender account identifier.
65
77
  bytes32 from;
package/docs/Schema.md CHANGED
@@ -161,8 +161,58 @@ with no payload, use a zero-payload block such as `#unit`.
161
161
 
162
162
  Endpoint descriptors currently use a narrower convention than the full block
163
163
  grammar: each state, input, or output lane is a single run of blocks, without
164
- additional global items. Future protocol surfaces may use the more flexible
165
- top-level structure.
164
+ additional global items. Endpoint decoder opening requires that run to consume
165
+ the complete supplied lane; a trailing block with another key is invalid.
166
+ Lower-level cursor scanning may still intentionally open only a prefix run.
167
+ Those lower layers retain only the raw block count; descriptor strides are
168
+ applied and lane groups reconciled once when an endpoint execution opens.
169
+ Future protocol surfaces may use the more flexible top-level structure.
170
+
171
+ For commands, complete-lane validation is also a state-safety rule. State is a
172
+ linear value owned by the current pipeline step, not optional context that a
173
+ command may disregard. Every command must account for the complete supplied
174
+ state by consuming it, transforming and returning it, forwarding it intact, or
175
+ reverting. A command whose descriptor declares an empty state lane must reject
176
+ non-empty state. A command that accepts state must validate the complete stream
177
+ against its declared schema; accepting only a prefix and silently dropping the
178
+ remainder is invalid.
179
+
180
+ ## Live Pipeline State
181
+
182
+ `#balance`, `#custody`, and `#position` are live state carried between command
183
+ steps for the active account. A position atomically pairs an asset side with a
184
+ liability side:
185
+
186
+ ```txt
187
+ position { bytes32 asset, uint amount, bytes32 liability, uint debt }
188
+ ```
189
+
190
+ The pair is deliberately general. The asset side represents value acquired or
191
+ controlled, and the liability side represents value owed or required. Commands
192
+ may preserve or replace either side and return a new position. The terminal
193
+ `settle` command consumes the pair. Position state is transient protocol state;
194
+ rewriting it does not by itself create, discharge, or replace an obligation
195
+ persisted by a host or external protocol. The responsible command hook must
196
+ perform or verify those effects. A command must not ignore a supplied position:
197
+ it must explicitly consume, transform, forward, or reject it, so neither its
198
+ asset nor its debt can disappear accidentally.
199
+
200
+ This representation supports ordinary forward transformations as well as
201
+ backward composition. For example, an exact-output route can carry its desired
202
+ asset while successive hops replace the upstream liability:
203
+
204
+ ```txt
205
+ position(C, 100, C, 100)
206
+ → position(C, 100, B, 50)
207
+ → position(C, 100, A, 25)
208
+ → settle
209
+ ```
210
+
211
+ “Backward” describes how requirements are composed from the desired result
212
+ toward the source. Pipeline execution is not reversed: STEP blocks always run
213
+ forward in their encoded order. Exact-output routing is only an example;
214
+ borrowing, refinancing, collateral transformation, callback obligations,
215
+ cross-host claims, fees, and netting can use the same position state.
166
216
 
167
217
  ## Field Aliases
168
218
 
@@ -19,15 +19,23 @@ library Budgets {
19
19
  budget.remaining = msg.value;
20
20
  }
21
21
 
22
+ /// @notice Deduct an exact native value from `budget`.
23
+ /// @param budget Mutable budget to debit.
24
+ /// @param value Native value to consume in wei.
25
+ /// @return The consumed native value.
26
+ function useValue(Budget memory budget, uint value) internal pure returns (uint) {
27
+ if (value > budget.remaining) revert InsufficientValue();
28
+ budget.remaining -= value;
29
+ return value;
30
+ }
31
+
22
32
  /// @notice Deduct the EVM value lane of `resources` from `budget`.
23
33
  /// @dev EVM resources use the low 128 bits as native value/endowment.
24
34
  /// @param budget Mutable budget to debit.
25
35
  /// @param resources Packed resources whose low 128 bits contain native value.
26
36
  /// @return value Native value to forward in wei.
27
- function use(Budget memory budget, uint resources) internal pure returns (uint128 value) {
28
- value = uint128(resources);
29
- if (value > budget.remaining) revert InsufficientValue();
30
- budget.remaining -= value;
37
+ function useResourceValue(Budget memory budget, uint resources) internal pure returns (uint128) {
38
+ return uint128(useValue(budget, uint128(resources)));
31
39
  }
32
40
 
33
41
  /// @notice Remove and return all remaining value from `budget`.
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, Tx} from "../core/Types.sol";
4
+ import {AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, Position, Tx} from "../core/Types.sol";
5
5
  import {Blocks} from "../codec/Blocks.sol";
6
6
  import {Buffers} from "../codec/Buffers.sol";
7
7
  import {Sizes, Specs} from "../codec/Specs.sol";
@@ -9,6 +9,7 @@ import {Descriptors} from "../codec/Descriptors.sol";
9
9
  import {Cursors, Cur} from "../utils/Cursors.sol";
10
10
  import {Lanes} from "../utils/Lanes.sol";
11
11
  import {Budget} from "./Budget.sol";
12
+ import {max16} from "../utils/Utils.sol";
12
13
 
13
14
  /// @notice Mutable state shared across one endpoint execution.
14
15
  /// @dev `decoders` contains tagged input and state cursor lanes. Cursor operations
@@ -28,6 +29,10 @@ library Executions {
28
29
 
29
30
  /// @dev Thrown when an execution attempts to spend more value than remains in its budget.
30
31
  error InsufficientValue();
32
+ /// @dev Decoder block counts do not form compatible descriptor groups.
33
+ error BadRatio();
34
+ /// @dev A descriptor-empty lane received a non-empty block source.
35
+ error ZeroStride();
31
36
 
32
37
  // -------------------------------------------------------------------------
33
38
  // Opening
@@ -37,15 +42,39 @@ library Executions {
37
42
  /// @param source Calldata source for the decoder lane.
38
43
  /// @param descriptor Packed endpoint descriptor.
39
44
  /// @param lane Input or state lane identifier.
40
- /// @return cur Tagged packed decoder cursor, or zero for an absent lane.
45
+ /// @return cur Tagged packed decoder cursor carrying its raw block count, or zero for an absent lane.
41
46
  function openDecoder(bytes calldata source, uint descriptor, uint8 lane) private pure returns (uint cur) {
42
47
  uint stride = Descriptors.stride(descriptor, lane);
43
48
  (uint abs, uint limit) = Cursors.bounds(source);
44
49
  if (stride == 0 && abs == limit) return 0;
50
+ if (stride == 0) revert ZeroStride();
45
51
 
46
- bytes4 key = bytes4(source);
47
- (uint groups, uint end) = Blocks.scope(abs, limit, key, stride);
48
- cur = Cursors.create(abs, end - abs, groups, 0, lane);
52
+ bytes4 key = Descriptors.key(descriptor, lane);
53
+ (uint count, uint end) = Blocks.runExact(abs, limit, key);
54
+ if (count == 0) revert Blocks.EmptyRun();
55
+ cur = Cursors.create(abs, end - abs, count, 0, lane);
56
+ }
57
+
58
+ /// @dev Convert one decoder lane's raw block count into descriptor groups.
59
+ function groupCount(uint decoders, uint descriptor, uint8 lane) private pure returns (uint groups) {
60
+ uint stride = Descriptors.stride(descriptor, lane);
61
+ if (stride == 0) return 0;
62
+
63
+ uint count = decoders.select(lane).count();
64
+ if (count % stride != 0) revert BadRatio();
65
+ groups = count / stride;
66
+ }
67
+
68
+ /// @dev Reconcile decoder lane groups once at endpoint execution opening.
69
+ function reconcile(uint decoders, uint descriptor, uint expected) private pure returns (uint groups) {
70
+ uint input = groupCount(decoders, descriptor, Lanes.Input);
71
+ uint state = groupCount(decoders, descriptor, Lanes.State);
72
+ if (input != 0 && state != 0 && input != state) revert BadRatio();
73
+
74
+ groups = input != 0 ? input : state;
75
+ if (groups != 0 && expected != 0 && groups != expected) revert BadRatio();
76
+ if (groups == 0) groups = expected;
77
+ max16(groups);
49
78
  }
50
79
 
51
80
  /// @dev Initialize one tagged writer cursor from a descriptor lane.
@@ -58,7 +87,9 @@ library Executions {
58
87
  (uint capacity, bool growable) = Descriptors.allocation(descriptor, lane, batches);
59
88
  if (capacity == 0) return 0;
60
89
 
61
- cur = Buffers.cursor(capacity + padding, batches, growable, lane);
90
+ uint count = batches * Descriptors.stride(descriptor, lane);
91
+ if (padding != 0) count += padding / Sizes.Transaction;
92
+ cur = Buffers.cursor(capacity + padding, count, growable, lane);
62
93
  }
63
94
 
64
95
  /// @dev Open and pair the input and state decoder cursors.
@@ -91,7 +122,7 @@ library Executions {
91
122
  function open(uint decoders, uint descriptor, uint batches) private view returns (Execution memory exec) {
92
123
  exec.budget = msg.value;
93
124
  exec.decoders = decoders;
94
- batches = Cursors.reconcile(decoders, batches);
125
+ batches = reconcile(decoders, descriptor, batches);
95
126
  exec.writers = writerCursors(descriptor, batches);
96
127
  }
97
128
 
@@ -294,6 +325,24 @@ library Executions {
294
325
  (value.asset, value.amount) = unpackBalance(exec, lane);
295
326
  }
296
327
 
328
+ /// @notice Decode and consume one POSITION block from `lane`.
329
+ function unpackPosition(
330
+ Execution memory exec,
331
+ uint8 lane
332
+ ) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
333
+ uint abs;
334
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Position);
335
+ (asset, amount, liability, debt) = Blocks.unpackPosition(abs);
336
+ }
337
+
338
+ /// @notice Decode one POSITION block into its structured value.
339
+ function unpackPositionValue(
340
+ Execution memory exec,
341
+ uint8 lane
342
+ ) internal pure returns (Position memory value) {
343
+ (value.asset, value.amount, value.liability, value.debt) = unpackPosition(exec, lane);
344
+ }
345
+
297
346
  /// @notice Decode one BALANCE block and associate it with `host`.
298
347
  /// @param exec Execution whose decoder is advanced.
299
348
  /// @param lane Decoder lane to consume.
@@ -730,6 +779,23 @@ library Executions {
730
779
  outputBalance(exec, value.asset, value.amount);
731
780
  }
732
781
 
782
+ /// @notice Append a POSITION block to execution output.
783
+ function outputPosition(
784
+ Execution memory exec,
785
+ bytes32 asset,
786
+ uint amount,
787
+ bytes32 liability,
788
+ uint debt
789
+ ) internal pure {
790
+ uint i = reserve(exec, Sizes.Position);
791
+ Blocks.writePosition(exec.output, i, asset, amount, liability, debt);
792
+ }
793
+
794
+ /// @notice Append a structured POSITION value to execution output.
795
+ function outputPosition(Execution memory exec, Position memory value) internal pure {
796
+ outputPosition(exec, value.asset, value.amount, value.liability, value.debt);
797
+ }
798
+
733
799
  /// @notice Append an ACCOUNT_ASSET block to execution output.
734
800
  /// @param exec Execution receiving the block.
735
801
  /// @param account Account identifier to encode.
@@ -1010,15 +1076,23 @@ library Executions {
1010
1076
  exec.budget = 0;
1011
1077
  }
1012
1078
 
1079
+ /// @notice Deduct an exact native value from the execution budget.
1080
+ /// @param exec Mutable execution whose budget is charged.
1081
+ /// @param value Native value to consume in wei.
1082
+ /// @return The consumed native value.
1083
+ function useValue(Execution memory exec, uint value) internal pure returns (uint) {
1084
+ if (value > exec.budget) revert InsufficientValue();
1085
+ exec.budget -= value;
1086
+ return value;
1087
+ }
1088
+
1013
1089
  /// @notice Deduct the EVM value lane of `resources` from the execution budget.
1014
1090
  /// @dev EVM resources use the low 128 bits as native value/endowment.
1015
1091
  /// @param exec Mutable execution whose budget is charged.
1016
1092
  /// @param resources Packed resources whose value lane should be spent.
1017
1093
  /// @return value Native value to forward in wei.
1018
- function useValue(Execution memory exec, uint resources) internal pure returns (uint128 value) {
1019
- value = uint128(resources);
1020
- if (value > exec.budget) revert InsufficientValue();
1021
- exec.budget -= value;
1094
+ function useResourceValue(Execution memory exec, uint resources) internal pure returns (uint128) {
1095
+ return uint128(useValue(exec, uint128(resources)));
1022
1096
  }
1023
1097
 
1024
1098
  /// @notice Append a deferred transaction to the transaction writer lane.
package/guards/Base.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 {EndpointBase} from "../core/Endpoint.sol";
4
+ import {InputEndpointBase} from "../core/Endpoint.sol";
5
5
  import {GuardianAccess} from "../core/Access.sol";
6
6
  import {Specs} from "../codec/Specs.sol";
7
7
  import {Nodes} from "../utils/Nodes.sol";
@@ -10,7 +10,7 @@ import {Selectors} from "../utils/Selectors.sol";
10
10
  /// @title GuardBase
11
11
  /// @notice Abstract base for guardian-only direct host actions.
12
12
  /// Guard actions are non-payable direct calls with no command context, state, or response.
13
- abstract contract GuardBase is GuardianAccess, EndpointBase {
13
+ abstract contract GuardBase is GuardianAccess, InputEndpointBase {
14
14
  /// @dev Restrict execution to active guardian addresses.
15
15
  modifier onlyGuardian() {
16
16
  enforceGuardian(msg.sender);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootzero/contracts",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "description": "Solidity contracts and protocol building blocks for rootzero hosts and commands.",
5
5
  "private": false,
6
6
  "license": "GPL-3.0-only",
package/ports/Base.sol CHANGED
@@ -4,7 +4,7 @@ pragma solidity ^0.8.33;
4
4
  import { NodeCalls } from "../core/Calls.sol";
5
5
  import { NodeAccess } from "../core/Access.sol";
6
6
  import { Specs } from "../codec/Specs.sol";
7
- import { EndpointBase } from "../core/Endpoint.sol";
7
+ import { InputEndpointBase } from "../core/Endpoint.sol";
8
8
  import { Nodes } from "../utils/Nodes.sol";
9
9
  import { Selectors } from "../utils/Selectors.sol";
10
10
  import { Descriptors } from "../codec/Descriptors.sol";
@@ -13,7 +13,7 @@ import { Descriptors } from "../codec/Descriptors.sol";
13
13
  /// @notice Abstract base for peer-facing rootzero ports.
14
14
  /// Ports handle inter-host operations between cooperating hosts.
15
15
  /// Access is restricted to trusted peer callers via `onlyPeer`.
16
- abstract contract PortBase is NodeCalls, NodeAccess, EndpointBase {
16
+ abstract contract PortBase is NodeCalls, NodeAccess, InputEndpointBase {
17
17
 
18
18
  /// @dev Restrict execution to trusted callers, excluding the commander.
19
19
  modifier onlyPeer() {
@@ -2,23 +2,23 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {PortBase} from "./Base.sol";
5
- import {RoutePayableHook} from "../commands/Relay.sol";
5
+ import {RelayPayableHook} from "../commands/Relay.sol";
6
6
  import {Specs} from "../Codec.sol";
7
7
  import {Execution, Executions, Lanes} from "../execution/Execution.sol";
8
8
 
9
9
  using Executions for Execution;
10
10
 
11
11
  /// @title PortDispatchPayable
12
- /// @notice Port endpoint that forwards DISPATCH blocks to a host-defined route hook.
13
- abstract contract PortDispatchPayable is PortBase, RoutePayableHook {
12
+ /// @notice Port endpoint that forwards DISPATCH blocks to a host-defined relay hook.
13
+ abstract contract PortDispatchPayable is PortBase, RelayPayableHook {
14
14
  uint private immutable descriptor;
15
15
 
16
16
  constructor() {
17
17
  (, descriptor) = port("portDispatchPayable", Specs.Dispatch, Specs.Empty, true);
18
18
  }
19
19
 
20
- /// @notice Forward peer-supplied dispatches to the host-defined route hook.
21
- /// @dev Route hooks receive the shared top-level source value
20
+ /// @notice Forward peer-supplied dispatches to the host-defined relay hook.
21
+ /// @dev Relay hooks receive the shared top-level source value
22
22
  /// budget. Any `msg.value` not spent by the hook remains on this host.
23
23
  /// @param data DISPATCH block stream supplied by the trusted peer.
24
24
  /// @return Empty response bytes.
@@ -27,7 +27,7 @@ abstract contract PortDispatchPayable is PortBase, RoutePayableHook {
27
27
 
28
28
  while (exec.more()) {
29
29
  (uint portal, uint resources, bytes calldata payload) = exec.unpackDispatch(Lanes.Input);
30
- route(portal, resources, bytes(payload), exec);
30
+ relayTo(portal, resources, bytes(payload), exec);
31
31
  }
32
32
 
33
33
  return "";
@@ -2,7 +2,7 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {PortBase} from "./Base.sol";
5
- import {Settlement} from "../core/Settlement.sol";
5
+ import {PostHook} from "../core/Settlement.sol";
6
6
  import {Specs} from "../Codec.sol";
7
7
  import {Execution, Executions, Lanes} from "../execution/Execution.sol";
8
8
  import {Action} from "../annotations/Action.sol";
@@ -10,29 +10,29 @@ import {Actions} from "../utils/Actions.sol";
10
10
 
11
11
  using Executions for Execution;
12
12
 
13
- /// @title PortSettle
14
- /// @notice Port that consumes peer-supplied TRANSACTION blocks through debit and credit hooks.
13
+ /// @title PortPost
14
+ /// @notice Port that posts peer-supplied TRANSACTION blocks through debit and credit hooks.
15
15
  /// Each TRANSACTION block calls `debitAccount` for `from` and `creditAccount` for `to`.
16
- abstract contract PortSettle is PortBase, Settlement, Action {
16
+ abstract contract PortPost is PortBase, PostHook, Action {
17
17
  uint private immutable descriptor;
18
18
 
19
19
  constructor() {
20
20
  uint id;
21
- (id, descriptor) = port("portSettle", Specs.Transaction, Specs.Empty, false);
22
- action(id, Actions.Settle);
21
+ (id, descriptor) = port("portPost", Specs.Transaction, Specs.Empty, false);
22
+ action(id, Actions.Post);
23
23
  }
24
24
 
25
- /// @notice Execute the port-settle call.
25
+ /// @notice Post peer-supplied transactions.
26
26
  /// @param data TRANSACTION block stream supplied by the trusted peer.
27
27
  /// @return Empty response bytes.
28
- function portSettle(bytes calldata data) external onlyPeer returns (bytes memory) {
28
+ function portPost(bytes calldata data) external onlyPeer returns (bytes memory) {
29
29
  Execution memory exec = openInput(data, descriptor, 0);
30
30
 
31
31
  while (exec.more()) {
32
32
  (bytes32 from, bytes32 to, bytes32 asset, uint amount) = exec.unpackTransaction(Lanes.Input);
33
- settle(from, to, asset, amount);
33
+ post(from, to, asset, amount);
34
34
  }
35
-
35
+
36
36
  return "";
37
37
  }
38
38
  }
package/queries/Base.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 { EndpointBase } from "../core/Endpoint.sol";
4
+ import { InputEndpointBase } from "../core/Endpoint.sol";
5
5
  import { Descriptors } from "../codec/Descriptors.sol";
6
6
  import { Specs } from "../codec/Specs.sol";
7
7
  import { Nodes } from "../utils/Nodes.sol";
@@ -11,7 +11,7 @@ import { Selectors } from "../utils/Selectors.sol";
11
11
  /// @notice Abstract base for rootzero query contracts.
12
12
  /// Queries are view-only entry points that consume a block-stream input and
13
13
  /// return a block-stream response.
14
- abstract contract QueryBase is EndpointBase {
14
+ abstract contract QueryBase is InputEndpointBase {
15
15
 
16
16
  /// @notice Publish query metadata and a default label.
17
17
  /// @param name Query entrypoint name and default label. It must exactly
package/utils/Actions.sol CHANGED
@@ -17,4 +17,5 @@ library Actions {
17
17
  uint32 constant Repay = 11;
18
18
  uint32 constant Liquidate = 12;
19
19
  uint32 constant Refund = 13;
20
+ uint32 constant Post = 14;
20
21
  }