@rootzero/contracts 1.12.0 → 1.14.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 (76) hide show
  1. package/CHANGELOG.md +76 -8
  2. package/Codec.sol +21 -0
  3. package/Commands.sol +14 -0
  4. package/Core.sol +4 -4
  5. package/Endpoints.sol +5 -7
  6. package/README.md +62 -35
  7. package/Utils.sol +2 -4
  8. package/codec/Blocks.sol +1606 -0
  9. package/codec/Buffers.sol +165 -0
  10. package/codec/Decoders.sol +558 -0
  11. package/codec/Descriptors.sol +124 -0
  12. package/{blocks → codec}/Keys.sol +4 -28
  13. package/codec/Readers.sol +114 -0
  14. package/{blocks → codec}/Schema.sol +38 -80
  15. package/codec/Specs.sol +218 -0
  16. package/codec/Writers.sol +487 -0
  17. package/commands/Allocate.sol +50 -0
  18. package/commands/Base.sol +71 -37
  19. package/commands/Burn.sol +19 -13
  20. package/commands/Credit.sol +25 -31
  21. package/commands/Debit.sol +28 -38
  22. package/commands/Deposit.sol +39 -39
  23. package/commands/Payout.sol +22 -15
  24. package/commands/Provision.sol +40 -40
  25. package/commands/Recover.sol +21 -20
  26. package/commands/Relay.sol +25 -23
  27. package/commands/Withdraw.sol +18 -20
  28. package/commands/admin/AllowAssets.sol +20 -16
  29. package/commands/admin/Allowance.sol +19 -13
  30. package/commands/admin/Appoint.sol +18 -15
  31. package/commands/admin/Authorize.sol +24 -14
  32. package/commands/admin/Base.sol +1 -1
  33. package/commands/admin/DenyAssets.sol +20 -16
  34. package/commands/admin/Dismiss.sol +18 -15
  35. package/commands/admin/Execute.sol +20 -18
  36. package/commands/admin/Label.sol +18 -13
  37. package/commands/admin/Schemas.sol +19 -14
  38. package/commands/admin/Unauthorize.sol +24 -14
  39. package/core/Calls.sol +7 -14
  40. package/core/Endpoint.sol +43 -126
  41. package/core/Host.sol +10 -2
  42. package/core/Pipeline.sol +29 -25
  43. package/core/Settlement.sol +39 -0
  44. package/core/Types.sol +1 -1
  45. package/docs/Schema.md +38 -32
  46. package/events/Endpoint.sol +2 -2
  47. package/events/Introduction.sol +4 -3
  48. package/events/Schema.sol +5 -5
  49. package/execution/Budget.sol +40 -0
  50. package/execution/Execution.sol +1083 -0
  51. package/guards/Base.sol +8 -9
  52. package/guards/Revoke.sol +11 -9
  53. package/package.json +1 -1
  54. package/ports/AllowAssets.sol +12 -15
  55. package/ports/Allowance.sol +11 -9
  56. package/ports/Base.sol +18 -11
  57. package/ports/Credit.sol +11 -9
  58. package/ports/Debit.sol +11 -9
  59. package/ports/DenyAssets.sol +10 -13
  60. package/ports/Dispatch.sol +13 -15
  61. package/ports/Pipe.sol +14 -12
  62. package/ports/Redeem.sol +12 -9
  63. package/ports/Settle.sol +13 -13
  64. package/queries/Assets.sol +15 -15
  65. package/queries/Balances.sol +17 -17
  66. package/queries/Base.sol +11 -12
  67. package/utils/Actions.sol +1 -0
  68. package/utils/Cursors.sol +308 -0
  69. package/utils/Lanes.sol +14 -0
  70. package/utils/Selectors.sol +2 -2
  71. package/utils/Utils.sol +46 -0
  72. package/Cursors.sol +0 -16
  73. package/blocks/Cursors.sol +0 -1400
  74. package/blocks/Writers.sol +0 -1028
  75. package/core/Payable.sol +0 -53
  76. package/utils/Value.sol +0 -43
