@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,558 @@
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 "./Blocks.sol";
6
+ import {Sizes, Specs} from "./Specs.sol";
7
+ import {Cursors, Cur} from "../utils/Cursors.sol";
8
+
9
+ using Decoders for Cur;
10
+
11
+ /// @title Decoders
12
+ /// @notice Mutable calldata block decoding through a Cur memory cursor.
13
+ library Decoders {
14
+ using Cursors for uint;
15
+
16
+ // -------------------------------------------------------------------------
17
+ // Cur memory adapters
18
+ // -------------------------------------------------------------------------
19
+
20
+ /// @notice Wrap a calldata source in an ungrouped cursor.
21
+ /// @param source Calldata region to wrap.
22
+ /// @return cur Cursor spanning the complete source.
23
+ function wrap(bytes calldata source) internal pure returns (Cur memory cur) {
24
+ cur.state = Cursors.wrap(source, 0, 0);
25
+ }
26
+
27
+ /// @notice Wrap the calldata tail beginning at relative position `i`.
28
+ /// @param source Calldata region containing the tail.
29
+ /// @param i Relative tail position.
30
+ /// @return cur Cursor spanning `source[i:]`.
31
+ function wrap(bytes calldata source, uint i) internal pure returns (Cur memory cur) {
32
+ cur.state = Cursors.wrap(source[i:], 0, 0);
33
+ }
34
+
35
+ /// @notice Open the first homogeneous run in `source` using `stride`.
36
+ /// @param source Calldata block stream to open.
37
+ /// @param stride Number of blocks per group, or zero for an ungrouped stream.
38
+ /// @return cur Cursor spanning the first homogeneous run.
39
+ function open(
40
+ bytes calldata source,
41
+ uint stride
42
+ ) internal pure returns (Cur memory cur) {
43
+ (uint abs, uint limit) = Cursors.bounds(source);
44
+ if (stride == 0 && abs == limit) return cur;
45
+
46
+ bytes4 key = bytes4(source);
47
+ (uint groups, uint end) = Blocks.scope(abs, limit, key, stride);
48
+ cur.state = Cursors.create(abs, end - abs, groups, 0, 0);
49
+ }
50
+
51
+ /// @notice Return whether `cur` has unread bytes.
52
+ /// @param cur Cursor to inspect.
53
+ /// @return Whether unread bytes remain.
54
+ function more(Cur memory cur) internal pure returns (bool) {
55
+ return cur.state.more();
56
+ }
57
+
58
+ /// @notice Validate and consume the next block from a cursor.
59
+ /// @param cur Cursor advanced over the complete block.
60
+ /// @param spec Expected block specification.
61
+ /// @return abs Absolute position of the first payload byte.
62
+ /// @return end Absolute position immediately after the payload.
63
+ function consume(Cur memory cur, uint spec) internal pure returns (uint abs, uint end) {
64
+ (abs, end) = Blocks.expect(cur.state.absolute(), spec);
65
+ cur.state = cur.state.seekAbs(end);
66
+ }
67
+
68
+ /// @notice Create a child cursor over relative range `[from, to)`.
69
+ /// @param cur Parent cursor.
70
+ /// @param from Inclusive relative start.
71
+ /// @param to Exclusive relative end.
72
+ /// @return out Child cursor spanning the selected range.
73
+ function slice(Cur memory cur, uint from, uint to) internal pure returns (Cur memory out) {
74
+ out.state = cur.state.slice(from, to, 0);
75
+ }
76
+
77
+ /// @notice Return the complete calldata region represented by `cur`.
78
+ /// @param cur Cursor whose calldata is returned.
79
+ /// @return Complete cursor region.
80
+ function raw(Cur memory cur) internal pure returns (bytes calldata) {
81
+ (, uint offset, uint len) = cur.state.decode();
82
+ if (len > msg.data.length || offset > msg.data.length - len) revert Blocks.MalformedBlocks();
83
+ return msg.data[offset:offset + len];
84
+ }
85
+
86
+ /// @notice Return relative calldata range `[from, to)` from `cur`.
87
+ /// @param cur Cursor containing the range.
88
+ /// @param from Inclusive relative start.
89
+ /// @param to Exclusive relative end.
90
+ /// @return data Selected calldata range.
91
+ function raw(Cur memory cur, uint from, uint to) internal pure returns (bytes calldata data) {
92
+ (, uint offset, uint len) = cur.state.decode();
93
+ if (from > to || to > len) revert Blocks.MalformedBlocks();
94
+ if (len > msg.data.length || offset > msg.data.length - len) revert Blocks.MalformedBlocks();
95
+ data = msg.data[offset + from:offset + to];
96
+ }
97
+
98
+ /// @notice Hash relative calldata range `[from, to)` from `cur`.
99
+ /// @param cur Cursor containing the range.
100
+ /// @param from Inclusive relative start.
101
+ /// @param to Exclusive relative end.
102
+ /// @return Hash of the selected calldata.
103
+ function hash(Cur memory cur, uint from, uint to) internal pure returns (bytes32) {
104
+ return keccak256(raw(cur, from, to));
105
+ }
106
+
107
+ /// @notice Read the block header at relative position `i` without advancing.
108
+ /// @param cur Cursor containing the block.
109
+ /// @param i Relative block position.
110
+ /// @return key Block key.
111
+ /// @return len Payload length.
112
+ function peek(Cur memory cur, uint i) internal pure returns (bytes4 key, uint len) {
113
+ (, uint offset, uint size) = cur.state.decode();
114
+ if (i > size || Sizes.Header > size - i) revert Blocks.MalformedBlocks();
115
+ (key, len) = Blocks.header(offset + i);
116
+ if (len > size - i - Sizes.Header) revert Blocks.MalformedBlocks();
117
+ }
118
+
119
+ /// @notice Return the relative position immediately after the current block.
120
+ /// @param cur Cursor positioned at a block.
121
+ /// @return Relative position after the block.
122
+ function past(Cur memory cur) internal pure returns (uint) {
123
+ (uint i, , ) = cur.state.decode();
124
+ (, uint len) = peek(cur, i);
125
+ return i + Sizes.Header + len;
126
+ }
127
+
128
+ /// @notice Return whether `key` occurs at relative position `i`.
129
+ /// @param cur Cursor containing the position.
130
+ /// @param i Relative block position.
131
+ /// @param key Expected block key.
132
+ /// @return Whether the key occurs at the position.
133
+ function hasAt(Cur memory cur, uint i, bytes4 key) internal pure returns (bool) {
134
+ (, uint offset, uint len) = cur.state.decode();
135
+ return Blocks.hasAt(offset + i, offset + len, key);
136
+ }
137
+
138
+ /// @notice Return whether the current block has `key`.
139
+ /// @param cur Cursor positioned at a block.
140
+ /// @param key Expected block key.
141
+ /// @return Whether the current block has the key.
142
+ function isAt(Cur memory cur, bytes4 key) internal pure returns (bool) {
143
+ (uint i, uint offset, uint len) = cur.state.decode();
144
+ return Blocks.hasAt(offset + i, offset + len, key);
145
+ }
146
+
147
+ /// @notice Find `key` at or after relative position `i`.
148
+ /// @param cur Cursor to search.
149
+ /// @param i Relative search position.
150
+ /// @param key Block key to find.
151
+ /// @return Relative position of the matching block.
152
+ function find(Cur memory cur, uint i, bytes4 key) internal pure returns (uint) {
153
+ (, uint offset, uint end) = cur.state.decode();
154
+ return Blocks.find(offset + i, offset + end, key) - offset;
155
+ }
156
+
157
+ /// @notice Find `key` at or after the current cursor position.
158
+ /// @param cur Cursor to search from its current position.
159
+ /// @param key Block key to find.
160
+ /// @return Relative position of the matching block.
161
+ function find(Cur memory cur, bytes4 key) internal pure returns (uint) {
162
+ (uint i, uint offset, uint end) = cur.state.decode();
163
+ return Blocks.find(offset + i, offset + end, key) - offset;
164
+ }
165
+
166
+ /// @notice Consume one LIST block and return a cursor over its items.
167
+ /// @param cur Cursor advanced past the list.
168
+ /// @return items Cursor spanning the list payload.
169
+ function list(Cur memory cur) internal pure returns (Cur memory items) {
170
+ (uint abs, uint end) = consume(cur, Specs.List);
171
+ items.state = Cursors.create(abs, end - abs, 0, 0, 0);
172
+ }
173
+
174
+ /// @notice Consume one block with `key` and return its complete encoded region.
175
+ /// @param cur Cursor advanced past the block.
176
+ /// @param key Expected block key.
177
+ /// @return out Cursor spanning the complete encoded block.
178
+ function take(Cur memory cur, bytes4 key) internal pure returns (Cur memory out) {
179
+ uint abs = cur.state.absolute();
180
+ (, uint end) = consume(cur, Specs.create(key, 0, 0, 0));
181
+ out.state = Cursors.create(abs, end - abs, 0, 0, 0);
182
+ }
183
+
184
+ // -------------------------------------------------------------------------
185
+ // Generic block decoding
186
+ // -------------------------------------------------------------------------
187
+
188
+ /// @notice Decode and consume a block described by `spec`.
189
+ /// @param cur Cursor advanced past the block.
190
+ /// @param spec Expected block specification.
191
+ /// @return data Decoded payload.
192
+ function unpackRaw(Cur memory cur, uint spec) internal pure returns (bytes calldata data) {
193
+ uint end;
194
+ (data, end) = Blocks.unpackRaw(cur.state.absolute(), spec);
195
+ cur.state = cur.state.seekAbs(end);
196
+ }
197
+
198
+ /// @notice Decode and consume one BYTES block.
199
+ /// @param cur Cursor advanced past the block.
200
+ /// @return data Decoded byte payload.
201
+ function unpackBytes(Cur memory cur) internal pure returns (bytes calldata data) {
202
+ uint end;
203
+ (data, end) = Blocks.unpackBytes(cur.state.absolute());
204
+ cur.state = cur.state.seekAbs(end);
205
+ }
206
+
207
+ /// @notice Decode and consume one STRING block.
208
+ /// @param cur Cursor advanced past the block.
209
+ /// @return data Decoded string payload.
210
+ function unpackString(Cur memory cur) internal pure returns (string memory data) {
211
+ bytes calldata value;
212
+ uint end;
213
+ (value, end) = Blocks.unpackString(cur.state.absolute());
214
+ cur.state = cur.state.seekAbs(end);
215
+ data = string(value);
216
+ }
217
+
218
+ // -------------------------------------------------------------------------
219
+ // Execution-compatible fixed-width block decoding
220
+ // -------------------------------------------------------------------------
221
+
222
+ /// @notice Decode one fixed 32-byte payload described by `spec`.
223
+ /// @param cur Cursor advanced past the block.
224
+ /// @param spec Expected block specification.
225
+ /// @return value Decoded payload word.
226
+ function unpack32(Cur memory cur, uint spec) internal pure returns (bytes32 value) {
227
+ uint abs;
228
+ (cur.state, abs) = cur.state.consume(Sizes.B32);
229
+ if (Blocks.header(abs, Specs.key(spec)) != 32) revert Blocks.InvalidBlock();
230
+ assembly ("memory-safe") {
231
+ value := calldataload(add(abs, 0x08))
232
+ }
233
+ }
234
+
235
+ /// @notice Decode and consume one ACCOUNT block.
236
+ /// @param cur Cursor advanced past the block.
237
+ /// @return account Decoded account identifier.
238
+ function unpackAccount(Cur memory cur) internal pure returns (bytes32 account) {
239
+ uint abs;
240
+ (cur.state, abs) = cur.state.consume(Sizes.B32);
241
+ account = Blocks.unpackAccount(abs);
242
+ }
243
+
244
+ /// @notice Decode and consume one NODE block.
245
+ /// @param cur Cursor advanced past the block.
246
+ /// @return node Decoded node identifier.
247
+ function unpackNode(Cur memory cur) internal pure returns (uint node) {
248
+ uint abs;
249
+ (cur.state, abs) = cur.state.consume(Sizes.B32);
250
+ node = Blocks.unpackNode(abs);
251
+ }
252
+
253
+ /// @notice Decode and consume one ASSET block.
254
+ /// @param cur Cursor advanced past the block.
255
+ /// @return asset Decoded asset identifier.
256
+ function unpackAsset(Cur memory cur) internal pure returns (bytes32 asset) {
257
+ uint abs;
258
+ (cur.state, abs) = cur.state.consume(Sizes.B32);
259
+ asset = Blocks.unpackAsset(abs);
260
+ }
261
+
262
+ /// @notice Decode and consume one ACCOUNT_ASSET block.
263
+ /// @param cur Cursor advanced past the block.
264
+ /// @return account Decoded account identifier.
265
+ /// @return asset Decoded asset identifier.
266
+ function unpackAccountAsset(Cur memory cur) internal pure returns (bytes32 account, bytes32 asset) {
267
+ uint abs;
268
+ (cur.state, abs) = cur.state.consume(Sizes.B64);
269
+ (account, asset) = Blocks.unpackAccountAsset(abs);
270
+ }
271
+
272
+ /// @notice Decode and consume one AMOUNT block.
273
+ /// @param cur Cursor advanced past the block.
274
+ /// @return asset Decoded asset identifier.
275
+ /// @return amount Decoded amount.
276
+ function unpackAmount(Cur memory cur) internal pure returns (bytes32 asset, uint amount) {
277
+ uint abs;
278
+ (cur.state, abs) = cur.state.consume(Sizes.Amount);
279
+ (asset, amount) = Blocks.unpackAmount(abs);
280
+ }
281
+
282
+ /// @notice Decode and consume one BALANCE block.
283
+ /// @param cur Cursor advanced past the block.
284
+ /// @return asset Decoded asset identifier.
285
+ /// @return amount Decoded balance.
286
+ function unpackBalance(Cur memory cur) internal pure returns (bytes32 asset, uint amount) {
287
+ uint abs;
288
+ (cur.state, abs) = cur.state.consume(Sizes.Balance);
289
+ (asset, amount) = Blocks.unpackBalance(abs);
290
+ }
291
+
292
+ /// @notice Decode one BALANCE block and associate it with `host`.
293
+ /// @param cur Cursor advanced past the block.
294
+ /// @param host Host identifier associated with the balance.
295
+ /// @return value Structured host balance.
296
+ function unpackBalanceForHost(Cur memory cur, uint host) internal pure returns (HostAmount memory value) {
297
+ uint abs;
298
+ (cur.state, abs) = cur.state.consume(Sizes.Balance);
299
+ value.host = host;
300
+ (value.asset, value.amount) = Blocks.unpackBalance(abs);
301
+ }
302
+
303
+ /// @notice Decode and consume one ACCOUNT_AMOUNT block.
304
+ /// @param cur Cursor advanced past the block.
305
+ /// @return account Decoded account identifier.
306
+ /// @return asset Decoded asset identifier.
307
+ /// @return amount Decoded amount.
308
+ function unpackAccountAmount(
309
+ Cur memory cur
310
+ ) internal pure returns (bytes32 account, bytes32 asset, uint amount) {
311
+ uint abs;
312
+ (cur.state, abs) = cur.state.consume(Sizes.B96);
313
+ (account, asset, amount) = Blocks.unpackAccountAmount(abs);
314
+ }
315
+
316
+ /// @notice Decode one ALLOCATION block into its structured value.
317
+ /// @param cur Cursor advanced past the block.
318
+ /// @return value Structured allocation.
319
+ function unpackAllocationValue(Cur memory cur) internal pure returns (HostAmount memory value) {
320
+ uint abs;
321
+ (cur.state, abs) = cur.state.consume(Sizes.B96);
322
+ (value.host, value.asset, value.amount) = Blocks.unpackAllocation(abs);
323
+ }
324
+
325
+ /// @notice Decode and consume one ALLOWANCE block.
326
+ /// @param cur Cursor advanced past the block.
327
+ /// @return host Decoded host identifier.
328
+ /// @return asset Decoded asset identifier.
329
+ /// @return amount Decoded allowance.
330
+ function unpackAllowance(Cur memory cur) internal pure returns (uint host, bytes32 asset, uint amount) {
331
+ uint abs;
332
+ (cur.state, abs) = cur.state.consume(Sizes.B96);
333
+ (host, asset, amount) = Blocks.unpackAllowance(abs);
334
+ }
335
+
336
+ /// @notice Decode and consume one TRANSACTION block.
337
+ /// @param cur Cursor advanced past the block.
338
+ /// @return from Decoded debit account.
339
+ /// @return to Decoded credit account.
340
+ /// @return asset Decoded asset identifier.
341
+ /// @return amount Decoded transaction amount.
342
+ function unpackTransaction(
343
+ Cur memory cur
344
+ ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
345
+ uint abs;
346
+ (cur.state, abs) = cur.state.consume(Sizes.Transaction);
347
+ (from, to, asset, amount) = Blocks.unpackTransaction(abs);
348
+ }
349
+
350
+ // -------------------------------------------------------------------------
351
+ // Execution-compatible dynamic block decoding
352
+ // -------------------------------------------------------------------------
353
+
354
+ /// @notice Decode and consume one CALL block.
355
+ /// @param cur Cursor advanced past the block.
356
+ /// @return target Decoded call target.
357
+ /// @return resources Decoded packed resources.
358
+ /// @return data Decoded call payload.
359
+ function unpackCall(
360
+ Cur memory cur
361
+ ) internal pure returns (uint target, uint resources, bytes calldata data) {
362
+ uint abs = cur.state.absolute();
363
+ uint end;
364
+ (target, resources, data, end) = Blocks.unpackCall(abs);
365
+ cur.state = cur.state.seekAbs(end);
366
+ }
367
+
368
+ /// @notice Decode and consume one CONTEXT block.
369
+ /// @param cur Cursor advanced past the block.
370
+ /// @return account Decoded account identifier.
371
+ /// @return state Decoded state payload.
372
+ /// @return input Decoded input payload.
373
+ function unpackContext(
374
+ Cur memory cur
375
+ ) internal pure returns (bytes32 account, bytes calldata state, bytes calldata input) {
376
+ uint abs = cur.state.absolute();
377
+ uint end;
378
+ (account, state, input, end) = Blocks.unpackContext(abs);
379
+ cur.state = cur.state.seekAbs(end);
380
+ }
381
+
382
+ /// @notice Decode and consume one DISPATCH block.
383
+ /// @param cur Cursor advanced past the block.
384
+ /// @return portal Decoded destination portal.
385
+ /// @return resources Decoded packed resources.
386
+ /// @return payload Decoded dispatch payload.
387
+ function unpackDispatch(
388
+ Cur memory cur
389
+ ) internal pure returns (uint portal, uint resources, bytes calldata payload) {
390
+ uint abs = cur.state.absolute();
391
+ uint end;
392
+ (portal, resources, payload, end) = Blocks.unpackDispatch(abs);
393
+ cur.state = cur.state.seekAbs(end);
394
+ }
395
+
396
+ /// @notice Decode and consume one LABEL block.
397
+ /// @param cur Cursor advanced past the block.
398
+ /// @return id Decoded node identifier.
399
+ /// @return namespace Decoded label namespace.
400
+ /// @return name Decoded label text.
401
+ function unpackLabel(Cur memory cur) internal pure returns (uint id, bytes32 namespace, string memory name) {
402
+ uint abs = cur.state.absolute();
403
+ uint end;
404
+ (id, namespace, name, end) = Blocks.unpackLabel(abs);
405
+ cur.state = cur.state.seekAbs(end);
406
+ }
407
+
408
+ /// @notice Decode and consume one SCHEMA block.
409
+ /// @param cur Cursor advanced past the block.
410
+ /// @return spec Decoded block specification.
411
+ /// @return body Decoded schema body.
412
+ /// @return name Decoded schema name.
413
+ function unpackSchema(Cur memory cur) internal pure returns (uint spec, string memory body, bytes32 name) {
414
+ uint abs = cur.state.absolute();
415
+ uint end;
416
+ (spec, body, name, end) = Blocks.unpackSchema(abs);
417
+ cur.state = cur.state.seekAbs(end);
418
+ }
419
+
420
+ /// @notice Decode and consume one RECOVER block.
421
+ /// @param cur Cursor advanced past the block.
422
+ /// @return handler Decoded recovery handler.
423
+ /// @return resources Decoded packed resources.
424
+ /// @return key Decoded recovery key.
425
+ /// @return witness Decoded recovery witness.
426
+ function unpackRecover(
427
+ Cur memory cur
428
+ ) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness) {
429
+ uint abs = cur.state.absolute();
430
+ uint end;
431
+ (handler, resources, key, witness, end) = Blocks.unpackRecover(abs);
432
+ cur.state = cur.state.seekAbs(end);
433
+ }
434
+
435
+ // -------------------------------------------------------------------------
436
+ // Additional semantic block decoding
437
+ // -------------------------------------------------------------------------
438
+
439
+ /// @notice Decode one ACCOUNT_ASSET block into its structured value.
440
+ /// @param cur Cursor advanced past the block.
441
+ /// @return value Structured account and asset.
442
+ function unpackAccountAssetValue(Cur memory cur) internal pure returns (AccountAsset memory value) {
443
+ (value.account, value.asset) = unpackAccountAsset(cur);
444
+ }
445
+
446
+ /// @notice Decode one AMOUNT block into its structured value.
447
+ /// @param cur Cursor advanced past the block.
448
+ /// @return value Structured asset amount.
449
+ function unpackAmountValue(Cur memory cur) internal pure returns (AssetAmount memory value) {
450
+ (value.asset, value.amount) = unpackAmount(cur);
451
+ }
452
+
453
+ /// @notice Decode one BALANCE block into its structured value.
454
+ /// @param cur Cursor advanced past the block.
455
+ /// @return value Structured asset balance.
456
+ function unpackBalanceValue(Cur memory cur) internal pure returns (AssetAmount memory value) {
457
+ (value.asset, value.amount) = unpackBalance(cur);
458
+ }
459
+
460
+ /// @notice Decode and consume one HOST_ACCOUNT_ASSET block.
461
+ /// @param cur Cursor advanced past the block.
462
+ /// @return host Decoded host identifier.
463
+ /// @return account Decoded account identifier.
464
+ /// @return asset Decoded asset identifier.
465
+ function unpackHostAccountAsset(
466
+ Cur memory cur
467
+ ) internal pure returns (uint host, bytes32 account, bytes32 asset) {
468
+ uint abs;
469
+ (cur.state, abs) = cur.state.consume(Sizes.B96);
470
+ (host, account, asset) = Blocks.unpackHostAccountAsset(abs);
471
+ }
472
+
473
+ /// @notice Decode one HOST_ACCOUNT_ASSET block into its structured value.
474
+ /// @param cur Cursor advanced past the block.
475
+ /// @return value Structured host, account, and asset.
476
+ function unpackHostAccountAssetValue(Cur memory cur) internal pure returns (HostAccountAsset memory value) {
477
+ (value.host, value.account, value.asset) = unpackHostAccountAsset(cur);
478
+ }
479
+
480
+ /// @notice Decode one ACCOUNT_AMOUNT block into its structured value.
481
+ /// @param cur Cursor advanced past the block.
482
+ /// @return value Structured account amount.
483
+ function unpackAccountAmountValue(Cur memory cur) internal pure returns (AccountAmount memory value) {
484
+ (value.account, value.asset, value.amount) = unpackAccountAmount(cur);
485
+ }
486
+
487
+ /// @notice Decode and consume one ALLOCATION block.
488
+ /// @param cur Cursor advanced past the block.
489
+ /// @return host Decoded host identifier.
490
+ /// @return asset Decoded asset identifier.
491
+ /// @return amount Decoded allocation.
492
+ function unpackAllocation(Cur memory cur) internal pure returns (uint host, bytes32 asset, uint amount) {
493
+ uint abs;
494
+ (cur.state, abs) = cur.state.consume(Sizes.B96);
495
+ (host, asset, amount) = Blocks.unpackAllocation(abs);
496
+ }
497
+
498
+ /// @notice Decode one ALLOWANCE block into its structured value.
499
+ /// @param cur Cursor advanced past the block.
500
+ /// @return value Structured allowance.
501
+ function unpackAllowanceValue(Cur memory cur) internal pure returns (HostAmount memory value) {
502
+ (value.host, value.asset, value.amount) = unpackAllowance(cur);
503
+ }
504
+
505
+ /// @notice Decode and consume one CUSTODY block.
506
+ /// @param cur Cursor advanced past the block.
507
+ /// @return host Decoded host identifier.
508
+ /// @return asset Decoded asset identifier.
509
+ /// @return amount Decoded custody amount.
510
+ function unpackCustody(Cur memory cur) internal pure returns (uint host, bytes32 asset, uint amount) {
511
+ uint abs;
512
+ (cur.state, abs) = cur.state.consume(Sizes.B96);
513
+ (host, asset, amount) = Blocks.unpackCustody(abs);
514
+ }
515
+
516
+ /// @notice Decode one CUSTODY block into its structured value.
517
+ /// @param cur Cursor advanced past the block.
518
+ /// @return value Structured custody amount.
519
+ function unpackCustodyValue(Cur memory cur) internal pure returns (HostAmount memory value) {
520
+ (value.host, value.asset, value.amount) = unpackCustody(cur);
521
+ }
522
+
523
+ /// @notice Decode one TRANSACTION block into its structured value.
524
+ /// @param cur Cursor advanced past the block.
525
+ /// @return value Structured transaction.
526
+ function unpackTransactionValue(Cur memory cur) internal pure returns (Tx memory value) {
527
+ (value.from, value.to, value.asset, value.amount) = unpackTransaction(cur);
528
+ }
529
+
530
+ /// @notice Decode and consume one STEP block.
531
+ /// @param cur Cursor advanced past the block.
532
+ /// @return cmd Decoded command identifier.
533
+ /// @return resources Decoded packed resources.
534
+ /// @return input Decoded command input.
535
+ function unpackStep(
536
+ Cur memory cur
537
+ ) internal pure returns (uint cmd, uint resources, bytes calldata input) {
538
+ uint abs = cur.state.absolute();
539
+ uint end;
540
+ (cmd, resources, input, end) = Blocks.unpackStep(abs);
541
+ cur.state = cur.state.seekAbs(end);
542
+ }
543
+
544
+ /// @notice Decode and consume one RELAY block.
545
+ /// @param cur Cursor advanced past the block.
546
+ /// @return portal Decoded destination portal.
547
+ /// @return resources Decoded packed resources.
548
+ /// @return input Decoded relay input.
549
+ function unpackRelay(
550
+ Cur memory cur
551
+ ) internal pure returns (uint portal, uint resources, bytes calldata input) {
552
+ uint abs = cur.state.absolute();
553
+ uint end;
554
+ (portal, resources, input, end) = Blocks.unpackRelay(abs);
555
+ cur.state = cur.state.seekAbs(end);
556
+ }
557
+
558
+ }
@@ -0,0 +1,124 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {Specs} from "./Specs.sol";
5
+ import {Lanes} from "../utils/Lanes.sol";
6
+
7
+ /// @title Descriptors
8
+ /// @notice Packing and lane metadata helpers for endpoint descriptors.
9
+ library Descriptors {
10
+ /// @dev The requested lane is not part of an endpoint descriptor.
11
+ error InvalidLane();
12
+
13
+ /// @dev Endpoint accepts nonzero native value.
14
+ uint8 internal constant Funded = 1 << 0;
15
+ /// @dev Endpoint is restricted to the admin account.
16
+ uint8 internal constant Admin = 1 << 1;
17
+
18
+ /// @notice Create a descriptor from endpoint lane specifications and flags.
19
+ /// @dev Layout: `[state key:4][stride:1]`
20
+ /// `[input key:4][item:4][stride:1]`
21
+ /// `[output key:4][min:4][max:4][hint:3][stride:1]`
22
+ /// `[transactions:1]`
23
+ /// `[flags:1]`. Flag bits: funded = 0, admin = 1.
24
+ /// @param state State lane specification.
25
+ /// @param input Input lane specification, optionally wrapped in a container.
26
+ /// @param output Output writer specification.
27
+ /// @param transactions Transactions produced per batch.
28
+ /// @param flags Endpoint behavior flags.
29
+ /// @return descriptor Packed endpoint descriptor.
30
+ function create(
31
+ uint state,
32
+ uint input,
33
+ uint output,
34
+ uint8 transactions,
35
+ uint8 flags
36
+ ) internal pure returns (uint descriptor) {
37
+ state = Specs.normalize(state, true);
38
+ input = Specs.normalize(input, false);
39
+ output = Specs.normalize(output, true);
40
+
41
+ descriptor = pack(state, input, output, transactions, flags);
42
+ }
43
+
44
+ /// @dev Pack normalized endpoint specs and flags into a descriptor.
45
+ /// @param state Normalized direct state specification.
46
+ /// @param input Normalized input specification.
47
+ /// @param output Normalized direct output specification.
48
+ /// @param transactions Transactions produced per batch.
49
+ /// @param flags Endpoint behavior flags.
50
+ /// @return descriptor Packed endpoint descriptor.
51
+ function pack(
52
+ uint state,
53
+ uint input,
54
+ uint output,
55
+ uint8 transactions,
56
+ uint8 flags
57
+ ) private pure returns (uint descriptor) {
58
+ (bytes4 outer, bytes4 child) = Specs.keys(input);
59
+
60
+ descriptor |= uint(uint32(Specs.key(state))) << 224;
61
+ descriptor |= uint(Specs.stride(state)) << 216;
62
+ descriptor |= uint(uint32(outer)) << 184;
63
+ descriptor |= uint(uint32(child)) << 152;
64
+ descriptor |= uint(Specs.stride(input)) << 144;
65
+ descriptor |= (output >> 128) << 16;
66
+ descriptor |= uint(transactions) << 8;
67
+ descriptor |= flags;
68
+ }
69
+
70
+ /// @notice Return whether a descriptor contains `flag`.
71
+ /// @param descriptor Packed endpoint descriptor.
72
+ /// @param flag Flag bit or bit set to test.
73
+ /// @return Whether any requested flag bit is present.
74
+ function flagged(uint descriptor, uint8 flag) internal pure returns (bool) {
75
+ return uint8(descriptor) & flag != 0;
76
+ }
77
+
78
+ /// @notice Return the effective per-batch stride for `lane`.
79
+ /// @dev Descriptor creation resolves implicit spec strides, so every lane
80
+ /// stores its effective value directly.
81
+ /// @param descriptor Packed endpoint descriptor.
82
+ /// @param lane Lane identifier from `Lanes`.
83
+ /// @return Effective blocks per batch for the lane.
84
+ function stride(uint descriptor, uint8 lane) internal pure returns (uint8) {
85
+ if (lane == Lanes.State) return uint8(descriptor >> 216);
86
+ if (lane == Lanes.Input) return uint8(descriptor >> 144);
87
+ if (lane == Lanes.Output) return uint8(descriptor >> 16);
88
+ if (lane == Lanes.Transactions) return uint8(descriptor >> 8);
89
+ revert InvalidLane();
90
+ }
91
+
92
+ /// @notice Return the effective block key for `lane`.
93
+ /// @dev Input returns its outer key. Transaction blocks have a fixed
94
+ /// protocol key that is not stored in the descriptor.
95
+ /// @param descriptor Packed endpoint descriptor.
96
+ /// @param lane Lane identifier from `Lanes`.
97
+ /// @return Effective outer block key for the lane.
98
+ function key(uint descriptor, uint8 lane) internal pure returns (bytes4) {
99
+ if (lane == Lanes.State) return bytes4(uint32(descriptor >> 224));
100
+ if (lane == Lanes.Input) return bytes4(uint32(descriptor >> 184));
101
+ if (lane == Lanes.Output) return bytes4(uint32(descriptor >> 112));
102
+ if (lane == Lanes.Transactions) return Specs.key(Specs.Transaction);
103
+ revert InvalidLane();
104
+ }
105
+
106
+ /// @notice Return the buffer configuration for descriptor writer `lane`.
107
+ /// @param descriptor Packed endpoint descriptor.
108
+ /// @param lane Output or transaction writer lane.
109
+ /// @param groups Number of execution batches to allocate for.
110
+ /// @return capacity Initial logical byte capacity.
111
+ /// @return growable Whether the writer may grow beyond that capacity.
112
+ function allocation(uint descriptor, uint8 lane, uint groups) internal pure returns (uint capacity, bool growable) {
113
+ if (lane == Lanes.Output) {
114
+ uint spec = uint(uint128(descriptor >> 16)) << 128;
115
+ return Specs.allocation(spec, groups);
116
+ }
117
+ if (lane == Lanes.Transactions) {
118
+ uint count = groups * stride(descriptor, lane);
119
+ return Specs.allocation(Specs.Transaction, count);
120
+ }
121
+
122
+ revert InvalidLane();
123
+ }
124
+ }