@rootzero/contracts 1.24.0 → 1.26.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 (69) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/Codec.sol +1 -2
  3. package/Core.sol +1 -1
  4. package/Endpoints.sol +3 -0
  5. package/README.md +66 -51
  6. package/Utils.sol +2 -1
  7. package/codec/Blocks.sol +354 -108
  8. package/codec/Buffers.sol +24 -20
  9. package/codec/Decoders.sol +49 -31
  10. package/codec/Descriptors.sol +75 -72
  11. package/codec/Keys.sol +5 -1
  12. package/codec/Schema.sol +5 -1
  13. package/codec/Specs.sol +19 -9
  14. package/codec/Writers.sol +14 -19
  15. package/commands/Allocate.sol +8 -7
  16. package/commands/Base.sol +14 -52
  17. package/commands/Bootstrap.sol +95 -0
  18. package/commands/Burn.sol +7 -7
  19. package/commands/Cashout.sol +85 -0
  20. package/commands/Credit.sol +18 -16
  21. package/commands/Debit.sol +22 -21
  22. package/commands/Deposit.sol +13 -13
  23. package/commands/Payout.sol +8 -8
  24. package/commands/Provision.sol +13 -13
  25. package/commands/Recover.sol +7 -7
  26. package/commands/Relay.sol +22 -23
  27. package/commands/Repay.sol +36 -34
  28. package/commands/Settle.sol +24 -22
  29. package/commands/Withdraw.sol +7 -7
  30. package/commands/admin/AllowAssets.sol +7 -7
  31. package/commands/admin/Allowance.sol +7 -7
  32. package/commands/admin/Annotate.sol +7 -7
  33. package/commands/admin/Appoint.sol +7 -7
  34. package/commands/admin/Authorize.sol +7 -7
  35. package/commands/admin/Base.sol +5 -11
  36. package/commands/admin/DenyAssets.sol +7 -7
  37. package/commands/admin/Dismiss.sol +7 -7
  38. package/commands/admin/Execute.sol +8 -8
  39. package/commands/admin/Unauthorize.sol +7 -7
  40. package/core/Calls.sol +3 -3
  41. package/core/Endpoint.sol +7 -7
  42. package/core/Pipeline.sol +40 -22
  43. package/execution/Budget.sol +24 -3
  44. package/execution/Execution.sol +289 -506
  45. package/guards/Base.sol +1 -1
  46. package/guards/Revoke.sol +7 -7
  47. package/package.json +1 -1
  48. package/ports/Allowance.sol +3 -3
  49. package/ports/Assets.sol +7 -7
  50. package/ports/Base.sol +1 -1
  51. package/ports/Credit.sol +3 -3
  52. package/ports/Debit.sol +3 -3
  53. package/ports/Dispatch.sol +3 -3
  54. package/ports/Pipe.sol +7 -8
  55. package/ports/Post.sol +3 -3
  56. package/ports/Redeem.sol +3 -3
  57. package/queries/Assets.sol +3 -3
  58. package/queries/Balances.sol +3 -3
  59. package/queries/Base.sol +1 -1
  60. package/utils/Accounts.sol +1 -3
  61. package/utils/Actions.sol +2 -0
  62. package/utils/Assets.sol +1 -10
  63. package/utils/Cursors.sol +60 -116
  64. package/utils/Errors.sol +50 -0
  65. package/utils/Ids.sol +2 -5
  66. package/utils/Lanes.sol +0 -2
  67. package/utils/Nodes.sol +1 -3
  68. package/utils/Utils.sol +2 -9
  69. package/codec/Readers.sol +0 -190