@@ -0,0 +1,1083 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, Tx} from "../core/Types.sol";
5
+ import {Blocks} from "../codec/Blocks.sol";
6
+ import {Buffers} from "../codec/Buffers.sol";
7
+ import {Sizes, Specs} from "../codec/Specs.sol";
8
+ import {Descriptors} from "../codec/Descriptors.sol";
9
+ import {Cursors, Cur} from "../utils/Cursors.sol";
10
+ import {Lanes} from "../utils/Lanes.sol";
11
+ import {Budget} from "./Budget.sol";
12
+
13
+ /// @notice Mutable state shared across one endpoint execution.
14
+ /// @dev `decoders` contains tagged input and state cursor lanes. Cursor operations
15
+ /// select one logical lane by swapping it into the lower 128 bits.
16
+ struct Execution {
17
+ uint budget;
18
+ uint decoders;
19
+ uint writers;
20
+ bytes transactions;
21
+ bytes output;
22
+ }
23
+
24
+ /// @title Executions
25
+ /// @notice Opening, decoding, output, transaction, and value helpers for executions.
26
+ library Executions {
27
+ using Cursors for uint;
28
+
29
+ /// @dev Thrown when an execution attempts to spend more value than remains in its budget.
30
+ error InsufficientValue();
31
+
32
+ // -------------------------------------------------------------------------
33
+ // Opening
34
+ // -------------------------------------------------------------------------
35
+
36
+ /// @dev A lane with stride zero accepts only an empty source and returns the zero cursor.
37
+ /// @param source Calldata source for the decoder lane.
38
+ /// @param descriptor Packed endpoint descriptor.
39
+ /// @param lane Input or state lane identifier.
40
+ /// @return cur Tagged packed decoder cursor, or zero for an absent lane.
41
+ function openDecoder(bytes calldata source, uint descriptor, uint8 lane) private pure returns (uint cur) {
42
+ uint stride = Descriptors.stride(descriptor, lane);
43
+ (uint abs, uint limit) = Cursors.bounds(source);
44
+ if (stride == 0 && abs == limit) return 0;
45
+
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);
49
+ }
50
+
51
+ /// @dev Initialize one tagged writer cursor from a descriptor lane.
52
+ /// @param descriptor Packed endpoint descriptor.
53
+ /// @param batches Reconciled execution batch count.
54
+ /// @param lane Output or transaction lane identifier.
55
+ /// @param padding Additional logical capacity reserved for the lane.
56
+ /// @return cur Tagged packed writer cursor, or zero for an absent lane.
57
+ function initWriter(uint descriptor, uint batches, uint8 lane, uint padding) private pure returns (uint cur) {
58
+ (uint capacity, bool growable) = Descriptors.allocation(descriptor, lane, batches);
59
+ if (capacity == 0) return 0;
60
+
61
+ cur = Buffers.cursor(capacity + padding, batches, growable, lane);
62
+ }
63
+
64
+ /// @dev Open and pair the input and state decoder cursors.
65
+ /// @param state State calldata source.
66
+ /// @param input Input calldata source.
67
+ /// @param descriptor Packed endpoint descriptor.
68
+ /// @return Paired decoder cursors.
69
+ function decodeCursors(bytes calldata state, bytes calldata input, uint descriptor) private pure returns (uint) {
70
+ return
71
+ Cursors.pair(openDecoder(input, descriptor, Lanes.Input), openDecoder(state, descriptor, Lanes.State));
72
+ }
73
+
74
+ /// @dev Initialize and pair the output and transaction writer cursors.
75
+ /// @param descriptor Packed endpoint descriptor.
76
+ /// @param batches Reconciled execution batch count.
77
+ /// @return Paired writer cursors.
78
+ function writerCursors(uint descriptor, uint batches) private pure returns (uint) {
79
+ return
80
+ Cursors.pair(
81
+ initWriter(descriptor, batches, Lanes.Output, 0),
82
+ initWriter(descriptor, batches, Lanes.Transactions, Sizes.Transaction)
83
+ );
84
+ }
85
+
86
+ /// @dev Complete execution initialization from pre-opened decoder cursors.
87
+ /// @param decoders Packed decoder cursor or pair.
88
+ /// @param descriptor Packed endpoint descriptor.
89
+ /// @param batches Expected batch count; zero derives it from the decoders.
90
+ /// @return exec Initialized execution.
91
+ function open(uint decoders, uint descriptor, uint batches) private view returns (Execution memory exec) {
92
+ exec.budget = msg.value;
93
+ exec.decoders = decoders;
94
+ batches = Cursors.reconcile(decoders, batches);
95
+ exec.writers = writerCursors(descriptor, batches);
96
+ }
97
+
98
+ /// @notice Open an execution containing only the current call-value budget.
99
+ /// @dev Decoders, writers, output, and transactions remain empty.
100
+ /// @return exec Budget-only execution initialized with `msg.value`.
101
+ function open() internal view returns (Execution memory exec) {
102
+ exec.budget = msg.value;
103
+ }
104
+
105
+ /// @notice Open an execution with an input decoder and descriptor writers.
106
+ /// @param input Input block stream.
107
+ /// @param descriptor Packed endpoint descriptor.
108
+ /// @param batches Expected batch count; zero derives it from the input run.
109
+ /// @return exec Initialized execution.
110
+ function openInput(
111
+ bytes calldata input,
112
+ uint descriptor,
113
+ uint batches
114
+ ) internal view returns (Execution memory exec) {
115
+ return open(openDecoder(input, descriptor, Lanes.Input), descriptor, batches);
116
+ }
117
+
118
+ /// @notice Open an execution with a state decoder and descriptor writers.
119
+ /// @param state State block stream.
120
+ /// @param descriptor Packed endpoint descriptor.
121
+ /// @param batches Expected batch count; zero derives it from the state run.
122
+ /// @return exec Initialized execution.
123
+ function openState(
124
+ bytes calldata state,
125
+ uint descriptor,
126
+ uint batches
127
+ ) internal view returns (Execution memory exec) {
128
+ return open(openDecoder(state, descriptor, Lanes.State), descriptor, batches);
129
+ }
130
+
131
+ /// @notice Open an execution with paired state and input decoders.
132
+ /// @param state State block stream.
133
+ /// @param input Input block stream.
134
+ /// @param descriptor Packed endpoint descriptor.
135
+ /// @param batches Expected batch count; zero derives it from the decoder runs.
136
+ /// @return exec Initialized execution.
137
+ function open(
138
+ bytes calldata state,
139
+ bytes calldata input,
140
+ uint descriptor,
141
+ uint batches
142
+ ) internal view returns (Execution memory exec) {
143
+ return open(decodeCursors(state, input, descriptor), descriptor, batches);
144
+ }
145
+
146
+ // -------------------------------------------------------------------------
147
+ // Traversal
148
+ // -------------------------------------------------------------------------
149
+
150
+ /// @notice Return whether either execution decoder lane has blocks remaining.
151
+ /// @param exec Execution to inspect.
152
+ /// @return Whether either decoder lane has unread bytes.
153
+ function more(Execution memory exec) internal pure returns (bool) {
154
+ return exec.decoders.any();
155
+ }
156
+
157
+ /// @notice Validate and consume the next block from an execution decoder lane.
158
+ /// @param exec Execution whose selected decoder cursor is advanced over the complete block.
159
+ /// @param lane Execution decoder lane to select.
160
+ /// @param spec Expected block specification.
161
+ /// @return abs Absolute position of the first payload byte.
162
+ /// @return end Absolute position immediately after the payload.
163
+ function consume(Execution memory exec, uint8 lane, uint spec) internal pure returns (uint abs, uint end) {
164
+ uint cur = exec.decoders.select(lane);
165
+ (abs, end) = Blocks.expect(cur.absolute(), spec);
166
+ exec.decoders = cur.seekAbs(end);
167
+ }
168
+
169
+ /// @notice Consume a LIST block and return a cursor scoped to its payload.
170
+ /// @param exec Execution whose decoder is advanced.
171
+ /// @param lane Decoder lane containing the LIST block.
172
+ /// @return items Cursor over the nested list items.
173
+ function list(Execution memory exec, uint8 lane) internal pure returns (Cur memory items) {
174
+ (uint abs, uint end) = consume(exec, lane, Specs.List);
175
+ items.state = Cursors.create(abs, end - abs, 0, 0, 0);
176
+ }
177
+
178
+ // -------------------------------------------------------------------------
179
+ // Fixed-width block decoding
180
+ // -------------------------------------------------------------------------
181
+
182
+ /// @notice Decode one fixed 32-byte payload from `lane`.
183
+ /// @param exec Execution whose decoder is advanced.
184
+ /// @param lane Decoder lane to consume.
185
+ /// @param spec Expected fixed block specification.
186
+ /// @return value Decoded payload word.
187
+ function unpack32(Execution memory exec, uint8 lane, uint spec) internal pure returns (bytes32 value) {
188
+ uint abs;
189
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B32);
190
+ if (Blocks.header(abs, Specs.key(spec)) != 32) revert Blocks.InvalidBlock();
191
+ assembly ("memory-safe") {
192
+ value := calldataload(add(abs, 0x08))
193
+ }
194
+ }
195
+
196
+ /// @notice Decode and consume one ACCOUNT block from `lane`.
197
+ /// @param exec Execution whose decoder is advanced.
198
+ /// @param lane Decoder lane to consume.
199
+ /// @return account Decoded account identifier.
200
+ function unpackAccount(Execution memory exec, uint8 lane) internal pure returns (bytes32 account) {
201
+ uint abs;
202
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B32);
203
+ account = Blocks.unpackAccount(abs);
204
+ }
205
+
206
+ /// @notice Decode and consume one NODE block from `lane`.
207
+ /// @param exec Execution whose decoder is advanced.
208
+ /// @param lane Decoder lane to consume.
209
+ /// @return node Decoded node identifier.
210
+ function unpackNode(Execution memory exec, uint8 lane) internal pure returns (uint node) {
211
+ uint abs;
212
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B32);
213
+ node = Blocks.unpackNode(abs);
214
+ }
215
+
216
+ /// @notice Decode and consume one ASSET block from `lane`.
217
+ /// @param exec Execution whose decoder is advanced.
218
+ /// @param lane Decoder lane to consume.
219
+ /// @return asset Decoded asset identifier.
220
+ function unpackAsset(Execution memory exec, uint8 lane) internal pure returns (bytes32 asset) {
221
+ uint abs;
222
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B32);
223
+ asset = Blocks.unpackAsset(abs);
224
+ }
225
+
226
+ /// @notice Decode and consume one ACCOUNT_ASSET block from `lane`.
227
+ /// @param exec Execution whose decoder is advanced.
228
+ /// @param lane Decoder lane to consume.
229
+ /// @return account Decoded account identifier.
230
+ /// @return asset Decoded asset identifier.
231
+ function unpackAccountAsset(
232
+ Execution memory exec,
233
+ uint8 lane
234
+ ) internal pure returns (bytes32 account, bytes32 asset) {
235
+ uint abs;
236
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B64);
237
+ (account, asset) = Blocks.unpackAccountAsset(abs);
238
+ }
239
+
240
+ /// @notice Decode one ACCOUNT_ASSET block into its structured value.
241
+ /// @param exec Execution whose decoder is advanced.
242
+ /// @param lane Decoder lane to consume.
243
+ /// @return value Decoded account and asset.
244
+ function unpackAccountAssetValue(
245
+ Execution memory exec,
246
+ uint8 lane
247
+ ) internal pure returns (AccountAsset memory value) {
248
+ (value.account, value.asset) = unpackAccountAsset(exec, lane);
249
+ }
250
+
251
+ /// @notice Decode and consume one AMOUNT block from `lane`.
252
+ /// @param exec Execution whose decoder is advanced.
253
+ /// @param lane Decoder lane to consume.
254
+ /// @return asset Decoded asset identifier.
255
+ /// @return amount Decoded amount.
256
+ function unpackAmount(Execution memory exec, uint8 lane) internal pure returns (bytes32 asset, uint amount) {
257
+ uint abs;
258
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Amount);
259
+ (asset, amount) = Blocks.unpackAmount(abs);
260
+ }
261
+
262
+ /// @notice Decode one AMOUNT block into its structured value.
263
+ /// @param exec Execution whose decoder is advanced.
264
+ /// @param lane Decoder lane to consume.
265
+ /// @return value Decoded asset and amount.
266
+ function unpackAmountValue(Execution memory exec, uint8 lane) internal pure returns (AssetAmount memory value) {
267
+ (value.asset, value.amount) = unpackAmount(exec, lane);
268
+ }
269
+
270
+ /// @notice Decode and consume one BALANCE block from `lane`.
271
+ /// @param exec Execution whose decoder is advanced.
272
+ /// @param lane Decoder lane to consume.
273
+ /// @return asset Decoded asset identifier.
274
+ /// @return amount Decoded balance amount.
275
+ function unpackBalance(Execution memory exec, uint8 lane) internal pure returns (bytes32 asset, uint amount) {
276
+ uint abs;
277
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Balance);
278
+ (asset, amount) = Blocks.unpackBalance(abs);
279
+ }
280
+
281
+ /// @notice Decode one BALANCE block into its structured value.
282
+ /// @param exec Execution whose decoder is advanced.
283
+ /// @param lane Decoder lane to consume.
284
+ /// @return value Decoded asset and balance amount.
285
+ function unpackBalanceValue(Execution memory exec, uint8 lane) internal pure returns (AssetAmount memory value) {
286
+ (value.asset, value.amount) = unpackBalance(exec, lane);
287
+ }
288
+
289
+ /// @notice Decode one BALANCE block and associate it with `host`.
290
+ /// @param exec Execution whose decoder is advanced.
291
+ /// @param lane Decoder lane to consume.
292
+ /// @param host Host associated with the decoded balance.
293
+ /// @return value Host-scoped asset amount.
294
+ function unpackBalanceForHost(
295
+ Execution memory exec,
296
+ uint8 lane,
297
+ uint host
298
+ ) internal pure returns (HostAmount memory value) {
299
+ uint abs;
300
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Balance);
301
+ value.host = host;
302
+ (value.asset, value.amount) = Blocks.unpackBalance(abs);
303
+ }
304
+
305
+ /// @notice Decode and consume one ACCOUNT_AMOUNT block from `lane`.
306
+ /// @param exec Execution whose decoder is advanced.
307
+ /// @param lane Decoder lane to consume.
308
+ /// @return account Decoded account identifier.
309
+ /// @return asset Decoded asset identifier.
310
+ /// @return amount Decoded amount.
311
+ function unpackAccountAmount(
312
+ Execution memory exec,
313
+ uint8 lane
314
+ ) internal pure returns (bytes32 account, bytes32 asset, uint amount) {
315
+ uint abs;
316
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
317
+ (account, asset, amount) = Blocks.unpackAccountAmount(abs);
318
+ }
319
+
320
+ /// @notice Decode one ACCOUNT_AMOUNT block into its structured value.
321
+ /// @param exec Execution whose decoder is advanced.
322
+ /// @param lane Decoder lane to consume.
323
+ /// @return value Decoded account, asset, and amount.
324
+ function unpackAccountAmountValue(
325
+ Execution memory exec,
326
+ uint8 lane
327
+ ) internal pure returns (AccountAmount memory value) {
328
+ (value.account, value.asset, value.amount) = unpackAccountAmount(exec, lane);
329
+ }
330
+
331
+ /// @notice Decode and consume one ALLOCATION block from `lane`.
332
+ /// @param exec Execution whose decoder is advanced.
333
+ /// @param lane Decoder lane to consume.
334
+ /// @return host Decoded host identifier.
335
+ /// @return asset Decoded asset identifier.
336
+ /// @return amount Decoded amount.
337
+ function unpackAllocation(
338
+ Execution memory exec,
339
+ uint8 lane
340
+ ) internal pure returns (uint host, bytes32 asset, uint amount) {
341
+ uint abs;
342
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
343
+ (host, asset, amount) = Blocks.unpackAllocation(abs);
344
+ }
345
+
346
+ /// @notice Decode one ALLOCATION block into its structured value.
347
+ /// @param exec Execution whose decoder is advanced.
348
+ /// @param lane Decoder lane to consume.
349
+ /// @return value Decoded host, asset, and amount.
350
+ function unpackAllocationValue(Execution memory exec, uint8 lane) internal pure returns (HostAmount memory value) {
351
+ (value.host, value.asset, value.amount) = unpackAllocation(exec, lane);
352
+ }
353
+
354
+ /// @notice Decode and consume one ALLOWANCE block from `lane`.
355
+ /// @param exec Execution whose decoder is advanced.
356
+ /// @param lane Decoder lane to consume.
357
+ /// @return host Decoded host identifier.
358
+ /// @return asset Decoded asset identifier.
359
+ /// @return amount Decoded allowance amount.
360
+ function unpackAllowance(
361
+ Execution memory exec,
362
+ uint8 lane
363
+ ) internal pure returns (uint host, bytes32 asset, uint amount) {
364
+ uint abs;
365
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
366
+ (host, asset, amount) = Blocks.unpackAllowance(abs);
367
+ }
368
+
369
+ /// @notice Decode one ALLOWANCE block into its structured value.
370
+ /// @param exec Execution whose decoder is advanced.
371
+ /// @param lane Decoder lane to consume.
372
+ /// @return value Decoded host, asset, and allowance amount.
373
+ function unpackAllowanceValue(Execution memory exec, uint8 lane) internal pure returns (HostAmount memory value) {
374
+ (value.host, value.asset, value.amount) = unpackAllowance(exec, lane);
375
+ }
376
+
377
+ /// @notice Decode and consume one CUSTODY block from `lane`.
378
+ /// @param exec Execution whose decoder is advanced.
379
+ /// @param lane Decoder lane to consume.
380
+ /// @return host Decoded host identifier.
381
+ /// @return asset Decoded asset identifier.
382
+ /// @return amount Decoded custody amount.
383
+ function unpackCustody(
384
+ Execution memory exec,
385
+ uint8 lane
386
+ ) internal pure returns (uint host, bytes32 asset, uint amount) {
387
+ uint abs;
388
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
389
+ (host, asset, amount) = Blocks.unpackCustody(abs);
390
+ }
391
+
392
+ /// @notice Decode one CUSTODY block into its structured value.
393
+ /// @param exec Execution whose decoder is advanced.
394
+ /// @param lane Decoder lane to consume.
395
+ /// @return value Decoded host, asset, and custody amount.
396
+ function unpackCustodyValue(Execution memory exec, uint8 lane) internal pure returns (HostAmount memory value) {
397
+ (value.host, value.asset, value.amount) = unpackCustody(exec, lane);
398
+ }
399
+
400
+ /// @notice Decode and consume one HOST_ACCOUNT_ASSET block from `lane`.
401
+ /// @param exec Execution whose decoder is advanced.
402
+ /// @param lane Decoder lane to consume.
403
+ /// @return host Decoded host identifier.
404
+ /// @return account Decoded account identifier.
405
+ /// @return asset Decoded asset identifier.
406
+ function unpackHostAccountAsset(
407
+ Execution memory exec,
408
+ uint8 lane
409
+ ) internal pure returns (uint host, bytes32 account, bytes32 asset) {
410
+ uint abs;
411
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.B96);
412
+ (host, account, asset) = Blocks.unpackHostAccountAsset(abs);
413
+ }
414
+
415
+ /// @notice Decode one HOST_ACCOUNT_ASSET block into its structured value.
416
+ /// @param exec Execution whose decoder is advanced.
417
+ /// @param lane Decoder lane to consume.
418
+ /// @return value Decoded host, account, and asset.
419
+ function unpackHostAccountAssetValue(
420
+ Execution memory exec,
421
+ uint8 lane
422
+ ) internal pure returns (HostAccountAsset memory value) {
423
+ (value.host, value.account, value.asset) = unpackHostAccountAsset(exec, lane);
424
+ }
425
+
426
+ /// @notice Decode and consume one TRANSACTION block from `lane`.
427
+ /// @param exec Execution whose decoder is advanced.
428
+ /// @param lane Decoder lane to consume.
429
+ /// @return from Decoded debit account.
430
+ /// @return to Decoded credit account.
431
+ /// @return asset Decoded asset identifier.
432
+ /// @return amount Decoded transaction amount.
433
+ function unpackTransaction(
434
+ Execution memory exec,
435
+ uint8 lane
436
+ ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
437
+ uint abs;
438
+ (exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Transaction);
439
+ (from, to, asset, amount) = Blocks.unpackTransaction(abs);
440
+ }
441
+
442
+ /// @notice Decode one TRANSACTION block into its structured value.
443
+ /// @param exec Execution whose decoder is advanced.
444
+ /// @param lane Decoder lane to consume.
445
+ /// @return value Decoded transaction.
446
+ function unpackTransactionValue(Execution memory exec, uint8 lane) internal pure returns (Tx memory value) {
447
+ (value.from, value.to, value.asset, value.amount) = unpackTransaction(exec, lane);
448
+ }
449
+
450
+ // -------------------------------------------------------------------------
451
+ // Dynamic block decoding
452
+ // -------------------------------------------------------------------------
453
+
454
+ /// @notice Decode and consume a block described by `spec` from `lane`.
455
+ /// @param exec Execution whose decoder is advanced.
456
+ /// @param lane Decoder lane to consume.
457
+ /// @param spec Expected block specification.
458
+ /// @return data Calldata view of the decoded payload.
459
+ function unpackRaw(Execution memory exec, uint8 lane, uint spec) internal pure returns (bytes calldata data) {
460
+ uint cur = exec.decoders.select(lane);
461
+ uint end;
462
+ (data, end) = Blocks.unpackRaw(cur.absolute(), spec);
463
+ exec.decoders = cur.seekAbs(end);
464
+ }
465
+
466
+ /// @notice Decode and consume one BYTES block from `lane`.
467
+ /// @param exec Execution whose decoder is advanced.
468
+ /// @param lane Decoder lane to consume.
469
+ /// @return data Decoded byte payload.
470
+ function unpackBytes(Execution memory exec, uint8 lane) internal pure returns (bytes calldata data) {
471
+ uint cur = exec.decoders.select(lane);
472
+ uint end;
473
+ (data, end) = Blocks.unpackBytes(cur.absolute());
474
+ exec.decoders = cur.seekAbs(end);
475
+ }
476
+
477
+ /// @notice Decode and consume one STRING block from `lane`.
478
+ /// @param exec Execution whose decoder is advanced.
479
+ /// @param lane Decoder lane to consume.
480
+ /// @return data Decoded string payload.
481
+ function unpackString(Execution memory exec, uint8 lane) internal pure returns (string memory data) {
482
+ uint cur = exec.decoders.select(lane);
483
+ bytes calldata value;
484
+ uint end;
485
+ (value, end) = Blocks.unpackString(cur.absolute());
486
+ exec.decoders = cur.seekAbs(end);
487
+ data = string(value);
488
+ }
489
+
490
+ /// @notice Decode and consume one STEP block from `lane`.
491
+ /// @param exec Execution whose decoder is advanced.
492
+ /// @param lane Decoder lane to consume.
493
+ /// @return cmd Decoded command identifier.
494
+ /// @return resources Decoded packed resources.
495
+ /// @return input Decoded nested input.
496
+ function unpackStep(
497
+ Execution memory exec,
498
+ uint8 lane
499
+ ) internal pure returns (uint cmd, uint resources, bytes calldata input) {
500
+ uint cur = exec.decoders.select(lane);
501
+ uint end;
502
+ (cmd, resources, input, end) = Blocks.unpackStep(cur.absolute());
503
+ exec.decoders = cur.seekAbs(end);
504
+ }
505
+
506
+ /// @notice Decode and consume one CALL block from `lane`.
507
+ /// @param exec Execution whose decoder is advanced.
508
+ /// @param lane Decoder lane to consume.
509
+ /// @return target Decoded call target.
510
+ /// @return resources Decoded packed resources.
511
+ /// @return data Decoded call payload.
512
+ function unpackCall(
513
+ Execution memory exec,
514
+ uint8 lane
515
+ ) internal pure returns (uint target, uint resources, bytes calldata data) {
516
+ uint cur = exec.decoders.select(lane);
517
+ uint abs = cur.absolute();
518
+ uint end;
519
+ (target, resources, data, end) = Blocks.unpackCall(abs);
520
+ exec.decoders = cur.seekAbs(end);
521
+ }
522
+
523
+ /// @notice Decode and consume one CONTEXT block from `lane`.
524
+ /// @param exec Execution whose decoder is advanced.
525
+ /// @param lane Decoder lane to consume.
526
+ /// @return account Decoded account identifier.
527
+ /// @return state Decoded nested state.
528
+ /// @return input Decoded nested input.
529
+ function unpackContext(
530
+ Execution memory exec,
531
+ uint8 lane
532
+ ) internal pure returns (bytes32 account, bytes calldata state, bytes calldata input) {
533
+ uint cur = exec.decoders.select(lane);
534
+ uint abs = cur.absolute();
535
+ uint end;
536
+ (account, state, input, end) = Blocks.unpackContext(abs);
537
+ exec.decoders = cur.seekAbs(end);
538
+ }
539
+
540
+ /// @notice Decode and consume one RELAY block from `lane`.
541
+ /// @param exec Execution whose decoder is advanced.
542
+ /// @param lane Decoder lane to consume.
543
+ /// @return portal Decoded destination portal.
544
+ /// @return resources Decoded packed resources.
545
+ /// @return input Decoded nested input.
546
+ function unpackRelay(
547
+ Execution memory exec,
548
+ uint8 lane
549
+ ) internal pure returns (uint portal, uint resources, bytes calldata input) {
550
+ uint cur = exec.decoders.select(lane);
551
+ uint end;
552
+ (portal, resources, input, end) = Blocks.unpackRelay(cur.absolute());
553
+ exec.decoders = cur.seekAbs(end);
554
+ }
555
+
556
+ /// @notice Decode and consume one DISPATCH block from `lane`.
557
+ /// @param exec Execution whose decoder is advanced.
558
+ /// @param lane Decoder lane to consume.
559
+ /// @return portal Decoded destination portal.
560
+ /// @return resources Decoded packed resources.
561
+ /// @return payload Decoded dispatch payload.
562
+ function unpackDispatch(
563
+ Execution memory exec,
564
+ uint8 lane
565
+ ) internal pure returns (uint portal, uint resources, bytes calldata payload) {
566
+ uint cur = exec.decoders.select(lane);
567
+ uint abs = cur.absolute();
568
+ uint end;
569
+ (portal, resources, payload, end) = Blocks.unpackDispatch(abs);
570
+ exec.decoders = cur.seekAbs(end);
571
+ }
572
+
573
+ /// @notice Decode and consume one LABEL block from `lane`.
574
+ /// @param exec Execution whose decoder is advanced.
575
+ /// @param lane Decoder lane to consume.
576
+ /// @return id Decoded node identifier.
577
+ /// @return namespace Decoded label namespace.
578
+ /// @return name Decoded label text.
579
+ function unpackLabel(
580
+ Execution memory exec,
581
+ uint8 lane
582
+ ) internal pure returns (uint id, bytes32 namespace, string memory name) {
583
+ uint cur = exec.decoders.select(lane);
584
+ uint abs = cur.absolute();
585
+ uint end;
586
+ (id, namespace, name, end) = Blocks.unpackLabel(abs);
587
+ exec.decoders = cur.seekAbs(end);
588
+ }
589
+
590
+ /// @notice Decode and consume one SCHEMA block from `lane`.
591
+ /// @param exec Execution whose decoder is advanced.
592
+ /// @param lane Decoder lane to consume.
593
+ /// @return spec Decoded block specification.
594
+ /// @return body Decoded schema body.
595
+ /// @return name Decoded schema name.
596
+ function unpackSchema(
597
+ Execution memory exec,
598
+ uint8 lane
599
+ ) internal pure returns (uint spec, string memory body, bytes32 name) {
600
+ uint cur = exec.decoders.select(lane);
601
+ uint abs = cur.absolute();
602
+ uint end;
603
+ (spec, body, name, end) = Blocks.unpackSchema(abs);
604
+ exec.decoders = cur.seekAbs(end);
605
+ }
606
+
607
+ /// @notice Decode and consume one RECOVER block from `lane`.
608
+ /// @param exec Execution whose decoder is advanced.
609
+ /// @param lane Decoder lane to consume.
610
+ /// @return handler Decoded recovery handler.
611
+ /// @return resources Decoded packed resources.
612
+ /// @return key Decoded recovery key.
613
+ /// @return witness Decoded recovery witness.
614
+ function unpackRecover(
615
+ Execution memory exec,
616
+ uint8 lane
617
+ ) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness) {
618
+ uint cur = exec.decoders.select(lane);
619
+ uint abs = cur.absolute();
620
+ uint end;
621
+ (handler, resources, key, witness, end) = Blocks.unpackRecover(abs);
622
+ exec.decoders = cur.seekAbs(end);
623
+ }
624
+
625
+ // -------------------------------------------------------------------------
626
+ // Output writing
627
+ // -------------------------------------------------------------------------
628
+
629
+ /// @dev Reserve output capacity and advance its writer cursor.
630
+ /// @param exec Execution whose output writer is advanced.
631
+ /// @param amount Logical number of bytes written.
632
+ /// @param touch Number of bytes that must be addressable by the write.
633
+ /// @return i Relative output offset reserved for the write.
634
+ function reserve(Execution memory exec, uint amount, uint touch) internal pure returns (uint i) {
635
+ uint writers = exec.writers.select(Lanes.Output);
636
+ (exec.writers, exec.output, i) = Buffers.reserve(writers, exec.output, amount, touch);
637
+ }
638
+
639
+ /// @dev Reserve an exact number of output bytes.
640
+ /// @param exec Execution whose output writer is advanced.
641
+ /// @param size Number of bytes to reserve and touch.
642
+ /// @return i Relative output offset reserved for the write.
643
+ function reserve(Execution memory exec, uint size) private pure returns (uint i) {
644
+ return reserve(exec, size, size);
645
+ }
646
+
647
+ /// @notice Append an ACCOUNT block to execution output.
648
+ /// @param exec Execution receiving the block.
649
+ /// @param account Account identifier to encode.
650
+ function outputAccount(Execution memory exec, bytes32 account) internal pure {
651
+ uint i = reserve(exec, Sizes.B32);
652
+ Blocks.writeAccount(exec.output, i, account);
653
+ }
654
+
655
+ /// @notice Append an ASSET block to execution output.
656
+ /// @param exec Execution receiving the block.
657
+ /// @param asset Asset identifier to encode.
658
+ function outputAsset(Execution memory exec, bytes32 asset) internal pure {
659
+ uint i = reserve(exec, Sizes.B32);
660
+ Blocks.writeAsset(exec.output, i, asset);
661
+ }
662
+
663
+ /// @notice Append a NODE block to execution output.
664
+ /// @param exec Execution receiving the block.
665
+ /// @param node Node identifier to encode.
666
+ function outputNode(Execution memory exec, uint node) internal pure {
667
+ uint i = reserve(exec, Sizes.B32);
668
+ Blocks.writeNode(exec.output, i, node);
669
+ }
670
+
671
+ /// @notice Append a STATUS block to execution output.
672
+ /// @param exec Execution receiving the block.
673
+ /// @param code Status code to encode.
674
+ function outputStatus(Execution memory exec, uint code) internal pure {
675
+ uint i = reserve(exec, Sizes.B32);
676
+ Blocks.writeStatus(exec.output, i, code);
677
+ }
678
+
679
+ /// @notice Append an AMOUNT block to execution output.
680
+ /// @param exec Execution receiving the block.
681
+ /// @param asset Asset identifier to encode.
682
+ /// @param amount Asset amount to encode.
683
+ function outputAmount(Execution memory exec, bytes32 asset, uint amount) internal pure {
684
+ uint i = reserve(exec, Sizes.B64);
685
+ Blocks.writeAmount(exec.output, i, asset, amount);
686
+ }
687
+
688
+ /// @notice Append a structured AMOUNT value to execution output.
689
+ /// @param exec Execution receiving the block.
690
+ /// @param value Structured asset amount to encode.
691
+ function outputAmount(Execution memory exec, AssetAmount memory value) internal pure {
692
+ outputAmount(exec, value.asset, value.amount);
693
+ }
694
+
695
+ /// @notice Append a BALANCE block to execution output.
696
+ /// @param exec Execution receiving the block.
697
+ /// @param asset Asset identifier to encode.
698
+ /// @param amount Balance amount to encode.
699
+ function outputBalance(Execution memory exec, bytes32 asset, uint amount) internal pure {
700
+ uint i = reserve(exec, Sizes.B64);
701
+ Blocks.writeBalance(exec.output, i, asset, amount);
702
+ }
703
+
704
+ /// @notice Append a structured BALANCE value to execution output.
705
+ /// @param exec Execution receiving the block.
706
+ /// @param value Structured asset balance to encode.
707
+ function outputBalance(Execution memory exec, AssetAmount memory value) internal pure {
708
+ outputBalance(exec, value.asset, value.amount);
709
+ }
710
+
711
+ /// @notice Append an ACCOUNT_ASSET block to execution output.
712
+ /// @param exec Execution receiving the block.
713
+ /// @param account Account identifier to encode.
714
+ /// @param asset Asset identifier to encode.
715
+ function outputAccountAsset(Execution memory exec, bytes32 account, bytes32 asset) internal pure {
716
+ uint i = reserve(exec, Sizes.B64);
717
+ Blocks.writeAccountAsset(exec.output, i, account, asset);
718
+ }
719
+
720
+ /// @notice Append an ALLOCATION block to execution output.
721
+ /// @param exec Execution receiving the block.
722
+ /// @param host Host identifier to encode.
723
+ /// @param asset Asset identifier to encode.
724
+ /// @param amount Allocation amount to encode.
725
+ function outputAllocation(Execution memory exec, uint host, bytes32 asset, uint amount) internal pure {
726
+ uint i = reserve(exec, Sizes.B96);
727
+ Blocks.writeAllocation(exec.output, i, host, asset, amount);
728
+ }
729
+
730
+ /// @notice Append an ALLOWANCE block to execution output.
731
+ /// @param exec Execution receiving the block.
732
+ /// @param host Host identifier to encode.
733
+ /// @param asset Asset identifier to encode.
734
+ /// @param amount Allowance amount to encode.
735
+ function outputAllowance(Execution memory exec, uint host, bytes32 asset, uint amount) internal pure {
736
+ uint i = reserve(exec, Sizes.B96);
737
+ Blocks.writeAllowance(exec.output, i, host, asset, amount);
738
+ }
739
+
740
+ /// @notice Append a CUSTODY block to execution output.
741
+ /// @param exec Execution receiving the block.
742
+ /// @param host Host identifier to encode.
743
+ /// @param asset Asset identifier to encode.
744
+ /// @param amount Custody amount to encode.
745
+ function outputCustody(Execution memory exec, uint host, bytes32 asset, uint amount) internal pure {
746
+ uint i = reserve(exec, Sizes.B96);
747
+ Blocks.writeCustody(exec.output, i, host, asset, amount);
748
+ }
749
+
750
+ /// @notice Append a CUSTODY block for `host` and a structured amount.
751
+ /// @param exec Execution receiving the block.
752
+ /// @param host Host identifier to encode.
753
+ /// @param value Structured asset amount to encode.
754
+ function outputCustody(Execution memory exec, uint host, AssetAmount memory value) internal pure {
755
+ outputCustody(exec, host, value.asset, value.amount);
756
+ }
757
+
758
+ /// @notice Append a structured CUSTODY value to execution output.
759
+ /// @param exec Execution receiving the block.
760
+ /// @param value Structured host asset amount to encode.
761
+ function outputCustody(Execution memory exec, HostAmount memory value) internal pure {
762
+ outputCustody(exec, value.host, value.asset, value.amount);
763
+ }
764
+
765
+ /// @notice Append an ACCOUNT_AMOUNT block to execution output.
766
+ /// @param exec Execution receiving the block.
767
+ /// @param account Account identifier to encode.
768
+ /// @param asset Asset identifier to encode.
769
+ /// @param amount Account amount to encode.
770
+ function outputAccountAmount(Execution memory exec, bytes32 account, bytes32 asset, uint amount) internal pure {
771
+ uint i = reserve(exec, Sizes.B96);
772
+ Blocks.writeAccountAmount(exec.output, i, account, asset, amount);
773
+ }
774
+
775
+ /// @notice Append a structured ACCOUNT_AMOUNT value to execution output.
776
+ /// @param exec Execution receiving the block.
777
+ /// @param value Structured account asset amount to encode.
778
+ function outputAccountAmount(Execution memory exec, AccountAmount memory value) internal pure {
779
+ outputAccountAmount(exec, value.account, value.asset, value.amount);
780
+ }
781
+
782
+ /// @notice Append a HOST_AMOUNT block to execution output.
783
+ /// @param exec Execution receiving the block.
784
+ /// @param host Host identifier to encode.
785
+ /// @param asset Asset identifier to encode.
786
+ /// @param amount Host amount to encode.
787
+ function outputHostAmount(Execution memory exec, uint host, bytes32 asset, uint amount) internal pure {
788
+ uint i = reserve(exec, Sizes.B96);
789
+ Blocks.writeHostAmount(exec.output, i, host, asset, amount);
790
+ }
791
+
792
+ /// @notice Append a HOST_ACCOUNT_ASSET block to execution output.
793
+ /// @param exec Execution receiving the block.
794
+ /// @param host Host identifier to encode.
795
+ /// @param account Account identifier to encode.
796
+ /// @param asset Asset identifier to encode.
797
+ function outputHostAccountAsset(Execution memory exec, uint host, bytes32 account, bytes32 asset) internal pure {
798
+ uint i = reserve(exec, Sizes.B96);
799
+ Blocks.writeHostAccountAsset(exec.output, i, host, account, asset);
800
+ }
801
+
802
+ /// @notice Append a TRANSACTION block to regular execution output.
803
+ /// @param exec Execution receiving the block.
804
+ /// @param from Debit account identifier.
805
+ /// @param to Credit account identifier.
806
+ /// @param asset Asset identifier to encode.
807
+ /// @param amount Transaction amount to encode.
808
+ function outputTransaction(
809
+ Execution memory exec,
810
+ bytes32 from,
811
+ bytes32 to,
812
+ bytes32 asset,
813
+ uint amount
814
+ ) internal pure {
815
+ uint i = reserve(exec, Sizes.B128);
816
+ Blocks.writeTransaction(exec.output, i, from, to, asset, amount);
817
+ }
818
+
819
+ /// @notice Append a structured TRANSACTION value to regular execution output.
820
+ /// @param exec Execution receiving the block.
821
+ /// @param value Structured transaction to encode.
822
+ function outputTransaction(Execution memory exec, Tx memory value) internal pure {
823
+ outputTransaction(exec, value.from, value.to, value.asset, value.amount);
824
+ }
825
+
826
+ /// @notice Append a HOST_ACCOUNT_AMOUNT block to execution output.
827
+ /// @param exec Execution receiving the block.
828
+ /// @param host Host identifier to encode.
829
+ /// @param account Account identifier to encode.
830
+ /// @param asset Asset identifier to encode.
831
+ /// @param amount Host account amount to encode.
832
+ function outputHostAccountAmount(
833
+ Execution memory exec,
834
+ uint host,
835
+ bytes32 account,
836
+ bytes32 asset,
837
+ uint amount
838
+ ) internal pure {
839
+ uint i = reserve(exec, Sizes.B128);
840
+ Blocks.writeHostAccountAmount(exec.output, i, host, account, asset, amount);
841
+ }
842
+
843
+ /// @notice Append a LIST block to execution output.
844
+ /// @param exec Execution receiving the block.
845
+ /// @param value Encoded list payload.
846
+ function outputList(Execution memory exec, bytes memory value) internal pure {
847
+ uint size = Sizes.Header + value.length;
848
+ uint i = reserve(exec, size);
849
+ Blocks.writeList(exec.output, i, value);
850
+ }
851
+
852
+ /// @notice Append an EVM block to execution output.
853
+ /// @param exec Execution receiving the block.
854
+ /// @param value EVM payload to encode.
855
+ function outputEvm(Execution memory exec, bytes memory value) internal pure {
856
+ uint size = Sizes.Header + value.length;
857
+ uint i = reserve(exec, size);
858
+ Blocks.writeEvm(exec.output, i, value);
859
+ }
860
+
861
+ /// @notice Append a BYTES block to execution output.
862
+ /// @param exec Execution receiving the block.
863
+ /// @param value Byte payload to encode.
864
+ function outputBytes(Execution memory exec, bytes memory value) internal pure {
865
+ uint size = Sizes.Header + value.length;
866
+ uint i = reserve(exec, size);
867
+ Blocks.writeBytes(exec.output, i, value);
868
+ }
869
+
870
+ /// @notice Append a STRING block to execution output.
871
+ /// @param exec Execution receiving the block.
872
+ /// @param value String payload to encode.
873
+ function outputString(Execution memory exec, string memory value) internal pure {
874
+ uint size = Sizes.Header + bytes(value).length;
875
+ uint i = reserve(exec, size);
876
+ Blocks.writeString(exec.output, i, value);
877
+ }
878
+
879
+ /// @notice Append a STEP block to execution output.
880
+ /// @param exec Execution receiving the block.
881
+ /// @param cmd Command identifier to encode.
882
+ /// @param resources Packed resources to encode.
883
+ /// @param input Command input to encode.
884
+ function outputStep(Execution memory exec, uint cmd, uint resources, bytes memory input) internal pure {
885
+ uint size = Sizes.B64 + Sizes.Header + input.length;
886
+ uint i = reserve(exec, size);
887
+ Blocks.writeStep(exec.output, i, cmd, resources, input);
888
+ }
889
+
890
+ /// @notice Append a CALL block to execution output.
891
+ /// @param exec Execution receiving the block.
892
+ /// @param target Call target to encode.
893
+ /// @param resources Packed resources to encode.
894
+ /// @param payload Call payload to encode.
895
+ function outputCall(Execution memory exec, uint target, uint resources, bytes memory payload) internal pure {
896
+ uint size = Sizes.B64 + Sizes.Header + payload.length;
897
+ uint i = reserve(exec, size);
898
+ Blocks.writeCall(exec.output, i, target, resources, payload);
899
+ }
900
+
901
+ /// @notice Append a RELAY block to execution output.
902
+ /// @param exec Execution receiving the block.
903
+ /// @param portal Destination portal to encode.
904
+ /// @param resources Packed resources to encode.
905
+ /// @param input Relay input to encode.
906
+ function outputRelay(Execution memory exec, uint portal, uint resources, bytes memory input) internal pure {
907
+ uint size = Sizes.B64 + Sizes.Header + input.length;
908
+ uint i = reserve(exec, size);
909
+ Blocks.writeRelay(exec.output, i, portal, resources, input);
910
+ }
911
+
912
+ /// @notice Append a DISPATCH block to execution output.
913
+ /// @param exec Execution receiving the block.
914
+ /// @param portal Destination portal to encode.
915
+ /// @param resources Packed resources to encode.
916
+ /// @param payload Dispatch payload to encode.
917
+ function outputDispatch(Execution memory exec, uint portal, uint resources, bytes memory payload) internal pure {
918
+ uint size = Sizes.B64 + Sizes.Header + payload.length;
919
+ uint i = reserve(exec, size);
920
+ Blocks.writeDispatch(exec.output, i, portal, resources, payload);
921
+ }
922
+
923
+ /// @notice Append a CONTEXT block to execution output.
924
+ /// @param exec Execution receiving the block.
925
+ /// @param account Account identifier to encode.
926
+ /// @param state State payload to encode.
927
+ /// @param input Input payload to encode.
928
+ function outputContext(
929
+ Execution memory exec,
930
+ bytes32 account,
931
+ bytes memory state,
932
+ bytes memory input
933
+ ) internal pure {
934
+ uint size = Sizes.B32 + 2 * Sizes.Header + state.length + input.length;
935
+ uint i = reserve(exec, size);
936
+ Blocks.writeContext(exec.output, i, account, state, input);
937
+ }
938
+
939
+ /// @notice Append a RECOVER block to execution output.
940
+ /// @param exec Execution receiving the block.
941
+ /// @param handler Recovery handler to encode.
942
+ /// @param resources Packed resources to encode.
943
+ /// @param recoverykey Recovery key to encode.
944
+ /// @param witness Recovery witness to encode.
945
+ function outputRecover(
946
+ Execution memory exec,
947
+ uint handler,
948
+ uint resources,
949
+ bytes32 recoverykey,
950
+ bytes memory witness
951
+ ) internal pure {
952
+ uint size = Sizes.B96 + Sizes.Header + witness.length;
953
+ uint i = reserve(exec, size);
954
+ Blocks.writeRecover(exec.output, i, handler, resources, recoverykey, witness);
955
+ }
956
+
957
+ /// @notice Append a LABEL block to execution output.
958
+ /// @param exec Execution receiving the block.
959
+ /// @param id Node identifier to encode.
960
+ /// @param namespace Label namespace to encode.
961
+ /// @param name Label text to encode.
962
+ function outputLabel(Execution memory exec, uint id, bytes32 namespace, string memory name) internal pure {
963
+ uint size = Sizes.B64 + Sizes.Header + bytes(name).length;
964
+ uint i = reserve(exec, size);
965
+ Blocks.writeLabel(exec.output, i, id, namespace, name);
966
+ }
967
+
968
+ /// @notice Append a SCHEMA block to execution output.
969
+ /// @param exec Execution receiving the block.
970
+ /// @param spec Block specification to encode.
971
+ /// @param body Schema body to encode.
972
+ /// @param name Schema name to encode.
973
+ function outputSchema(Execution memory exec, uint spec, string memory body, bytes32 name) internal pure {
974
+ uint size = Sizes.B64 + Sizes.Header + bytes(body).length;
975
+ uint i = reserve(exec, size);
976
+ Blocks.writeSchema(exec.output, i, spec, body, name);
977
+ }
978
+
979
+ // -------------------------------------------------------------------------
980
+ // Value and transaction writing
981
+ // -------------------------------------------------------------------------
982
+
983
+ /// @notice Transfer the remaining value budget out of an execution.
984
+ /// @dev Clears `exec.budget` so the returned budget becomes its sole owner.
985
+ /// @param exec Execution whose budget is detached.
986
+ /// @return budget Detached budget containing the remaining value.
987
+ function takeBudget(Execution memory exec) internal pure returns (Budget memory budget) {
988
+ budget.remaining = exec.budget;
989
+ exec.budget = 0;
990
+ }
991
+
992
+ /// @notice Deduct the EVM value lane of `resources` from the execution budget.
993
+ /// @dev EVM resources use the low 128 bits as native value/endowment.
994
+ /// @param exec Mutable execution whose budget is charged.
995
+ /// @param resources Packed resources whose value lane should be spent.
996
+ /// @return value Native value to forward in wei.
997
+ function useValue(Execution memory exec, uint resources) internal pure returns (uint128 value) {
998
+ value = uint128(resources);
999
+ if (value > exec.budget) revert InsufficientValue();
1000
+ exec.budget -= value;
1001
+ }
1002
+
1003
+ /// @notice Append a deferred transaction to the transaction writer lane.
1004
+ /// @param exec Execution receiving the transaction.
1005
+ /// @param from Debit account identifier.
1006
+ /// @param to Credit account identifier.
1007
+ /// @param asset Asset identifier.
1008
+ /// @param amount Transaction amount.
1009
+ function queueTransaction(
1010
+ Execution memory exec,
1011
+ bytes32 from,
1012
+ bytes32 to,
1013
+ bytes32 asset,
1014
+ uint amount
1015
+ ) internal pure {
1016
+ uint i;
1017
+ uint size = Sizes.Transaction;
1018
+ uint writers = exec.writers.select(Lanes.Transactions);
1019
+ (exec.writers, exec.transactions, i) = Buffers.reserve(writers, exec.transactions, size, size);
1020
+ Blocks.writeTransaction(exec.transactions, i, from, to, asset, amount);
1021
+ }
1022
+
1023
+ /// @notice Queue a transaction that debits `account`.
1024
+ /// @param exec Execution receiving the transaction.
1025
+ /// @param account Account to debit.
1026
+ /// @param asset Asset to debit.
1027
+ /// @param amount Amount to debit.
1028
+ function queueDebit(Execution memory exec, bytes32 account, bytes32 asset, uint amount) internal pure {
1029
+ queueTransaction(exec, account, bytes32(0), asset, amount);
1030
+ }
1031
+
1032
+ /// @notice Queue a transaction that credits `account`.
1033
+ /// @param exec Execution receiving the transaction.
1034
+ /// @param account Account to credit.
1035
+ /// @param asset Asset to credit.
1036
+ /// @param amount Amount to credit.
1037
+ function queueCredit(Execution memory exec, bytes32 account, bytes32 asset, uint amount) internal pure {
1038
+ queueTransaction(exec, bytes32(0), account, asset, amount);
1039
+ }
1040
+
1041
+ /// @notice Drain the remaining value budget and queue it as an account refund.
1042
+ /// @dev Creates a one-transaction writer lane when the descriptor declared none.
1043
+ /// @param exec Execution whose remaining budget is refunded.
1044
+ /// @param account Account receiving the refund.
1045
+ /// @param asset Asset identifier used for the refund transaction.
1046
+ /// @return amount Value removed from the execution budget and queued for refund.
1047
+ function refundValue(Execution memory exec, bytes32 account, bytes32 asset) internal pure returns (uint amount) {
1048
+ amount = exec.budget;
1049
+ if (amount == 0) return 0;
1050
+
1051
+ exec.budget = 0;
1052
+ if (!exec.writers.contains(Lanes.Transactions)) {
1053
+ uint refunds = Buffers.cursor(Sizes.Transaction, 1, false, Lanes.Transactions);
1054
+ exec.writers = Cursors.pair(exec.writers, refunds);
1055
+ }
1056
+
1057
+ queueCredit(exec, account, asset, amount);
1058
+ }
1059
+
1060
+ // -------------------------------------------------------------------------
1061
+ // Finalization
1062
+ // -------------------------------------------------------------------------
1063
+
1064
+ /// @notice Finalize and return regular execution output.
1065
+ /// @param exec Execution whose output is finalized.
1066
+ /// @return out Trimmed output bytes.
1067
+ function finish(Execution memory exec) internal pure returns (bytes memory out) {
1068
+ if (exec.output.length == 0) return new bytes(0);
1069
+
1070
+ uint writers = exec.writers.select(Lanes.Output);
1071
+ out = Buffers.finish(writers, exec.output);
1072
+ }
1073
+
1074
+ /// @notice Finalize and return queued execution transactions.
1075
+ /// @param exec Execution whose transactions are finalized.
1076
+ /// @return out Trimmed transaction bytes.
1077
+ function finishTransactions(Execution memory exec) internal pure returns (bytes memory out) {
1078
+ if (exec.transactions.length == 0) return new bytes(0);
1079
+
1080
+ uint writers = exec.writers.select(Lanes.Transactions);
1081
+ out = Buffers.finish(writers, exec.transactions);
1082
+ }
1083
+ }