@@ -5,11 +5,10 @@ import {AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAcc
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";
8
- import {Descriptors} from "../codec/Descriptors.sol";
9
8
  import {Cursors, Cur} from "../utils/Cursors.sol";
9
+ import {InsufficientValue, UnconsumedData} from "../utils/Errors.sol";
10
10
  import {Lanes} from "../utils/Lanes.sol";
11
11
  import {Budget} from "./Budget.sol";
12
- import {max16} from "../utils/Utils.sol";
13
12
 
14
13
  /// @notice Mutable state shared across one endpoint execution.
15
14
  /// @dev `decoders` contains tagged input and state cursor lanes. Cursor operations
@@ -18,165 +17,31 @@ struct Execution {
18
17
  bytes32 account;
19
18
  uint budget;
20
19
  uint decoders;
21
- uint writers;
22
- bytes transactions;
20
+ uint writer;
23
21
  bytes output;
24
22
  }
25
23
 
26
24
  /// @title Executions
27
- /// @notice Opening, decoding, output, transaction, and value helpers for executions.
25
+ /// @notice Opening, decoding, output, and value helpers for executions.
28
26
  /// @dev `output*` helpers consume memory inputs; `outputCopy*` helpers copy
29
27
  /// calldata inputs directly to the output lane.
30
28
  library Executions {
31
29
  using Cursors for uint;
32
30
 
33
- /// @dev Thrown when an execution attempts to spend more value than remains in its budget.
34
- error InsufficientValue();
35
- /// @dev Decoder block counts do not form compatible descriptor groups.
36
- error BadRatio();
37
- /// @dev A descriptor-empty lane received a non-empty block source.
31
+ /// @dev Command-defined lane policy rejected data in an expected-empty lane.
38
32
  error ZeroStride();
39
33
 
40
34
  // -------------------------------------------------------------------------
41
35
  // Opening
42
36
  // -------------------------------------------------------------------------
43
37
 
44
- /// @dev A lane with stride zero accepts only an empty source and returns the zero cursor.
45
- /// @param source Calldata source for the decoder lane.
46
- /// @param descriptor Packed endpoint descriptor.
47
- /// @param lane Input or state lane identifier.
48
- /// @return cur Tagged packed decoder cursor carrying its raw block count, or zero for an absent lane.
49
- function openDecoder(bytes calldata source, uint descriptor, uint8 lane) private pure returns (uint cur) {
50
- uint stride = Descriptors.stride(descriptor, lane);
51
- (uint abs, uint limit) = Cursors.bounds(source);
52
- if (stride == 0 && abs == limit) return 0;
53
- if (stride == 0) revert ZeroStride();
54
-
55
- bytes4 key = Descriptors.key(descriptor, lane);
56
- (uint count, uint end) = Blocks.runExact(abs, limit, key);
57
- if (count == 0) revert Blocks.EmptyRun();
58
- cur = Cursors.create(abs, end - abs, count, 0, lane);
59
- }
60
-
61
- /// @dev Convert one decoder lane's raw block count into descriptor groups.
62
- function groupCount(uint decoders, uint descriptor, uint8 lane) private pure returns (uint groups) {
63
- uint stride = Descriptors.stride(descriptor, lane);
64
- if (stride == 0) return 0;
65
-
66
- uint count = decoders.select(lane).count();
67
- if (count % stride != 0) revert BadRatio();
68
- groups = count / stride;
69
- }
70
-
71
- /// @dev Reconcile decoder lane groups once at endpoint execution opening.
72
- function reconcile(uint decoders, uint descriptor, uint expected) private pure returns (uint groups) {
73
- uint input = groupCount(decoders, descriptor, Lanes.Input);
74
- uint state = groupCount(decoders, descriptor, Lanes.State);
75
- if (input != 0 && state != 0 && input != state) revert BadRatio();
76
-
77
- groups = input != 0 ? input : state;
78
- if (groups != 0 && expected != 0 && groups != expected) revert BadRatio();
79
- if (groups == 0) groups = expected;
80
- max16(groups);
81
- }
82
-
83
- /// @dev Initialize one tagged writer cursor from a descriptor lane.
84
- /// @param descriptor Packed endpoint descriptor.
85
- /// @param batches Reconciled execution batch count.
86
- /// @param lane Output or transaction lane identifier.
87
- /// @param padding Additional logical capacity reserved for the lane.
88
- /// @return cur Tagged packed writer cursor, or zero for an absent lane.
89
- function initWriter(uint descriptor, uint batches, uint8 lane, uint padding) private pure returns (uint cur) {
90
- (uint capacity, bool growable) = Descriptors.allocation(descriptor, lane, batches);
91
- if (capacity == 0) return 0;
92
-
93
- uint count = batches * Descriptors.stride(descriptor, lane);
94
- if (padding != 0) count += padding / Sizes.Transaction;
95
- cur = Buffers.cursor(capacity + padding, count, growable, lane);
96
- }
97
-
98
- /// @dev Open and pair the input and state decoder cursors.
99
- /// @param state State calldata source.
100
- /// @param input Input calldata source.
101
- /// @param descriptor Packed endpoint descriptor.
102
- /// @return Paired decoder cursors.
103
- function decodeCursors(bytes calldata state, bytes calldata input, uint descriptor) private pure returns (uint) {
104
- return
105
- Cursors.pair(openDecoder(input, descriptor, Lanes.Input), openDecoder(state, descriptor, Lanes.State));
106
- }
107
-
108
- /// @dev Initialize and pair the output and transaction writer cursors.
109
- /// @param descriptor Packed endpoint descriptor.
110
- /// @param batches Reconciled execution batch count.
111
- /// @return Paired writer cursors.
112
- function writerCursors(uint descriptor, uint batches) private pure returns (uint) {
113
- return
114
- Cursors.pair(
115
- initWriter(descriptor, batches, Lanes.Output, 0),
116
- initWriter(descriptor, batches, Lanes.Transactions, Sizes.Transaction)
117
- );
118
- }
119
-
120
- /// @dev Complete execution initialization from pre-opened decoder cursors.
121
- /// @param decoders Packed decoder cursor or pair.
122
- /// @param descriptor Packed endpoint descriptor.
123
- /// @param batches Expected batch count; zero derives it from the decoders.
124
- /// @return exec Initialized execution.
125
- function open(uint decoders, uint descriptor, uint batches) private view returns (Execution memory exec) {
126
- exec.budget = msg.value;
127
- exec.decoders = decoders;
128
- batches = reconcile(decoders, descriptor, batches);
129
- exec.writers = writerCursors(descriptor, batches);
130
- }
131
-
132
38
  /// @notice Open an execution containing only the current call-value budget.
133
- /// @dev Decoders, writers, output, and transactions remain empty.
39
+ /// @dev Decoders, writer, and output remain empty.
134
40
  /// @return exec Budget-only execution initialized with `msg.value`.
135
41
  function open() internal view returns (Execution memory exec) {
136
42
  exec.budget = msg.value;
137
43
  }
138
44
 
139
- /// @notice Open an execution with an input decoder and descriptor writers.
140
- /// @param input Input block stream.
141
- /// @param descriptor Packed endpoint descriptor.
142
- /// @param batches Expected batch count; zero derives it from the input run.
143
- /// @return exec Initialized execution.
144
- function openInput(
145
- bytes calldata input,
146
- uint descriptor,
147
- uint batches
148
- ) internal view returns (Execution memory exec) {
149
- return open(openDecoder(input, descriptor, Lanes.Input), descriptor, batches);
150
- }
151
-
152
- /// @notice Open an execution with a state decoder and descriptor writers.
153
- /// @param state State block stream.
154
- /// @param descriptor Packed endpoint descriptor.
155
- /// @param batches Expected batch count; zero derives it from the state run.
156
- /// @return exec Initialized execution.
157
- function openState(
158
- bytes calldata state,
159
- uint descriptor,
160
- uint batches
161
- ) internal view returns (Execution memory exec) {
162
- return open(openDecoder(state, descriptor, Lanes.State), descriptor, batches);
163
- }
164
-
165
- /// @notice Open an execution with paired state and input decoders.
166
- /// @param state State block stream.
167
- /// @param input Input block stream.
168
- /// @param descriptor Packed endpoint descriptor.
169
- /// @param batches Expected batch count; zero derives it from the decoder runs.
170
- /// @return exec Initialized execution.
171
- function open(
172
- bytes calldata state,
173
- bytes calldata input,
174
- uint descriptor,
175
- uint batches
176
- ) internal view returns (Execution memory exec) {
177
- return open(decodeCursors(state, input, descriptor), descriptor, batches);
178
- }
179
-
180
45
  // -------------------------------------------------------------------------
181
46
  // Traversal
182
47
  // -------------------------------------------------------------------------
@@ -188,85 +53,134 @@ library Executions {
188
53
  return exec.decoders.any();
189
54
  }
190
55
 
191
- /// @notice Return a decoder lane's current absolute calldata position.
56
+ /// @notice Make the input decoder the active low lane.
57
+ /// @return exec The same execution, allowing chained decoding.
58
+ function oninput(Execution memory exec) internal pure returns (Execution memory) {
59
+ exec.decoders = exec.decoders.select(Lanes.Input);
60
+ return exec;
61
+ }
62
+
63
+ /// @notice Make the state decoder the active low lane.
64
+ /// @return exec The same execution, allowing chained decoding.
65
+ function onstate(Execution memory exec) internal pure returns (Execution memory) {
66
+ exec.decoders = exec.decoders.select(Lanes.State);
67
+ return exec;
68
+ }
69
+
70
+ /// @notice Return the active decoder's current absolute calldata position.
192
71
  /// @param exec Execution whose decoder is inspected.
193
- /// @param lane Decoder lane to select.
194
- /// @return Current absolute calldata position of the selected lane.
195
- function absolute(Execution memory exec, uint8 lane) internal pure returns (uint) {
196
- return exec.decoders.select(lane).absolute();
72
+ /// @return Current absolute calldata position of the active lane.
73
+ function absolute(Execution memory exec) internal pure returns (uint) {
74
+ return exec.decoders.absolute();
197
75
  }
198
76
 
199
- /// @dev Return the complete validated calldata source for a decoder lane.
77
+ /// @dev Return the complete bounded calldata source for a decoder lane.
200
78
  /// @dev Does not consume or depend on the lane's current position. A lane
201
79
  /// absent because its descriptor is EMPTY returns an empty calldata slice.
202
80
  /// @param exec Execution whose input or state source is requested.
203
- /// @param lane Input or state decoder lane.
204
81
  /// @return data Complete calldata region represented by the lane.
205
82
  function raw(Execution memory exec, uint8 lane) private pure returns (bytes calldata data) {
206
83
  if (!exec.decoders.contains(lane)) return msg.data[0:0];
207
84
 
208
85
  uint cur = exec.decoders.select(lane);
209
- (, uint offset, uint len) = cur.decode();
210
- if (len > msg.data.length || offset > msg.data.length - len) revert Blocks.MalformedBlocks();
211
- return msg.data[offset:offset + len];
86
+ if (uint8(cur >> 96) == 0) return msg.data[0:0];
87
+ (uint abs, uint end) = cur.bounds();
88
+ if (end > msg.data.length) revert Blocks.MalformedBlocks();
89
+ return msg.data[abs:end];
212
90
  }
213
91
 
214
- /// @notice Return the complete validated command state without consuming it.
92
+ /// @notice Return the complete bounded command state without consuming it.
215
93
  /// @dev Remains the complete original state after the state cursor advances.
216
94
  function rawState(Execution memory exec) internal pure returns (bytes calldata) {
217
95
  return raw(exec, Lanes.State);
218
96
  }
219
97
 
220
- /// @notice Return the complete validated endpoint input without consuming it.
98
+ /// @notice Return the complete state lane and mark it fully consumed.
99
+ /// @dev Intended for commands that forward their state intact without decoding it.
100
+ /// A lane declared EMPTY is returned empty and remains unconsumed so close
101
+ /// still rejects any state supplied against the descriptor.
102
+ function takeRawState(Execution memory exec) internal pure returns (bytes calldata data) {
103
+ data = raw(exec, Lanes.State);
104
+ if (!exec.decoders.contains(Lanes.State)) return data;
105
+
106
+ uint cur = exec.decoders.select(Lanes.State);
107
+ if (uint8(cur >> 96) == 0) return data;
108
+ (, , uint len) = cur.decode();
109
+ exec.decoders = cur.seek(len);
110
+ }
111
+
112
+ /// @notice Return the complete bounded endpoint input without consuming it.
221
113
  /// @dev Remains the complete original input after the input cursor advances.
222
114
  function rawInput(Execution memory exec) internal pure returns (bytes calldata) {
223
115
  return raw(exec, Lanes.Input);
224
116
  }
225
117
 
118
+ /// @notice Return the complete input lane and mark it fully consumed.
119
+ /// @dev Intended for endpoints that forward their input intact without decoding it.
120
+ /// A lane declared EMPTY is returned empty and remains unconsumed so close
121
+ /// still rejects any input supplied against the descriptor.
122
+ function takeRawInput(Execution memory exec) internal pure returns (bytes calldata data) {
123
+ data = raw(exec, Lanes.Input);
124
+ if (!exec.decoders.contains(Lanes.Input)) return data;
125
+
126
+ uint cur = exec.decoders.select(Lanes.Input);
127
+ if (uint8(cur >> 96) == 0) return data;
128
+ (, , uint len) = cur.decode();
129
+ exec.decoders = cur.seek(len);
130
+ }
131
+
226
132
  /// @notice Return whether the next block on `lane` has `key` and an empty payload.
227
133
  /// @param exec Execution whose decoder is inspected without advancing.
228
- /// @param lane Decoder lane to inspect.
229
134
  /// @param key Expected block key.
230
135
  /// @return Whether a complete matching empty block header occurs next.
231
- function isEmpty(Execution memory exec, uint8 lane, bytes4 key) internal pure returns (bool) {
232
- uint cur = exec.decoders.select(lane);
136
+ function isEmpty(Execution memory exec, bytes4 key) internal pure returns (bool) {
137
+ uint cur = exec.decoders;
233
138
  (uint i, uint offset, uint len) = cur.decode();
234
139
  return Blocks.isEmpty(offset + i, offset + len, key);
235
140
  }
236
141
 
237
142
  /// @notice Validate and consume the next block from an execution decoder lane.
238
- /// @param exec Execution whose selected decoder cursor is advanced over the complete block.
239
- /// @param lane Execution decoder lane to select.
143
+ /// @param exec Execution whose active decoder cursor is advanced over the complete block.
240
144
  /// @param spec Expected block specification.
241
145
  /// @return abs Absolute position of the first payload byte.
242
146
  /// @return end Absolute position immediately after the payload.
243
- function consume(Execution memory exec, uint8 lane, uint spec) internal pure returns (uint abs, uint end) {
244
- uint cur = exec.decoders.select(lane);
147
+ function consume(Execution memory exec, uint spec) internal pure returns (uint abs, uint end) {
148
+ uint cur = exec.decoders;
245
149
  (abs, end) = Blocks.expect(cur.absolute(), spec);
246
150
  exec.decoders = cur.seekAbs(end);
247
151
  }
248
152
 
153
+ /// @notice Validate a known key and consume the next block from an execution decoder lane.
154
+ /// @dev Validates no payload-size constraint beyond proving the complete block
155
+ /// lies within the active lane's logical region.
156
+ /// @param exec Execution whose active decoder cursor is advanced over the complete block.
157
+ /// @param key Expected block key.
158
+ /// @return abs Absolute position of the first payload byte.
159
+ /// @return end Absolute position immediately after the payload.
160
+ function consume(Execution memory exec, bytes4 key) internal pure returns (uint abs, uint end) {
161
+ uint cur = exec.decoders;
162
+ (abs, end) = Blocks.expectKey(cur.absolute(), key);
163
+ exec.decoders = cur.seekAbs(end);
164
+ }
165
+
249
166
  /// @notice Validate and consume one block from a decoder lane, returning its complete encoding.
250
- /// @param exec Execution whose selected decoder cursor is advanced past the block.
251
- /// @param lane Execution decoder lane to select.
167
+ /// @param exec Execution whose active decoder cursor is advanced past the block.
252
168
  /// @param key Expected block key.
253
169
  /// @return data Calldata view of the complete block, including its header.
254
170
  function takeBlock(
255
171
  Execution memory exec,
256
- uint8 lane,
257
172
  bytes4 key
258
173
  ) internal pure returns (bytes calldata data) {
259
- (uint abs, uint end) = consume(exec, lane, Specs.create(key, 0, 0, 0));
174
+ (uint abs, uint end) = consume(exec, key);
260
175
  data = msg.data[abs - Sizes.Header:end];
261
176
  }
262
177
 
263
178
  /// @notice Consume a matching empty block from an execution decoder lane when present.
264
- /// @param exec Execution whose selected decoder advances only for a matching empty block.
265
- /// @param lane Decoder lane to consume.
179
+ /// @param exec Execution whose active decoder advances only for a matching empty block.
266
180
  /// @param key Expected block key.
267
181
  /// @return Whether an empty block was consumed.
268
- function tryConsumeEmpty(Execution memory exec, uint8 lane, bytes4 key) internal pure returns (bool) {
269
- uint cur = exec.decoders.select(lane);
182
+ function tryConsumeEmpty(Execution memory exec, bytes4 key) internal pure returns (bool) {
183
+ uint cur = exec.decoders;
270
184
  (uint i, uint offset, uint size) = cur.decode();
271
185
  (bytes4 current, uint len) = Blocks.peek(offset + i, offset + size);
272
186
  if (current != key || len != 0) return false;
@@ -275,34 +189,31 @@ library Executions {
275
189
  }
276
190
 
277
191
  /// @notice Validate and enter the payload of the next block in an execution decoder lane.
278
- /// @dev The selected lane remains in its existing frame so callers can decode
192
+ /// @dev The active lane remains in its existing frame so callers can decode
279
193
  /// child blocks in place. Callers should prove complete payload consumption
280
194
  /// with `exec.expectAbs(end)` after decoding the children from the same lane.
281
- /// @param exec Execution whose selected decoder cursor advances over the block header.
282
- /// @param lane Execution decoder lane to select.
195
+ /// @param exec Execution whose active decoder cursor advances over the block header.
283
196
  /// @param spec Expected parent block specification.
284
197
  /// @return abs Absolute position of the first payload byte.
285
198
  /// @return end Absolute position immediately after the payload.
286
- function enter(Execution memory exec, uint8 lane, uint spec) internal pure returns (uint abs, uint end) {
287
- return enter(exec, lane, spec, 0);
199
+ function enter(Execution memory exec, uint spec) internal pure returns (uint abs, uint end) {
200
+ return enter(exec, spec, 0);
288
201
  }
289
202
 
290
203
  /// @notice Validate a parent block and advance over a fixed payload prefix.
291
204
  /// @dev `amount` is relative to the payload start and cannot exceed the
292
205
  /// current parent payload. The returned `abs` remains the payload start.
293
- /// @param exec Execution whose selected decoder advances over the header and fixed prefix.
294
- /// @param lane Execution decoder lane to select.
206
+ /// @param exec Execution whose active decoder advances over the header and fixed prefix.
295
207
  /// @param spec Expected parent block specification.
296
208
  /// @param amount Number of initial payload bytes to advance over.
297
209
  /// @return abs Absolute position of the first payload byte.
298
210
  /// @return end Absolute position immediately after the payload.
299
211
  function enter(
300
212
  Execution memory exec,
301
- uint8 lane,
302
213
  uint spec,
303
214
  uint amount
304
215
  ) internal pure returns (uint abs, uint end) {
305
- uint cur = exec.decoders.select(lane);
216
+ uint cur = exec.decoders;
306
217
  (abs, end) = Blocks.expect(cur.absolute(), spec);
307
218
  if (amount > end - abs) revert Blocks.InvalidBlock();
308
219
  exec.decoders = cur.seekAbs(abs + amount);
@@ -310,26 +221,24 @@ library Executions {
310
221
 
311
222
  /// @notice Advance an execution decoder lane by a raw byte count.
312
223
  /// @dev No block header or schema is validated.
313
- /// @param exec Execution whose selected decoder cursor is advanced.
314
- /// @param lane Decoder lane to select.
224
+ /// @param exec Execution whose active decoder cursor is advanced.
315
225
  /// @param amount Number of bytes to advance.
316
- function advance(Execution memory exec, uint8 lane, uint amount) internal pure {
317
- uint cur = exec.decoders.select(lane);
226
+ function advance(Execution memory exec, uint amount) internal pure {
227
+ uint cur = exec.decoders;
318
228
  exec.decoders = cur.advance(amount);
319
229
  }
320
230
 
321
231
  /// @notice Take a raw byte range from an execution decoder lane.
322
232
  /// @dev No block header or schema is validated.
323
- /// @param exec Execution whose selected decoder cursor is advanced.
324
- /// @param lane Decoder lane to select.
233
+ /// @param exec Execution whose active decoder cursor is advanced.
325
234
  /// @param amount Number of bytes to take.
326
235
  /// @return abs Absolute position of the first taken byte.
327
- function take(Execution memory exec, uint8 lane, uint amount) internal pure returns (uint abs) {
328
- (exec.decoders, abs) = exec.decoders.consume(lane, amount);
236
+ function take(Execution memory exec, uint amount) internal pure returns (uint abs) {
237
+ (exec.decoders, abs) = exec.decoders.consume(amount);
329
238
  }
330
239
 
331
240
  /// @notice Require the active execution decoder to be at absolute position `abs`.
332
- /// @dev The most recent lane-aware decoder operation determines the active lane.
241
+ /// @dev `oninput()` and `onstate()` determine the active lane.
333
242
  /// @param exec Execution whose active decoder position is validated.
334
243
  /// @param abs Expected absolute position.
335
244
  function expectAbs(Execution memory exec, uint abs) internal pure {
@@ -338,19 +247,17 @@ library Executions {
338
247
 
339
248
  /// @notice Consume a LIST block and return a cursor scoped to its payload.
340
249
  /// @param exec Execution whose decoder is advanced.
341
- /// @param lane Decoder lane containing the LIST block.
342
250
  /// @return items Cursor over the nested list items.
343
- function list(Execution memory exec, uint8 lane) internal pure returns (Cur memory items) {
344
- return list(exec, Specs.List, lane);
251
+ function list(Execution memory exec) internal pure returns (Cur memory items) {
252
+ return list(exec, Specs.List);
345
253
  }
346
254
 
347
255
  /// @notice Consume a list block described by `spec` and return a cursor scoped to its payload.
348
256
  /// @param exec Execution whose decoder is advanced.
349
257
  /// @param spec Custom list block specification.
350
- /// @param lane Decoder lane containing the list block.
351
258
  /// @return items Cursor over the nested list items.
352
- function list(Execution memory exec, uint spec, uint8 lane) internal pure returns (Cur memory items) {
353
- (uint abs, uint end) = consume(exec, lane, spec);
259
+ function list(Execution memory exec, uint spec) internal pure returns (Cur memory items) {
260
+ (uint abs, uint end) = consume(exec, spec);
354
261
  items.state = Cursors.create(abs, end - abs, 0, 0, 0);
355
262
  }
356
263
 
@@ -358,400 +265,350 @@ library Executions {
358
265
  // Fixed-width block decoding
359
266
  // -------------------------------------------------------------------------
360
267
 
361
- /// @dev Return the next raw calldata word from `lane` and advance by `size` bytes.
362
- function next(Execution memory exec, uint8 lane, uint size) private pure returns (bytes32 value) {
363
- value = Blocks.read32(take(exec, lane, size));
268
+ /// @dev Return the next raw calldata word from the active lane and advance by `size` bytes.
269
+ function next(Execution memory exec, uint size) private pure returns (bytes32 value) {
270
+ value = Blocks.read32(take(exec, size));
364
271
  }
365
272
 
366
273
  /// @notice Return the next raw byte from a decoder lane and advance it by one byte.
367
- function next1(Execution memory exec, uint8 lane) internal pure returns (bytes1 value) {
368
- value = bytes1(next(exec, lane, 1));
274
+ function next1(Execution memory exec) internal pure returns (bytes1 value) {
275
+ value = bytes1(next(exec, 1));
369
276
  }
370
277
 
371
278
  /// @notice Return the next two raw bytes from a decoder lane and advance it by two bytes.
372
- function next2(Execution memory exec, uint8 lane) internal pure returns (bytes2 value) {
373
- value = bytes2(next(exec, lane, 2));
279
+ function next2(Execution memory exec) internal pure returns (bytes2 value) {
280
+ value = bytes2(next(exec, 2));
374
281
  }
375
282
 
376
283
  /// @notice Return the next four raw bytes from a decoder lane and advance it by four bytes.
377
- function next4(Execution memory exec, uint8 lane) internal pure returns (bytes4 value) {
378
- value = bytes4(next(exec, lane, 4));
284
+ function next4(Execution memory exec) internal pure returns (bytes4 value) {
285
+ value = bytes4(next(exec, 4));
379
286
  }
380
287
 
381
288
  /// @notice Return the next eight raw bytes from a decoder lane and advance it by eight bytes.
382
- function next8(Execution memory exec, uint8 lane) internal pure returns (bytes8 value) {
383
- value = bytes8(next(exec, lane, 8));
289
+ function next8(Execution memory exec) internal pure returns (bytes8 value) {
290
+ value = bytes8(next(exec, 8));
384
291
  }
385
292
 
386
293
  /// @notice Return the next sixteen raw bytes from a decoder lane and advance it by sixteen bytes.
387
- function next16(Execution memory exec, uint8 lane) internal pure returns (bytes16 value) {
388
- value = bytes16(next(exec, lane, 16));
294
+ function next16(Execution memory exec) internal pure returns (bytes16 value) {
295
+ value = bytes16(next(exec, 16));
389
296
  }
390
297
 
391
298
  /// @notice Return the next raw calldata word from a decoder lane and advance it.
392
- /// @param exec Execution whose selected decoder cursor advances by one word.
393
- /// @param lane Execution decoder lane to select.
394
- /// @return value Raw word at the selected lane's previous position.
395
- function next32(Execution memory exec, uint8 lane) internal pure returns (bytes32 value) {
396
- value = next(exec, lane, Sizes.Word);
299
+ /// @param exec Execution whose active decoder cursor advances by one word.
300
+ /// @return value Raw word at the active lane's previous position.
301
+ function next32(Execution memory exec) internal pure returns (bytes32 value) {
302
+ value = next(exec, Sizes.Word);
397
303
  }
398
304
 
399
- /// @notice Decode one fixed 32-byte payload from `lane`.
305
+ /// @notice Decode one fixed 32-byte payload from the active lane.
400
306
  /// @param exec Execution whose decoder is advanced.
401
- /// @param lane Decoder lane to consume.
402
307
  /// @param spec Expected fixed block specification.
403
308
  /// @return value Decoded payload word.
404
- function unpack32(Execution memory exec, uint8 lane, uint spec) internal pure returns (bytes32 value) {
309
+ function unpack32(Execution memory exec, uint spec) internal pure returns (bytes32 value) {
405
310
  uint abs;
406
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B32);
311
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B32);
407
312
  if (Blocks.header(abs, Specs.key(spec)) != 32) revert Blocks.InvalidBlock();
408
313
  assembly ("memory-safe") {
409
314
  value := calldataload(add(abs, 0x08))
410
315
  }
411
316
  }
412
317
 
413
- /// @notice Decode and consume one ACCOUNT block from `lane`.
318
+ /// @notice Decode and consume one ACCOUNT block from the active lane.
414
319
  /// @param exec Execution whose decoder is advanced.
415
- /// @param lane Decoder lane to consume.
416
320
  /// @return account Decoded account identifier.
417
- function unpackAccount(Execution memory exec, uint8 lane) internal pure returns (bytes32 account) {
321
+ function unpackAccount(Execution memory exec) internal pure returns (bytes32 account) {
418
322
  uint abs;
419
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B32);
323
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B32);
420
324
  account = Blocks.unpackAccount(abs);
421
325
  }
422
326
 
423
- /// @notice Decode and consume one NODE block from `lane`.
327
+ /// @notice Decode and consume one NODE block from the active lane.
424
328
  /// @param exec Execution whose decoder is advanced.
425
- /// @param lane Decoder lane to consume.
426
329
  /// @return node Decoded node identifier.
427
- function unpackNode(Execution memory exec, uint8 lane) internal pure returns (uint node) {
330
+ function unpackNode(Execution memory exec) internal pure returns (uint node) {
428
331
  uint abs;
429
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B32);
332
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B32);
430
333
  node = Blocks.unpackNode(abs);
431
334
  }
432
335
 
433
- /// @notice Decode and consume one ASSET block from `lane`.
336
+ /// @notice Decode and consume one CASHOUT block from the active lane.
337
+ /// @param exec Execution whose decoder is advanced.
338
+ /// @return amount Native-asset amount to withdraw.
339
+ function unpackCashout(Execution memory exec) internal pure returns (uint amount) {
340
+ uint abs;
341
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.Cashout);
342
+ amount = Blocks.unpackCashout(abs);
343
+ }
344
+
345
+ /// @notice Decode and consume one BOOTSTRAP block from the active lane.
346
+ /// @param exec Execution whose decoder is advanced.
347
+ /// @return asset Decoded asset identifier.
348
+ /// @return amount Decoded balance amount.
349
+ /// @return budget Decoded native-value budget contribution.
350
+ function unpackBootstrap(
351
+ Execution memory exec
352
+ ) internal pure returns (bytes32 asset, uint amount, uint budget) {
353
+ uint abs;
354
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.Bootstrap);
355
+ return Blocks.unpackBootstrap(abs);
356
+ }
357
+
358
+ /// @notice Decode and consume one ASSET block from the active lane.
434
359
  /// @param exec Execution whose decoder is advanced.
435
- /// @param lane Decoder lane to consume.
436
360
  /// @return asset Decoded asset identifier.
437
- function unpackAsset(Execution memory exec, uint8 lane) internal pure returns (bytes32 asset) {
361
+ function unpackAsset(Execution memory exec) internal pure returns (bytes32 asset) {
438
362
  uint abs;
439
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B32);
363
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B32);
440
364
  asset = Blocks.unpackAsset(abs);
441
365
  }
442
366
 
443
- /// @notice Decode and consume one ACCOUNT_ASSET block from `lane`.
367
+ /// @notice Decode and consume one ACCOUNT_ASSET block from the active lane.
444
368
  /// @param exec Execution whose decoder is advanced.
445
- /// @param lane Decoder lane to consume.
446
369
  /// @return account Decoded account identifier.
447
370
  /// @return asset Decoded asset identifier.
448
- function unpackAccountAsset(
449
- Execution memory exec,
450
- uint8 lane
451
- ) internal pure returns (bytes32 account, bytes32 asset) {
371
+ function unpackAccountAsset(Execution memory exec) internal pure returns (bytes32 account, bytes32 asset) {
452
372
  uint abs;
453
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B64);
373
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B64);
454
374
  (account, asset) = Blocks.unpackAccountAsset(abs);
455
375
  }
456
376
 
457
377
  /// @notice Decode one ACCOUNT_ASSET block into its structured value.
458
378
  /// @param exec Execution whose decoder is advanced.
459
- /// @param lane Decoder lane to consume.
460
379
  /// @return value Decoded account and asset.
461
- function unpackAccountAssetValue(
462
- Execution memory exec,
463
- uint8 lane
464
- ) internal pure returns (AccountAsset memory value) {
465
- (value.account, value.asset) = unpackAccountAsset(exec, lane);
380
+ function unpackAccountAssetValue(Execution memory exec) internal pure returns (AccountAsset memory value) {
381
+ (value.account, value.asset) = unpackAccountAsset(exec);
466
382
  }
467
383
 
468
- /// @notice Decode and consume one HOST_ASSET block from `lane`.
384
+ /// @notice Decode and consume one HOST_ASSET block from the active lane.
469
385
  /// @param exec Execution whose decoder is advanced.
470
- /// @param lane Decoder lane to consume.
471
386
  /// @return host Decoded host identifier.
472
387
  /// @return asset Decoded asset identifier.
473
- function unpackHostAsset(
474
- Execution memory exec,
475
- uint8 lane
476
- ) internal pure returns (uint host, bytes32 asset) {
388
+ function unpackHostAsset(Execution memory exec) internal pure returns (uint host, bytes32 asset) {
477
389
  uint abs;
478
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.HostAsset);
390
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.HostAsset);
479
391
  (host, asset) = Blocks.unpackHostAsset(abs);
480
392
  }
481
393
 
482
394
  /// @notice Decode one HOST_ASSET block into its structured value.
483
395
  /// @param exec Execution whose decoder is advanced.
484
- /// @param lane Decoder lane to consume.
485
396
  /// @return value Decoded host and asset.
486
- function unpackHostAssetValue(
487
- Execution memory exec,
488
- uint8 lane
489
- ) internal pure returns (HostAsset memory value) {
490
- (value.host, value.asset) = unpackHostAsset(exec, lane);
397
+ function unpackHostAssetValue(Execution memory exec) internal pure returns (HostAsset memory value) {
398
+ (value.host, value.asset) = unpackHostAsset(exec);
491
399
  }
492
400
 
493
- /// @notice Decode and consume one AMOUNT block from `lane`.
401
+ /// @notice Decode and consume one AMOUNT block from the active lane.
494
402
  /// @param exec Execution whose decoder is advanced.
495
- /// @param lane Decoder lane to consume.
496
403
  /// @return asset Decoded asset identifier.
497
404
  /// @return amount Decoded amount.
498
- function unpackAmount(Execution memory exec, uint8 lane) internal pure returns (bytes32 asset, uint amount) {
405
+ function unpackAmount(Execution memory exec) internal pure returns (bytes32 asset, uint amount) {
499
406
  uint abs;
500
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Amount);
407
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.Amount);
501
408
  (asset, amount) = Blocks.unpackAmount(abs);
502
409
  }
503
410
 
504
411
  /// @notice Decode one AMOUNT block into its structured value.
505
412
  /// @param exec Execution whose decoder is advanced.
506
- /// @param lane Decoder lane to consume.
507
413
  /// @return value Decoded asset and amount.
508
- function unpackAmountValue(Execution memory exec, uint8 lane) internal pure returns (AssetAmount memory value) {
509
- (value.asset, value.amount) = unpackAmount(exec, lane);
414
+ function unpackAmountValue(Execution memory exec) internal pure returns (AssetAmount memory value) {
415
+ (value.asset, value.amount) = unpackAmount(exec);
510
416
  }
511
417
 
512
- /// @notice Decode and consume one BALANCE block from `lane`.
418
+ /// @notice Decode and consume one BALANCE block from the active lane.
513
419
  /// @param exec Execution whose decoder is advanced.
514
- /// @param lane Decoder lane to consume.
515
420
  /// @return asset Decoded asset identifier.
516
421
  /// @return amount Decoded balance amount.
517
- function unpackBalance(Execution memory exec, uint8 lane) internal pure returns (bytes32 asset, uint amount) {
422
+ function unpackBalance(Execution memory exec) internal pure returns (bytes32 asset, uint amount) {
518
423
  uint abs;
519
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Balance);
424
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.Balance);
520
425
  (asset, amount) = Blocks.unpackBalance(abs);
521
426
  }
522
427
 
523
428
  /// @notice Decode one BALANCE block into its structured value.
524
429
  /// @param exec Execution whose decoder is advanced.
525
- /// @param lane Decoder lane to consume.
526
430
  /// @return value Decoded asset and balance amount.
527
- function unpackBalanceValue(Execution memory exec, uint8 lane) internal pure returns (AssetAmount memory value) {
528
- (value.asset, value.amount) = unpackBalance(exec, lane);
431
+ function unpackBalanceValue(Execution memory exec) internal pure returns (AssetAmount memory value) {
432
+ (value.asset, value.amount) = unpackBalance(exec);
529
433
  }
530
434
 
531
- /// @notice Decode and consume one DEBT block from `lane`.
532
- function unpackDebt(Execution memory exec, uint8 lane) internal pure returns (bytes32 liability, uint debt) {
435
+ /// @notice Decode and consume one DEBT block from the active lane.
436
+ function unpackDebt(Execution memory exec) internal pure returns (bytes32 liability, uint debt) {
533
437
  uint abs;
534
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Debt);
438
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.Debt);
535
439
  (liability, debt) = Blocks.unpackDebt(abs);
536
440
  }
537
441
 
538
442
  /// @notice Decode one DEBT block into its structured value.
539
- function unpackDebtValue(Execution memory exec, uint8 lane) internal pure returns (Debt memory value) {
540
- (value.liability, value.debt) = unpackDebt(exec, lane);
443
+ function unpackDebtValue(Execution memory exec) internal pure returns (Debt memory value) {
444
+ (value.liability, value.debt) = unpackDebt(exec);
541
445
  }
542
446
 
543
- /// @notice Decode and consume one POSITION block from `lane`.
544
- function unpackPosition(
545
- Execution memory exec,
546
- uint8 lane
547
- ) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
447
+ /// @notice Decode and consume one POSITION block from the active lane.
448
+ function unpackPosition(Execution memory exec) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
548
449
  uint abs;
549
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Position);
450
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.Position);
550
451
  (asset, amount, liability, debt) = Blocks.unpackPosition(abs);
551
452
  }
552
453
 
553
454
  /// @notice Decode one POSITION block into its structured value.
554
- function unpackPositionValue(
555
- Execution memory exec,
556
- uint8 lane
557
- ) internal pure returns (Position memory value) {
558
- (value.asset, value.amount, value.liability, value.debt) = unpackPosition(exec, lane);
455
+ function unpackPositionValue(Execution memory exec) internal pure returns (Position memory value) {
456
+ (value.asset, value.amount, value.liability, value.debt) = unpackPosition(exec);
559
457
  }
560
458
 
561
459
  /// @notice Decode one BALANCE block and associate it with `host`.
562
460
  /// @param exec Execution whose decoder is advanced.
563
- /// @param lane Decoder lane to consume.
564
461
  /// @param host Host associated with the decoded balance.
565
462
  /// @return value Host-scoped asset amount.
566
463
  function unpackBalanceForHost(
567
464
  Execution memory exec,
568
- uint8 lane,
569
465
  uint host
570
466
  ) internal pure returns (HostAmount memory value) {
571
467
  uint abs;
572
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Balance);
468
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.Balance);
573
469
  value.host = host;
574
470
  (value.asset, value.amount) = Blocks.unpackBalance(abs);
575
471
  }
576
472
 
577
- /// @notice Decode and consume one ACCOUNT_AMOUNT block from `lane`.
473
+ /// @notice Decode and consume one ACCOUNT_AMOUNT block from the active lane.
578
474
  /// @param exec Execution whose decoder is advanced.
579
- /// @param lane Decoder lane to consume.
580
475
  /// @return account Decoded account identifier.
581
476
  /// @return asset Decoded asset identifier.
582
477
  /// @return amount Decoded amount.
583
- function unpackAccountAmount(
584
- Execution memory exec,
585
- uint8 lane
586
- ) internal pure returns (bytes32 account, bytes32 asset, uint amount) {
478
+ function unpackAccountAmount(Execution memory exec) internal pure returns (bytes32 account, bytes32 asset, uint amount) {
587
479
  uint abs;
588
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
480
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B96);
589
481
  (account, asset, amount) = Blocks.unpackAccountAmount(abs);
590
482
  }
591
483
 
592
484
  /// @notice Decode one ACCOUNT_AMOUNT block into its structured value.
593
485
  /// @param exec Execution whose decoder is advanced.
594
- /// @param lane Decoder lane to consume.
595
486
  /// @return value Decoded account, asset, and amount.
596
- function unpackAccountAmountValue(
597
- Execution memory exec,
598
- uint8 lane
599
- ) internal pure returns (AccountAmount memory value) {
600
- (value.account, value.asset, value.amount) = unpackAccountAmount(exec, lane);
487
+ function unpackAccountAmountValue(Execution memory exec) internal pure returns (AccountAmount memory value) {
488
+ (value.account, value.asset, value.amount) = unpackAccountAmount(exec);
601
489
  }
602
490
 
603
- /// @notice Decode and consume one ALLOCATION block from `lane`.
491
+ /// @notice Decode and consume one ALLOCATION block from the active lane.
604
492
  /// @param exec Execution whose decoder is advanced.
605
- /// @param lane Decoder lane to consume.
606
493
  /// @return host Decoded host identifier.
607
494
  /// @return asset Decoded asset identifier.
608
495
  /// @return amount Decoded amount.
609
- function unpackAllocation(
610
- Execution memory exec,
611
- uint8 lane
612
- ) internal pure returns (uint host, bytes32 asset, uint amount) {
496
+ function unpackAllocation(Execution memory exec) internal pure returns (uint host, bytes32 asset, uint amount) {
613
497
  uint abs;
614
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
498
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B96);
615
499
  (host, asset, amount) = Blocks.unpackAllocation(abs);
616
500
  }
617
501
 
618
502
  /// @notice Decode one ALLOCATION block into its structured value.
619
503
  /// @param exec Execution whose decoder is advanced.
620
- /// @param lane Decoder lane to consume.
621
504
  /// @return value Decoded host, asset, and amount.
622
- function unpackAllocationValue(Execution memory exec, uint8 lane) internal pure returns (HostAmount memory value) {
623
- (value.host, value.asset, value.amount) = unpackAllocation(exec, lane);
505
+ function unpackAllocationValue(Execution memory exec) internal pure returns (HostAmount memory value) {
506
+ (value.host, value.asset, value.amount) = unpackAllocation(exec);
624
507
  }
625
508
 
626
- /// @notice Decode and consume one ALLOWANCE block from `lane`.
509
+ /// @notice Decode and consume one ALLOWANCE block from the active lane.
627
510
  /// @param exec Execution whose decoder is advanced.
628
- /// @param lane Decoder lane to consume.
629
511
  /// @return host Decoded host identifier.
630
512
  /// @return asset Decoded asset identifier.
631
513
  /// @return amount Decoded allowance amount.
632
- function unpackAllowance(
633
- Execution memory exec,
634
- uint8 lane
635
- ) internal pure returns (uint host, bytes32 asset, uint amount) {
514
+ function unpackAllowance(Execution memory exec) internal pure returns (uint host, bytes32 asset, uint amount) {
636
515
  uint abs;
637
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
516
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B96);
638
517
  (host, asset, amount) = Blocks.unpackAllowance(abs);
639
518
  }
640
519
 
641
520
  /// @notice Decode one ALLOWANCE block into its structured value.
642
521
  /// @param exec Execution whose decoder is advanced.
643
- /// @param lane Decoder lane to consume.
644
522
  /// @return value Decoded host, asset, and allowance amount.
645
- function unpackAllowanceValue(Execution memory exec, uint8 lane) internal pure returns (HostAmount memory value) {
646
- (value.host, value.asset, value.amount) = unpackAllowance(exec, lane);
523
+ function unpackAllowanceValue(Execution memory exec) internal pure returns (HostAmount memory value) {
524
+ (value.host, value.asset, value.amount) = unpackAllowance(exec);
647
525
  }
648
526
 
649
- /// @notice Decode and consume one CUSTODY block from `lane`.
527
+ /// @notice Decode and consume one CUSTODY block from the active lane.
650
528
  /// @param exec Execution whose decoder is advanced.
651
- /// @param lane Decoder lane to consume.
652
529
  /// @return host Decoded host identifier.
653
530
  /// @return asset Decoded asset identifier.
654
531
  /// @return amount Decoded custody amount.
655
- function unpackCustody(
656
- Execution memory exec,
657
- uint8 lane
658
- ) internal pure returns (uint host, bytes32 asset, uint amount) {
532
+ function unpackCustody(Execution memory exec) internal pure returns (uint host, bytes32 asset, uint amount) {
659
533
  uint abs;
660
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
534
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B96);
661
535
  (host, asset, amount) = Blocks.unpackCustody(abs);
662
536
  }
663
537
 
664
538
  /// @notice Decode one CUSTODY block into its structured value.
665
539
  /// @param exec Execution whose decoder is advanced.
666
- /// @param lane Decoder lane to consume.
667
540
  /// @return value Decoded host, asset, and custody amount.
668
- function unpackCustodyValue(Execution memory exec, uint8 lane) internal pure returns (HostAmount memory value) {
669
- (value.host, value.asset, value.amount) = unpackCustody(exec, lane);
541
+ function unpackCustodyValue(Execution memory exec) internal pure returns (HostAmount memory value) {
542
+ (value.host, value.asset, value.amount) = unpackCustody(exec);
670
543
  }
671
544
 
672
- /// @notice Decode and consume one HOST_ACCOUNT_ASSET block from `lane`.
545
+ /// @notice Decode and consume one HOST_ACCOUNT_ASSET block from the active lane.
673
546
  /// @param exec Execution whose decoder is advanced.
674
- /// @param lane Decoder lane to consume.
675
547
  /// @return host Decoded host identifier.
676
548
  /// @return account Decoded account identifier.
677
549
  /// @return asset Decoded asset identifier.
678
- function unpackHostAccountAsset(
679
- Execution memory exec,
680
- uint8 lane
681
- ) internal pure returns (uint host, bytes32 account, bytes32 asset) {
550
+ function unpackHostAccountAsset(Execution memory exec) internal pure returns (uint host, bytes32 account, bytes32 asset) {
682
551
  uint abs;
683
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
552
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.B96);
684
553
  (host, account, asset) = Blocks.unpackHostAccountAsset(abs);
685
554
  }
686
555
 
687
556
  /// @notice Decode one HOST_ACCOUNT_ASSET block into its structured value.
688
557
  /// @param exec Execution whose decoder is advanced.
689
- /// @param lane Decoder lane to consume.
690
558
  /// @return value Decoded host, account, and asset.
691
- function unpackHostAccountAssetValue(
692
- Execution memory exec,
693
- uint8 lane
694
- ) internal pure returns (HostAccountAsset memory value) {
695
- (value.host, value.account, value.asset) = unpackHostAccountAsset(exec, lane);
559
+ function unpackHostAccountAssetValue(Execution memory exec) internal pure returns (HostAccountAsset memory value) {
560
+ (value.host, value.account, value.asset) = unpackHostAccountAsset(exec);
696
561
  }
697
562
 
698
- /// @notice Decode and consume one TRANSACTION block from `lane`.
563
+ /// @notice Decode and consume one TRANSACTION block from the active lane.
699
564
  /// @param exec Execution whose decoder is advanced.
700
- /// @param lane Decoder lane to consume.
701
565
  /// @return from Decoded debit account.
702
566
  /// @return to Decoded credit account.
703
567
  /// @return asset Decoded asset identifier.
704
568
  /// @return amount Decoded transaction amount.
705
- function unpackTransaction(
706
- Execution memory exec,
707
- uint8 lane
708
- ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
569
+ function unpackTransaction(Execution memory exec) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
709
570
  uint abs;
710
- (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Transaction);
571
+ (exec.decoders, abs) = exec.decoders.consume(Sizes.Transaction);
711
572
  (from, to, asset, amount) = Blocks.unpackTransaction(abs);
712
573
  }
713
574
 
714
575
  /// @notice Decode one TRANSACTION block into its structured value.
715
576
  /// @param exec Execution whose decoder is advanced.
716
- /// @param lane Decoder lane to consume.
717
577
  /// @return value Decoded transaction.
718
- function unpackTransactionValue(Execution memory exec, uint8 lane) internal pure returns (Tx memory value) {
719
- (value.from, value.to, value.asset, value.amount) = unpackTransaction(exec, lane);
578
+ function unpackTransactionValue(Execution memory exec) internal pure returns (Tx memory value) {
579
+ (value.from, value.to, value.asset, value.amount) = unpackTransaction(exec);
720
580
  }
721
581
 
722
582
  // -------------------------------------------------------------------------
723
583
  // Dynamic block decoding
724
584
  // -------------------------------------------------------------------------
725
585
 
726
- /// @notice Decode and consume a block described by `spec` from `lane`.
586
+ /// @notice Decode and consume a block described by `spec` from the active lane.
727
587
  /// @param exec Execution whose decoder is advanced.
728
- /// @param lane Decoder lane to consume.
729
588
  /// @param spec Expected block specification.
730
589
  /// @return data Calldata view of the decoded payload.
731
- function unpackRaw(Execution memory exec, uint8 lane, uint spec) internal pure returns (bytes calldata data) {
732
- uint cur = exec.decoders.select(lane);
590
+ function unpackRaw(Execution memory exec, uint spec) internal pure returns (bytes calldata data) {
591
+ uint cur = exec.decoders;
733
592
  uint end;
734
593
  (data, end) = Blocks.unpackRaw(cur.absolute(), spec);
735
594
  exec.decoders = cur.seekAbs(end);
736
595
  }
737
596
 
738
- /// @notice Decode and consume one BYTES block from `lane`.
597
+ /// @notice Decode and consume one BYTES block from the active lane.
739
598
  /// @param exec Execution whose decoder is advanced.
740
- /// @param lane Decoder lane to consume.
741
599
  /// @return data Decoded byte payload.
742
- function unpackBytes(Execution memory exec, uint8 lane) internal pure returns (bytes calldata data) {
743
- uint cur = exec.decoders.select(lane);
600
+ function unpackBytes(Execution memory exec) internal pure returns (bytes calldata data) {
601
+ uint cur = exec.decoders;
744
602
  uint end;
745
603
  (data, end) = Blocks.unpackBytes(cur.absolute());
746
604
  exec.decoders = cur.seekAbs(end);
747
605
  }
748
606
 
749
- /// @notice Decode and consume one STRING block from `lane`.
607
+ /// @notice Decode and consume one STRING block from the active lane.
750
608
  /// @param exec Execution whose decoder is advanced.
751
- /// @param lane Decoder lane to consume.
752
609
  /// @return data Decoded string payload.
753
- function unpackString(Execution memory exec, uint8 lane) internal pure returns (string memory data) {
754
- uint cur = exec.decoders.select(lane);
610
+ function unpackString(Execution memory exec) internal pure returns (string memory data) {
611
+ uint cur = exec.decoders;
755
612
  bytes calldata value;
756
613
  uint end;
757
614
  (value, end) = Blocks.unpackString(cur.absolute());
@@ -759,149 +616,113 @@ library Executions {
759
616
  data = string(value);
760
617
  }
761
618
 
762
- /// @notice Decode and consume one STEP block from `lane`.
619
+ /// @notice Decode and consume one STEP block from the active lane.
763
620
  /// @param exec Execution whose decoder is advanced.
764
- /// @param lane Decoder lane to consume.
765
621
  /// @return cmd Decoded command identifier.
766
- /// @return resources Decoded packed resources.
622
+ /// @return value Decoded native value.
767
623
  /// @return input Decoded nested input.
768
- function unpackStep(
769
- Execution memory exec,
770
- uint8 lane
771
- ) internal pure returns (uint cmd, uint resources, bytes calldata input) {
772
- uint cur = exec.decoders.select(lane);
624
+ function unpackStep(Execution memory exec) internal pure returns (uint cmd, uint128 value, bytes calldata input) {
625
+ uint cur = exec.decoders;
773
626
  uint end;
774
- (cmd, resources, input, end) = Blocks.unpackStep(cur.absolute());
627
+ (cmd, value, input, end) = Blocks.unpackStep(cur.absolute());
775
628
  exec.decoders = cur.seekAbs(end);
776
629
  }
777
630
 
778
- /// @notice Decode and consume one CALL block from `lane`.
631
+ /// @notice Decode and consume one CALL block from the active lane.
779
632
  /// @param exec Execution whose decoder is advanced.
780
- /// @param lane Decoder lane to consume.
781
633
  /// @return target Decoded call target.
782
634
  /// @return resources Decoded packed resources.
783
635
  /// @return data Decoded call payload.
784
- function unpackCall(
785
- Execution memory exec,
786
- uint8 lane
787
- ) internal pure returns (uint target, uint resources, bytes calldata data) {
788
- uint cur = exec.decoders.select(lane);
636
+ function unpackCall(Execution memory exec) internal pure returns (uint target, uint resources, bytes calldata data) {
637
+ uint cur = exec.decoders;
789
638
  uint abs = cur.absolute();
790
639
  uint end;
791
640
  (target, resources, data, end) = Blocks.unpackCall(abs);
792
641
  exec.decoders = cur.seekAbs(end);
793
642
  }
794
643
 
795
- /// @notice Decode and consume one ANNOTATION block from `lane`.
644
+ /// @notice Decode and consume one ANNOTATION block from the active lane.
796
645
  /// @param exec Execution whose decoder is advanced.
797
- /// @param lane Decoder lane to consume.
798
646
  /// @return entity Decoded entity identifier.
799
647
  /// @return data Decoded annotation block stream.
800
- function unpackAnnotation(
801
- Execution memory exec,
802
- uint8 lane
803
- ) internal pure returns (uint entity, bytes calldata data) {
804
- uint cur = exec.decoders.select(lane);
648
+ function unpackAnnotation(Execution memory exec) internal pure returns (uint entity, bytes calldata data) {
649
+ uint cur = exec.decoders;
805
650
  uint end;
806
651
  (entity, data, end) = Blocks.unpackAnnotation(cur.absolute());
807
652
  exec.decoders = cur.seekAbs(end);
808
653
  }
809
654
 
810
- /// @notice Decode and consume one CONTEXT block from `lane`.
655
+ /// @notice Decode and consume one CONTEXT block from the active lane.
811
656
  /// @param exec Execution whose decoder is advanced.
812
- /// @param lane Decoder lane to consume.
813
657
  /// @return account Decoded account identifier.
814
658
  /// @return state Decoded nested state.
815
659
  /// @return input Decoded nested input.
816
- function unpackContext(
817
- Execution memory exec,
818
- uint8 lane
819
- ) internal pure returns (bytes32 account, bytes calldata state, bytes calldata input) {
820
- uint cur = exec.decoders.select(lane);
660
+ function unpackContext(Execution memory exec) internal pure returns (bytes32 account, bytes calldata state, bytes calldata input) {
661
+ uint cur = exec.decoders;
821
662
  uint abs = cur.absolute();
822
663
  uint end;
823
664
  (account, state, input, end) = Blocks.unpackContext(abs);
824
665
  exec.decoders = cur.seekAbs(end);
825
666
  }
826
667
 
827
- /// @notice Decode and consume one RELAY block from `lane`.
668
+ /// @notice Decode and consume one RELAY block from the active lane.
828
669
  /// @param exec Execution whose decoder is advanced.
829
- /// @param lane Decoder lane to consume.
830
670
  /// @return portal Decoded destination portal.
831
671
  /// @return resources Decoded packed resources.
832
672
  /// @return input Decoded nested input.
833
- function unpackRelay(
834
- Execution memory exec,
835
- uint8 lane
836
- ) internal pure returns (uint portal, uint resources, bytes calldata input) {
837
- uint cur = exec.decoders.select(lane);
673
+ function unpackRelay(Execution memory exec) internal pure returns (uint portal, uint resources, bytes calldata input) {
674
+ uint cur = exec.decoders;
838
675
  uint end;
839
676
  (portal, resources, input, end) = Blocks.unpackRelay(cur.absolute());
840
677
  exec.decoders = cur.seekAbs(end);
841
678
  }
842
679
 
843
- /// @notice Decode and consume one DISPATCH block from `lane`.
680
+ /// @notice Decode and consume one DISPATCH block from the active lane.
844
681
  /// @param exec Execution whose decoder is advanced.
845
- /// @param lane Decoder lane to consume.
846
682
  /// @return portal Decoded destination portal.
847
683
  /// @return resources Decoded packed resources.
848
684
  /// @return payload Decoded dispatch payload.
849
- function unpackDispatch(
850
- Execution memory exec,
851
- uint8 lane
852
- ) internal pure returns (uint portal, uint resources, bytes calldata payload) {
853
- uint cur = exec.decoders.select(lane);
685
+ function unpackDispatch(Execution memory exec) internal pure returns (uint portal, uint resources, bytes calldata payload) {
686
+ uint cur = exec.decoders;
854
687
  uint abs = cur.absolute();
855
688
  uint end;
856
689
  (portal, resources, payload, end) = Blocks.unpackDispatch(abs);
857
690
  exec.decoders = cur.seekAbs(end);
858
691
  }
859
692
 
860
- /// @notice Decode and consume one LABEL block from `lane`.
693
+ /// @notice Decode and consume one LABEL block from the active lane.
861
694
  /// @param exec Execution whose decoder is advanced.
862
- /// @param lane Decoder lane to consume.
863
695
  /// @return namespace Decoded label namespace.
864
696
  /// @return name Decoded label text.
865
- function unpackLabel(
866
- Execution memory exec,
867
- uint8 lane
868
- ) internal pure returns (bytes32 namespace, string memory name) {
869
- uint cur = exec.decoders.select(lane);
697
+ function unpackLabel(Execution memory exec) internal pure returns (bytes32 namespace, string memory name) {
698
+ uint cur = exec.decoders;
870
699
  uint abs = cur.absolute();
871
700
  uint end;
872
701
  (namespace, name, end) = Blocks.unpackLabel(abs);
873
702
  exec.decoders = cur.seekAbs(end);
874
703
  }
875
704
 
876
- /// @notice Decode and consume one SCHEMA block from `lane`.
705
+ /// @notice Decode and consume one SCHEMA block from the active lane.
877
706
  /// @param exec Execution whose decoder is advanced.
878
- /// @param lane Decoder lane to consume.
879
707
  /// @return spec Decoded block specification.
880
708
  /// @return body Decoded schema body.
881
709
  /// @return name Decoded schema name.
882
- function unpackSchema(
883
- Execution memory exec,
884
- uint8 lane
885
- ) internal pure returns (uint spec, string memory body, bytes32 name) {
886
- uint cur = exec.decoders.select(lane);
710
+ function unpackSchema(Execution memory exec) internal pure returns (uint spec, string memory body, bytes32 name) {
711
+ uint cur = exec.decoders;
887
712
  uint abs = cur.absolute();
888
713
  uint end;
889
714
  (spec, body, name, end) = Blocks.unpackSchema(abs);
890
715
  exec.decoders = cur.seekAbs(end);
891
716
  }
892
717
 
893
- /// @notice Decode and consume one RECOVER block from `lane`.
718
+ /// @notice Decode and consume one RECOVER block from the active lane.
894
719
  /// @param exec Execution whose decoder is advanced.
895
- /// @param lane Decoder lane to consume.
896
720
  /// @return handler Decoded recovery handler.
897
721
  /// @return resources Decoded packed resources.
898
722
  /// @return key Decoded recovery key.
899
723
  /// @return witness Decoded recovery witness.
900
- function unpackRecover(
901
- Execution memory exec,
902
- uint8 lane
903
- ) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness) {
904
- uint cur = exec.decoders.select(lane);
724
+ function unpackRecover(Execution memory exec) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness) {
725
+ uint cur = exec.decoders;
905
726
  uint abs = cur.absolute();
906
727
  uint end;
907
728
  (handler, resources, key, witness, end) = Blocks.unpackRecover(abs);
@@ -918,8 +739,7 @@ library Executions {
918
739
  /// @param touch Number of bytes that must be addressable by the write.
919
740
  /// @return i Relative output offset reserved for the write.
920
741
  function reserve(Execution memory exec, uint amount, uint touch) internal pure returns (uint i) {
921
- uint writers = exec.writers.select(Lanes.Output);
922
- (exec.writers, exec.output, i) = Buffers.reserve(writers, exec.output, amount, touch);
742
+ (exec.writer, exec.output, i) = Buffers.reserve(exec.writer, exec.output, amount, touch);
923
743
  }
924
744
 
925
745
  /// @dev Reserve an exact number of output bytes.
@@ -927,7 +747,7 @@ library Executions {
927
747
  /// @param size Number of bytes to reserve and touch.
928
748
  /// @return i Relative output offset reserved for the write.
929
749
  function reserve(Execution memory exec, uint size) private pure returns (uint i) {
930
- return reserve(exec, size, size);
750
+ (exec.writer, exec.output, i) = Buffers.reserve(exec.writer, exec.output, size, size);
931
751
  }
932
752
 
933
753
  /// @notice Append an empty block to execution output.
@@ -1210,12 +1030,12 @@ library Executions {
1210
1030
  /// @notice Append a STEP block to execution output.
1211
1031
  /// @param exec Execution receiving the block.
1212
1032
  /// @param cmd Command identifier to encode.
1213
- /// @param resources Packed resources to encode.
1033
+ /// @param value Native value to encode.
1214
1034
  /// @param input Command input to encode.
1215
- function outputStep(Execution memory exec, uint cmd, uint resources, bytes memory input) internal pure {
1216
- uint size = Sizes.B64 + Sizes.Header + input.length;
1035
+ function outputStep(Execution memory exec, uint cmd, uint128 value, bytes memory input) internal pure {
1036
+ uint size = Sizes.Step + input.length;
1217
1037
  uint i = reserve(exec, size);
1218
- Blocks.writeStep(exec.output, i, cmd, resources, input);
1038
+ Blocks.writeStep(exec.output, i, cmd, value, input);
1219
1039
  }
1220
1040
 
1221
1041
  /// @notice Append a CALL block to execution output.
@@ -1347,10 +1167,10 @@ library Executions {
1347
1167
  }
1348
1168
 
1349
1169
  /// @notice Append a STEP block to execution output by copying its nested input from calldata.
1350
- function outputCopyStep(Execution memory exec, uint cmd, uint resources, bytes calldata input) internal pure {
1351
- uint size = Sizes.B64 + Sizes.Header + input.length;
1170
+ function outputCopyStep(Execution memory exec, uint cmd, uint128 value, bytes calldata input) internal pure {
1171
+ uint size = Sizes.Step + input.length;
1352
1172
  uint i = reserve(exec, size);
1353
- Blocks.copyStep(exec.output, i, cmd, resources, input);
1173
+ Blocks.copyStep(exec.output, i, cmd, value, input);
1354
1174
  }
1355
1175
 
1356
1176
  /// @notice Append a CALL block to execution output by copying its nested payload from calldata.
@@ -1400,16 +1220,23 @@ library Executions {
1400
1220
  }
1401
1221
 
1402
1222
  // -------------------------------------------------------------------------
1403
- // Value and transaction writing
1223
+ // Value
1404
1224
  // -------------------------------------------------------------------------
1405
1225
 
1226
+ /// @notice Remove and return the remaining execution value budget.
1227
+ /// @param exec Execution whose budget is drained.
1228
+ /// @return budget Native value removed from the execution.
1229
+ function drainBudget(Execution memory exec) internal pure returns (uint budget) {
1230
+ budget = exec.budget;
1231
+ exec.budget = 0;
1232
+ }
1233
+
1406
1234
  /// @notice Transfer the remaining value budget out of an execution.
1407
1235
  /// @dev Clears `exec.budget` so the returned budget becomes its sole owner.
1408
1236
  /// @param exec Execution whose budget is detached.
1409
1237
  /// @return budget Detached budget containing the remaining value.
1410
1238
  function takeBudget(Execution memory exec) internal pure returns (Budget memory budget) {
1411
- budget.remaining = exec.budget;
1412
- exec.budget = 0;
1239
+ budget.remaining = drainBudget(exec);
1413
1240
  }
1414
1241
 
1415
1242
  /// @notice Deduct an exact native value from the execution budget.
@@ -1431,63 +1258,6 @@ library Executions {
1431
1258
  return uint128(useValue(exec, uint128(resources)));
1432
1259
  }
1433
1260
 
1434
- /// @notice Append a deferred transaction to the transaction writer lane.
1435
- /// @param exec Execution receiving the transaction.
1436
- /// @param from Debit account identifier.
1437
- /// @param to Credit account identifier.
1438
- /// @param asset Asset identifier.
1439
- /// @param amount Transaction amount.
1440
- function queueTransaction(
1441
- Execution memory exec,
1442
- bytes32 from,
1443
- bytes32 to,
1444
- bytes32 asset,
1445
- uint amount
1446
- ) internal pure {
1447
- uint i;
1448
- uint size = Sizes.Transaction;
1449
- uint writers = exec.writers.select(Lanes.Transactions);
1450
- (exec.writers, exec.transactions, i) = Buffers.reserve(writers, exec.transactions, size, size);
1451
- Blocks.writeTransaction(exec.transactions, i, from, to, asset, amount);
1452
- }
1453
-
1454
- /// @notice Queue a transaction that debits `account`.
1455
- /// @param exec Execution receiving the transaction.
1456
- /// @param account Account to debit.
1457
- /// @param asset Asset to debit.
1458
- /// @param amount Amount to debit.
1459
- function queueDebit(Execution memory exec, bytes32 account, bytes32 asset, uint amount) internal pure {
1460
- queueTransaction(exec, account, bytes32(0), asset, amount);
1461
- }
1462
-
1463
- /// @notice Queue a transaction that credits `account`.
1464
- /// @param exec Execution receiving the transaction.
1465
- /// @param account Account to credit.
1466
- /// @param asset Asset to credit.
1467
- /// @param amount Amount to credit.
1468
- function queueCredit(Execution memory exec, bytes32 account, bytes32 asset, uint amount) internal pure {
1469
- queueTransaction(exec, bytes32(0), account, asset, amount);
1470
- }
1471
-
1472
- /// @notice Drain the remaining value budget and queue it as an account refund.
1473
- /// @dev Creates a one-transaction writer lane when the descriptor declared none.
1474
- /// @param exec Execution whose remaining budget is refunded.
1475
- /// @param account Account receiving the refund.
1476
- /// @param asset Asset identifier used for the refund transaction.
1477
- /// @return amount Value removed from the execution budget and queued for refund.
1478
- function refundValue(Execution memory exec, bytes32 account, bytes32 asset) internal pure returns (uint amount) {
1479
- amount = exec.budget;
1480
- if (amount == 0) return 0;
1481
-
1482
- exec.budget = 0;
1483
- if (!exec.writers.contains(Lanes.Transactions)) {
1484
- uint refunds = Buffers.cursor(Sizes.Transaction, 1, false, Lanes.Transactions);
1485
- exec.writers = Cursors.pair(exec.writers, refunds);
1486
- }
1487
-
1488
- queueCredit(exec, account, asset, amount);
1489
- }
1490
-
1491
1261
  // -------------------------------------------------------------------------
1492
1262
  // Finalization
1493
1263
  // -------------------------------------------------------------------------
@@ -1496,19 +1266,32 @@ library Executions {
1496
1266
  /// @param exec Execution whose output is finalized.
1497
1267
  /// @return out Trimmed output bytes.
1498
1268
  function finish(Execution memory exec) internal pure returns (bytes memory out) {
1269
+ if (exec.decoders.any()) revert UnconsumedData();
1499
1270
  if (exec.output.length == 0) return new bytes(0);
1500
1271
 
1501
- uint writers = exec.writers.select(Lanes.Output);
1502
- out = Buffers.finish(writers, exec.output);
1272
+ out = Buffers.finish(exec.writer, exec.output);
1503
1273
  }
1504
1274
 
1505
- /// @notice Finalize and return queued execution transactions.
1506
- /// @param exec Execution whose transactions are finalized.
1507
- /// @return out Trimmed transaction bytes.
1508
- function finishTransactions(Execution memory exec) internal pure returns (bytes memory out) {
1509
- if (exec.transactions.length == 0) return new bytes(0);
1275
+ /// @notice Close an execution and return its output and remaining budget.
1276
+ /// @param exec Execution whose lanes, writer, and budget are finalized.
1277
+ /// @return output Final encoded output block stream.
1278
+ /// @return credit Remaining native value to credit to the caller's budget.
1279
+ function close(Execution memory exec) internal pure returns (bytes memory output, uint credit) {
1280
+ return close(exec, 0);
1281
+ }
1510
1282
 
1511
- uint writers = exec.writers.select(Lanes.Transactions);
1512
- out = Buffers.finish(writers, exec.transactions);
1283
+ /// @notice Close an execution and combine its remaining budget with additional command credit.
1284
+ /// @param exec Execution whose lanes, writer, and budget are finalized.
1285
+ /// @param extraCredit Additional trusted credit produced by the command.
1286
+ /// @return output Final encoded output block stream.
1287
+ /// @return credit Remaining execution budget plus `extraCredit`.
1288
+ function close(
1289
+ Execution memory exec,
1290
+ uint extraCredit
1291
+ ) internal pure returns (bytes memory output, uint credit) {
1292
+ output = finish(exec);
1293
+ credit = exec.budget + extraCredit;
1294
+ exec.budget = 0;
1513
1295
  }
1296
+
1514
1297
  }