@rootzero/contracts 1.13.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 (73) hide show
  1. package/CHANGELOG.md +45 -3
  2. package/Codec.sol +21 -0
  3. package/Commands.sol +14 -0
  4. package/Core.sol +2 -3
  5. package/Endpoints.sol +1 -5
  6. package/README.md +34 -30
  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 -16
  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 +21 -20
  18. package/commands/Base.sol +71 -37
  19. package/commands/Burn.sol +18 -13
  20. package/commands/Credit.sol +21 -20
  21. package/commands/Debit.sol +25 -28
  22. package/commands/Deposit.sol +34 -35
  23. package/commands/Payout.sol +21 -15
  24. package/commands/Provision.sol +37 -38
  25. package/commands/Recover.sol +20 -19
  26. package/commands/Relay.sol +24 -22
  27. package/commands/Withdraw.sol +15 -18
  28. package/commands/admin/AllowAssets.sol +19 -16
  29. package/commands/admin/Allowance.sol +18 -13
  30. package/commands/admin/Appoint.sol +17 -15
  31. package/commands/admin/Authorize.sol +23 -14
  32. package/commands/admin/Base.sol +1 -1
  33. package/commands/admin/DenyAssets.sol +19 -16
  34. package/commands/admin/Dismiss.sol +17 -15
  35. package/commands/admin/Execute.sol +20 -19
  36. package/commands/admin/Label.sol +17 -13
  37. package/commands/admin/Schemas.sol +18 -14
  38. package/commands/admin/Unauthorize.sol +23 -14
  39. package/core/Calls.sol +3 -11
  40. package/core/Endpoint.sol +42 -127
  41. package/core/Pipeline.sol +16 -15
  42. package/core/Types.sol +1 -1
  43. package/docs/Schema.md +35 -29
  44. package/events/Endpoint.sol +2 -2
  45. package/events/Schema.sol +5 -5
  46. package/execution/Budget.sol +40 -0
  47. package/execution/Execution.sol +1083 -0
  48. package/guards/Base.sol +8 -9
  49. package/guards/Revoke.sol +11 -9
  50. package/package.json +1 -1
  51. package/ports/AllowAssets.sol +12 -15
  52. package/ports/Allowance.sol +11 -9
  53. package/ports/Base.sol +18 -11
  54. package/ports/Credit.sol +11 -9
  55. package/ports/Debit.sol +11 -9
  56. package/ports/DenyAssets.sol +10 -13
  57. package/ports/Dispatch.sol +13 -15
  58. package/ports/Pipe.sol +14 -12
  59. package/ports/Redeem.sol +12 -9
  60. package/ports/Settle.sol +11 -9
  61. package/queries/Assets.sol +15 -15
  62. package/queries/Balances.sol +17 -17
  63. package/queries/Base.sol +11 -12
  64. package/utils/Actions.sol +1 -0
  65. package/utils/Cursors.sol +308 -0
  66. package/utils/Lanes.sol +14 -0
  67. package/utils/Selectors.sol +2 -2
  68. package/utils/Utils.sol +46 -0
  69. package/Cursors.sol +0 -16
  70. package/blocks/Cursors.sol +0 -1529
  71. package/blocks/Writers.sol +0 -1036
  72. package/core/Payable.sol +0 -53
  73. package/utils/Value.sol +0 -43
@@ -1,1529 +0,0 @@
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 {Sizes} from "./Schema.sol";
6
- import {Keys} from "./Keys.sol";
7
-
8
- /// @notice Zero-copy view into a calldata block stream.
9
- /// All positions (`i`) are byte offsets relative to the start of the source region.
10
- /// The absolute calldata location of byte `i` is `offset + i`.
11
- struct Cur {
12
- /// @dev Absolute calldata byte offset of the source region start.
13
- uint offset;
14
- /// @dev Current read position, relative to the source start.
15
- uint i;
16
- /// @dev Total byte length of the source region.
17
- uint len;
18
- }
19
-
20
- /// @notice Mutable reader over a block stream stored in memory.
21
- /// All positions (`i`) are byte offsets relative to the start of `source`.
22
- struct Reader {
23
- /// @dev Current read position, relative to the source start.
24
- uint i;
25
- /// @dev Memory bytes containing the complete source region.
26
- bytes source;
27
- }
28
-
29
- using Cursors for Cur;
30
- using Readers for Reader;
31
-
32
- /// @title Readers
33
- /// @notice Memory block stream parser for the rootzero protocol.
34
- /// A `Reader` advances through an existing `bytes memory` source without copying its contents.
35
- /// Blocks are encoded as `[bytes4 key][bytes4 payloadLen][payload]`.
36
- library Readers {
37
- /// @dev The current block has a truncated header or payload, an unexpected key,
38
- /// or a payload size outside the accepted range.
39
- error InvalidBlock();
40
-
41
- /// @notice Create a reader backed by a memory byte array.
42
- /// @param source Memory bytes containing the block stream.
43
- /// @return cur Reader positioned at the beginning of `source`.
44
- function open(bytes memory source) internal pure returns (Reader memory cur) {
45
- cur.source = source;
46
- }
47
-
48
- /// @notice Return whether the reader has consumed its entire source.
49
- /// @param cur Reader whose position should be checked.
50
- /// @return Whether `cur.i` equals the source length.
51
- function done(Reader memory cur) internal pure returns (bool) {
52
- return cur.i == cur.source.length;
53
- }
54
-
55
- /// @notice Return whether the reader has bytes left to consume.
56
- /// @param cur Reader whose position should be checked.
57
- /// @return Whether `cur.i` differs from the source length.
58
- function more(Reader memory cur) internal pure returns (bool) {
59
- return cur.i != cur.source.length;
60
- }
61
-
62
- /// @notice Validate and consume the current block, advancing `cur.i` past it.
63
- /// @param cur Reader to advance.
64
- /// @param key Expected block key.
65
- /// @param min Minimum payload length.
66
- /// @param max Maximum payload length; zero means unbounded.
67
- /// @return abs Absolute memory address of the payload start.
68
- function consume(
69
- Reader memory cur,
70
- bytes4 key,
71
- uint min,
72
- uint max
73
- ) internal pure returns (uint abs) {
74
- bytes memory source = cur.source;
75
- uint i = cur.i;
76
-
77
- if (i > source.length || source.length - i < Sizes.Header) revert InvalidBlock();
78
-
79
- bytes4 current;
80
- uint len;
81
- assembly ("memory-safe") {
82
- let header := mload(add(add(source, 0x20), i))
83
- current := header
84
- len := and(shr(192, header), 0xffffffff)
85
- abs := add(add(source, 0x28), i)
86
- }
87
-
88
- if (current != key || len < min || (max != 0 && len > max)) revert InvalidBlock();
89
- if (len > source.length - i - Sizes.Header) revert InvalidBlock();
90
- cur.i = i + Sizes.Header + len;
91
- }
92
-
93
- /// @notice Consume a BALANCE block and return its fields.
94
- /// @param cur Reader; advanced past the block.
95
- /// @return asset Asset identifier.
96
- /// @return amount Token amount.
97
- function unpackBalance(Reader memory cur) internal pure returns (bytes32 asset, uint amount) {
98
- uint abs = consume(cur, Keys.Balance, 64, 64);
99
- assembly ("memory-safe") {
100
- asset := mload(abs)
101
- amount := mload(add(abs, 0x20))
102
- }
103
- }
104
-
105
- /// @notice Consume a TRANSACTION block and return its fields.
106
- /// @param cur Reader; advanced past the block.
107
- /// @return from Source account identifier.
108
- /// @return to Destination account identifier.
109
- /// @return asset Asset identifier.
110
- /// @return amount Token amount.
111
- function unpackTransaction(
112
- Reader memory cur
113
- ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
114
- uint abs = consume(cur, Keys.Transaction, 128, 128);
115
- assembly ("memory-safe") {
116
- from := mload(abs)
117
- to := mload(add(abs, 0x20))
118
- asset := mload(add(abs, 0x40))
119
- amount := mload(add(abs, 0x60))
120
- }
121
- }
122
- }
123
-
124
- /// @title Cursors
125
- /// @notice Calldata block stream parser for the rootzero protocol.
126
- /// A `Cur` is a lightweight view into a slice of `msg.data`; no data is copied.
127
- /// Blocks are encoded as `[bytes4 key][bytes4 payloadLen][payload]`.
128
- library Cursors {
129
- /// @dev Source region contains a block whose declared length exceeds the region boundary,
130
- /// or a header read would go out of bounds.
131
- error MalformedBlocks();
132
- /// @dev Current block key does not match the expected key, or payload size is out of range.
133
- error InvalidBlock();
134
- /// @dev `complete` called but the cursor has not consumed exactly to `len`.
135
- error IncompleteCursor();
136
- /// @dev `run` found zero blocks of the expected key; the cursor region is empty.
137
- error ZeroCursor();
138
- /// @dev `run` was called with a zero group size.
139
- error ZeroGroup();
140
- /// @dev An account field was required but the block or fallback was zero.
141
- error ZeroAccount();
142
- /// @dev A node field was required but the block or fallback was zero.
143
- error ZeroNode();
144
- /// @dev A field value did not match the expected value.
145
- error UnexpectedValue();
146
- /// @dev Prime block counts are not divisible by, or do not match, their declared group sizes.
147
- error BadRatio();
148
-
149
- // -------------------------------------------------------------------------
150
- // Cursor construction and navigation
151
- // -------------------------------------------------------------------------
152
-
153
- /// @notice Create a cursor backed by a calldata slice.
154
- /// @param source Calldata slice that forms the block stream.
155
- /// @return cur Cursor positioned at the beginning of `source`.
156
- function open(bytes calldata source) internal pure returns (Cur memory cur) {
157
- uint offset;
158
- // Extract the absolute calldata offset of `source` using inline assembly,
159
- // as Solidity does not expose this directly for calldata slices.
160
- assembly ("memory-safe") {
161
- offset := source.offset
162
- }
163
- cur.offset = offset;
164
- cur.len = source.length;
165
- }
166
-
167
- /// @notice Create a cursor backed by `source[i:]`.
168
- /// @param source Calldata slice that forms the parent block stream.
169
- /// @param i Start byte offset within `source`.
170
- /// @return cur Cursor positioned at the beginning of `source[i:]`.
171
- function open(bytes calldata source, uint i) internal pure returns (Cur memory cur) {
172
- return open(source[i:]);
173
- }
174
-
175
- /// @notice Create a cursor over `source` and restrict it to its first grouped run.
176
- /// Equivalent to `open(source)`, reading the current key, then `run(key, group)`.
177
- /// When `group` is zero, `source` must be empty and the function returns an empty cursor.
178
- /// @param source Calldata slice that forms the block stream.
179
- /// @param group Expected block group size (e.g. 1 for single, 2 for paired); 0 means empty.
180
- /// @return cur Cursor with `len` truncated to the end of the first run in `source`.
181
- /// @return groups Number of block groups in the run (`block count / group`).
182
- function init(bytes calldata source, uint group) internal pure returns (Cur memory cur, uint groups) {
183
- cur = open(source);
184
- if (group == 0) {
185
- if (cur.len != 0) revert IncompleteCursor();
186
- return (cur, 0);
187
- }
188
- if (cur.len == 0) revert ZeroCursor();
189
- (bytes4 key, ) = cur.peek(cur.i);
190
- groups = cur.run(key, group);
191
- }
192
-
193
- /// @notice Move the cursor to an absolute position within the source region.
194
- /// @param cur Cursor to update.
195
- /// @param i New read position (byte offset relative to source start).
196
- /// @return Updated cursor with `cur.i == i`.
197
- function seek(Cur memory cur, uint i) internal pure returns (Cur memory) {
198
- if (i > cur.len) revert MalformedBlocks();
199
- cur.i = i;
200
- return cur;
201
- }
202
-
203
- /// @notice Advance the cursor by `n` bytes within the source region.
204
- /// Reverts with `IncompleteCursor` if `n` exceeds the remaining cursor region length.
205
- /// @param cur Cursor to advance.
206
- /// @param n Number of bytes to skip from the current read position.
207
- function skip(Cur memory cur, uint n) internal pure returns (Cur memory) {
208
- if (n > cur.len - cur.i) revert IncompleteCursor();
209
- cur.i += n;
210
- return cur;
211
- }
212
-
213
- /// @notice Advance the cursor to a later absolute position within the source region.
214
- /// Reverts with `IncompleteCursor` if `i` exceeds the cursor region length or is before `cur.i`.
215
- /// @param cur Cursor to advance.
216
- /// @param i New read position (byte offset relative to source start).
217
- function skipTo(Cur memory cur, uint i) internal pure returns (Cur memory) {
218
- if (i > cur.len || cur.i > i) revert IncompleteCursor();
219
- cur.i = i;
220
- return cur;
221
- }
222
-
223
- /// @notice Create a subcursor over the half-open range `[from, to)` within the source region.
224
- /// The returned cursor starts at position zero within that sliced region.
225
- /// @param cur Source cursor.
226
- /// @param from Start byte offset within the source region (inclusive).
227
- /// @param to End byte offset within the source region (exclusive).
228
- /// @return out Cursor scoped to the requested sub-range.
229
- function slice(Cur memory cur, uint from, uint to) internal pure returns (Cur memory out) {
230
- if (from > to || to > cur.len) revert MalformedBlocks();
231
- out.offset = cur.offset + from;
232
- out.len = to - from;
233
- }
234
-
235
- /// @notice Return the full cursor region as a calldata slice.
236
- /// Does not advance the cursor; `cur.i` is ignored.
237
- /// @param cur Cursor whose backing region should be returned.
238
- /// @return data Calldata view over `[cur.offset, cur.offset + cur.len)`.
239
- function raw(Cur memory cur) internal pure returns (bytes calldata data) {
240
- if (cur.len > msg.data.length || cur.offset > msg.data.length - cur.len) revert MalformedBlocks();
241
- data = msg.data[cur.offset:cur.offset + cur.len];
242
- }
243
-
244
- /// @notice Return a sub-range of the cursor region as a calldata slice.
245
- /// Does not advance the cursor; `cur.i` is ignored.
246
- /// @param cur Source cursor.
247
- /// @param from Start byte offset within the source region (inclusive).
248
- /// @param to End byte offset within the source region (exclusive).
249
- /// @return data Calldata view over the requested sub-range.
250
- function raw(Cur memory cur, uint from, uint to) internal pure returns (bytes calldata data) {
251
- if (from > to || to > cur.len) revert MalformedBlocks();
252
- if (cur.len > msg.data.length || cur.offset > msg.data.length - cur.len) revert MalformedBlocks();
253
- data = msg.data[cur.offset + from:cur.offset + to];
254
- }
255
-
256
- /// @notice Hash a sub-range of the cursor region.
257
- /// Does not advance the cursor; `from` and `to` are relative to the source region.
258
- /// @param cur Source cursor.
259
- /// @param from Start byte offset within the source region (inclusive).
260
- /// @param to End byte offset within the source region (exclusive).
261
- /// @return digest Keccak256 hash of the requested sub-range.
262
- function hash(Cur memory cur, uint from, uint to) internal pure returns (bytes32 digest) {
263
- digest = keccak256(cur.raw(from, to));
264
- }
265
-
266
- /// @notice Read a block header at position `i` without advancing the cursor.
267
- /// @param cur Source cursor.
268
- /// @param i Byte offset of the block header within the source region.
269
- /// @return key Four-byte block type identifier.
270
- /// @return len Payload byte length declared in the header.
271
- function peek(Cur memory cur, uint i) internal pure returns (bytes4 key, uint len) {
272
- if (i + Sizes.Header > cur.len) revert MalformedBlocks();
273
- uint abs = cur.offset + i;
274
- key = bytes4(msg.data[abs:abs + 4]);
275
- len = uint32(bytes4(msg.data[abs + 4:abs + 8]));
276
- if (i + Sizes.Header + len > cur.len) revert MalformedBlocks();
277
- }
278
-
279
- /// @notice Return the byte offset immediately past the block at the current cursor position.
280
- /// Does not advance the cursor.
281
- /// @param cur Source cursor.
282
- /// @return Byte offset immediately past the current block, relative to the source region.
283
- function past(Cur memory cur) internal pure returns (uint) {
284
- (, uint len) = peek(cur, cur.i);
285
- return cur.i + Sizes.Header + len;
286
- }
287
-
288
- /// @notice Return true if position `i` is at a block header with the given key.
289
- /// Returns false when `i` is out of bounds or the key differs.
290
- /// @param cur Source cursor.
291
- /// @param i Byte offset of the block header within the source region.
292
- /// @param key Expected block type identifier.
293
- /// @return Whether the block header at `i` uses `key`.
294
- function hasAt(Cur memory cur, uint i, bytes4 key) internal pure returns (bool) {
295
- if (i > cur.len || Sizes.Header > cur.len - i) return false;
296
- uint abs = cur.offset + i;
297
- return bytes4(msg.data[abs:abs + 4]) == key;
298
- }
299
-
300
- /// @notice Return true if the current cursor position is at a block header with the given key.
301
- /// Returns false when `cur.i` is out of bounds or the key differs.
302
- /// @param cur Source cursor.
303
- /// @param key Expected block type identifier.
304
- /// @return Whether the block header at `cur.i` uses `key`.
305
- function isAt(Cur memory cur, bytes4 key) internal pure returns (bool) {
306
- return cur.hasAt(cur.i, key);
307
- }
308
-
309
- /// @notice Enter a block at the current position and return its next offset.
310
- /// Advances `cur.i` past the block header so the payload can be parsed
311
- /// directly from the same cursor. The returned `next` is the byte offset
312
- /// immediately after the block payload, relative to the current cursor region.
313
- /// @param cur Cursor positioned at the expected block; advanced past the 8-byte header.
314
- /// @param key Expected block key.
315
- /// @param min Minimum acceptable payload length.
316
- /// @param max Maximum acceptable payload length; 0 means unbounded.
317
- /// @return next Byte offset immediately after the block payload.
318
- function enter(Cur memory cur, bytes4 key, uint min, uint max) internal pure returns (uint next) {
319
- (bytes4 current, uint len) = peek(cur, cur.i);
320
- if (current != key) revert InvalidBlock();
321
- if (len < min || (max != 0 && len > max)) revert InvalidBlock();
322
- next = cur.i + Sizes.Header + len;
323
- cur.i += Sizes.Header;
324
- }
325
-
326
- /// @notice Validate a block at position `i` and return its payload location.
327
- /// Does not advance the cursor.
328
- /// @param cur Source cursor.
329
- /// @param i Byte offset of the block within the source region.
330
- /// @param end Required next offset after the block; 0 means no exact-end check.
331
- /// @param key Expected block type key; reverts if actual key differs.
332
- /// @param min Minimum acceptable payload length (inclusive).
333
- /// @param max Maximum acceptable payload length (inclusive); 0 means unbounded.
334
- /// @return abs Absolute calldata offset of the payload start.
335
- /// @return next Byte offset of the block immediately following this one (relative to source start).
336
- function expect(
337
- Cur memory cur,
338
- uint i,
339
- uint end,
340
- bytes4 key,
341
- uint min,
342
- uint max
343
- ) internal pure returns (uint abs, uint next) {
344
- (bytes4 current, uint len) = peek(cur, i);
345
- if (current != key) revert InvalidBlock();
346
- if (len < min || (max != 0 && len > max)) revert InvalidBlock();
347
- abs = cur.offset + i + Sizes.Header;
348
- next = i + Sizes.Header + len;
349
- if (end != 0 && next != end) revert IncompleteCursor();
350
- }
351
-
352
- /// @notice Validate and consume the current block, advancing `cur.i` past it.
353
- /// @param cur Cursor to advance.
354
- /// @param end Required next offset after the block; 0 means no exact-end check.
355
- /// @param key Expected block type key.
356
- /// @param min Minimum payload length.
357
- /// @param max Maximum payload length (0 = unbounded).
358
- /// @return abs Absolute calldata offset of the payload start.
359
- function consume(Cur memory cur, uint end, bytes4 key, uint min, uint max) internal pure returns (uint abs) {
360
- uint next;
361
- (abs, next) = expect(cur, cur.i, end, key, min, max);
362
- cur.i = next;
363
- }
364
-
365
- /// @notice Count consecutive blocks of the same key starting at `i`.
366
- /// @param cur Source cursor.
367
- /// @param i Starting byte offset within the source region.
368
- /// @param key Block type to count.
369
- /// @return total Number of consecutive matching blocks.
370
- /// @return next Byte offset immediately after the last counted block.
371
- function countRun(Cur memory cur, uint i, bytes4 key) internal pure returns (uint total, uint next) {
372
- next = i;
373
- while (next < cur.len) {
374
- (bytes4 current, uint len) = peek(cur, next);
375
- if (current != key) break;
376
- next += Sizes.Header + len;
377
-
378
- unchecked {
379
- ++total;
380
- }
381
- }
382
- }
383
-
384
- /// @notice Restrict the cursor to the consecutive run of `key` at its current position.
385
- /// Counts the run, truncates `cur.len` to the run end, and validates that the
386
- /// count is a multiple of `group`.
387
- /// @param cur Cursor to restrict; `cur.len` is updated in place.
388
- /// @param key Expected block type identifier of the run.
389
- /// @param group Expected group size (e.g. 1 for single-asset, 2 for paired input/output).
390
- /// @return groups Number of groups represented by the run (`block count / group`).
391
- function run(Cur memory cur, bytes4 key, uint group) internal pure returns (uint groups) {
392
- if (group == 0) revert ZeroGroup();
393
- (uint count, uint next) = countRun(cur, cur.i, key);
394
- if (count == 0) revert ZeroCursor();
395
- if (count % group != 0) revert BadRatio();
396
- cur.len = next;
397
- groups = count / group;
398
- }
399
-
400
- /// @notice Scan forward from `i` for the first block matching `key`.
401
- /// @param cur Source cursor.
402
- /// @param i Starting byte offset for the search.
403
- /// @param key Block type to find.
404
- /// @return Byte offset of the matching block, or `cur.len` if not found.
405
- function find(Cur memory cur, uint i, bytes4 key) internal pure returns (uint) {
406
- while (i < cur.len) {
407
- (bytes4 current, uint len) = peek(cur, i);
408
- if (current == key) return i;
409
- i += Sizes.Header + len;
410
- }
411
- return cur.len;
412
- }
413
-
414
- /// @notice Scan forward from the current position for the first block matching `key`.
415
- /// @param cur Source cursor.
416
- /// @param key Block type to find.
417
- /// @return Byte offset of the matching block, or `cur.len` if not found.
418
- function find(Cur memory cur, bytes4 key) internal pure returns (uint) {
419
- return find(cur, cur.i, key);
420
- }
421
-
422
- /// @notice Consume a LIST block and return a cursor over its payload.
423
- /// Advances `cur.i` past the full list while the returned cursor is scoped to
424
- /// the list members as a fresh zero-based region.
425
- /// @param cur Cursor positioned at a list block; advanced past the full list.
426
- /// @return items Cursor scoped to the list payload.
427
- function list(Cur memory cur) internal pure returns (Cur memory items) {
428
- uint next = enter(cur, Keys.List, 0, 0);
429
- items = cur.slice(cur.i, next);
430
- cur.i = next;
431
- }
432
-
433
- /// @notice Consume a block with the given key at the current position and return a cursor over the full block slice.
434
- /// Advances `cur.i` past the block while the returned cursor is scoped to the
435
- /// full block bytes as a fresh zero-based region.
436
- /// @param cur Cursor positioned at the expected block.
437
- /// @param key Expected block type key.
438
- /// @return out Cursor scoped to the full block.
439
- function take(Cur memory cur, bytes4 key) internal pure returns (Cur memory out) {
440
- (, uint next) = expect(cur, cur.i, 0, key, 0, 0);
441
- out = cur.slice(cur.i, next);
442
- cur.i = next;
443
- }
444
-
445
- /// @notice Return whether the remaining cursor region is empty or exactly one block with `key`.
446
- /// Returns false for an empty remaining region. Reverts if the next block has another key or
447
- /// if a matching block is followed by trailing bytes.
448
- /// @param cur Source cursor.
449
- /// @param key Expected optional block key.
450
- /// @return Whether the remaining region contains exactly one block with `key`.
451
- function maybeOnly(Cur memory cur, bytes4 key) internal pure returns (bool) {
452
- if (cur.i == cur.len) return false;
453
- if (!cur.isAt(key)) revert InvalidBlock();
454
- if (cur.past() != cur.len) revert IncompleteCursor();
455
- return true;
456
- }
457
-
458
- /// @notice Consume an optional block with the given key and return a cursor over the full block slice.
459
- /// If the current block key does not match, returns an empty cursor and leaves `cur.i` unchanged.
460
- /// Otherwise behaves like `take(cur, key)`.
461
- /// @param cur Cursor positioned at an optional block.
462
- /// @param key Optional block type key.
463
- /// @return out Cursor scoped to the full matching block, or empty when no matching block is present.
464
- function maybeTake(Cur memory cur, bytes4 key) internal pure returns (Cur memory out) {
465
- return cur.isAt(key) ? take(cur, key) : cur.slice(cur.i, cur.i);
466
- }
467
-
468
- /// @notice Ensure the cursor is at an exact position.
469
- /// Reverts with `IncompleteCursor` if `pos` exceeds the cursor region length
470
- /// or `cur.i != pos`.
471
- /// @param cur Cursor to check.
472
- /// @param pos Relative byte offset the cursor must be positioned at.
473
- function ensureAt(Cur memory cur, uint pos) internal pure {
474
- if (pos > cur.len || cur.i != pos) revert IncompleteCursor();
475
- }
476
-
477
- /// @notice Assert that the cursor has consumed its entire source region.
478
- /// Reverts with `IncompleteCursor` when `cur.i != cur.len`.
479
- /// @param cur Cursor to check.
480
- function complete(Cur memory cur) internal pure {
481
- if (cur.i != cur.len) revert IncompleteCursor();
482
- }
483
-
484
- // -------------------------------------------------------------------------
485
- // Block factory helpers
486
- // -------------------------------------------------------------------------
487
-
488
- /// @notice Encode a block with a raw payload.
489
- /// @param key Block type key.
490
- /// @param data Raw payload bytes.
491
- /// @return Encoded block bytes.
492
- function createBlock(bytes4 key, bytes memory data) internal pure returns (bytes memory) {
493
- return bytes.concat(key, bytes4(uint32(data.length)), data);
494
- }
495
-
496
- /// @notice Encode a block with a single 32-byte payload word.
497
- /// @param key Block type key.
498
- /// @param value 32-byte payload.
499
- /// @return Encoded block bytes.
500
- function createBlock32(bytes4 key, bytes32 value) internal pure returns (bytes memory) {
501
- return bytes.concat(key, bytes4(uint32(0x20)), value);
502
- }
503
-
504
- /// @notice Encode a block with two 32-byte payload words (64-byte payload).
505
- /// @param key Block type key.
506
- /// @param a First payload word.
507
- /// @param b Second payload word.
508
- /// @return Encoded block bytes.
509
- function createBlock64(bytes4 key, bytes32 a, bytes32 b) internal pure returns (bytes memory) {
510
- return bytes.concat(key, bytes4(uint32(0x40)), a, b);
511
- }
512
-
513
- /// @notice Encode a block with three 32-byte payload words (96-byte payload).
514
- /// @param key Block type key.
515
- /// @param a First payload word.
516
- /// @param b Second payload word.
517
- /// @param c Third payload word.
518
- /// @return Encoded block bytes.
519
- function createBlock96(bytes4 key, bytes32 a, bytes32 b, bytes32 c) internal pure returns (bytes memory) {
520
- return bytes.concat(key, bytes4(uint32(0x60)), a, b, c);
521
- }
522
-
523
- /// @notice Encode a block with four 32-byte payload words (128-byte payload).
524
- /// @param key Block type key.
525
- /// @param a First payload word.
526
- /// @param b Second payload word.
527
- /// @param c Third payload word.
528
- /// @param d Fourth payload word.
529
- /// @return Encoded block bytes.
530
- function createBlock128(
531
- bytes4 key,
532
- bytes32 a,
533
- bytes32 b,
534
- bytes32 c,
535
- bytes32 d
536
- ) internal pure returns (bytes memory) {
537
- return bytes.concat(key, bytes4(uint32(0x80)), a, b, c, d);
538
- }
539
-
540
- /// @notice Encode a block with five 32-byte payload words (160-byte payload).
541
- /// @param key Block type key.
542
- /// @param a First payload word.
543
- /// @param b Second payload word.
544
- /// @param c Third payload word.
545
- /// @param d Fourth payload word.
546
- /// @param e Fifth payload word.
547
- /// @return Encoded block bytes.
548
- function createBlock160(
549
- bytes4 key,
550
- bytes32 a,
551
- bytes32 b,
552
- bytes32 c,
553
- bytes32 d,
554
- bytes32 e
555
- ) internal pure returns (bytes memory) {
556
- return bytes.concat(key, bytes4(uint32(0xa0)), a, b, c, d, e);
557
- }
558
-
559
- /// @notice Encode a BYTES block with a raw payload.
560
- /// @param data Raw payload bytes.
561
- /// @return Encoded BYTES block bytes.
562
- function toBytesBlock(bytes memory data) internal pure returns (bytes memory) {
563
- return createBlock(Keys.Bytes, data);
564
- }
565
-
566
- /// @notice Encode a STRING block with a UTF-8 payload.
567
- /// @param data String payload.
568
- /// @return Encoded STRING block bytes.
569
- function toStringBlock(string memory data) internal pure returns (bytes memory) {
570
- return createBlock(Keys.String, bytes(data));
571
- }
572
-
573
- /// @notice Encode a BOUNTY block.
574
- /// @param bounty Relayer reward amount.
575
- /// @param relayer Relayer account identifier.
576
- /// @return Encoded BOUNTY block bytes.
577
- function toBountyBlock(uint bounty, bytes32 relayer) internal pure returns (bytes memory) {
578
- return createBlock64(Keys.Bounty, bytes32(bounty), relayer);
579
- }
580
-
581
- /// @notice Encode a BALANCE block.
582
- /// @param asset Asset identifier.
583
- /// @param amount Token amount.
584
- /// @return Encoded BALANCE block bytes.
585
- function toBalanceBlock(bytes32 asset, uint amount) internal pure returns (bytes memory) {
586
- return createBlock64(Keys.Balance, asset, bytes32(amount));
587
- }
588
-
589
- /// @notice Encode a CUSTODY block.
590
- /// @param host Host node ID holding the custody.
591
- /// @param asset Asset identifier.
592
- /// @param amount Token amount.
593
- /// @return Encoded CUSTODY block bytes.
594
- function toCustodyBlock(uint host, bytes32 asset, uint amount) internal pure returns (bytes memory) {
595
- return createBlock96(Keys.Custody, bytes32(host), asset, bytes32(amount));
596
- }
597
-
598
- /// @notice Encode a TRANSACTION block.
599
- /// @param from Source account identifier.
600
- /// @param to Destination account identifier.
601
- /// @param asset Asset identifier.
602
- /// @param amount Transfer amount.
603
- /// @return Encoded TRANSACTION block bytes.
604
- function toTransactionBlock(
605
- bytes32 from,
606
- bytes32 to,
607
- bytes32 asset,
608
- uint amount
609
- ) internal pure returns (bytes memory) {
610
- return createBlock128(Keys.Transaction, from, to, asset, bytes32(amount));
611
- }
612
-
613
- /// @notice Encode a STEP block.
614
- /// @param target Command target identifier.
615
- /// @param resources Packed resources assigned to the step.
616
- /// @param request Raw nested request payload.
617
- /// @return Encoded STEP block bytes.
618
- function toStepBlock(uint target, uint resources, bytes memory request) internal pure returns (bytes memory) {
619
- return createBlock(Keys.Step, bytes.concat(bytes32(target), bytes32(resources), toBytesBlock(request)));
620
- }
621
-
622
- /// @notice Encode a CALL block.
623
- /// @param target Target node identifier.
624
- /// @param resources Packed resources assigned to the call.
625
- /// @param data Raw calldata payload for the target.
626
- /// @return Encoded CALL block bytes.
627
- function toCallBlock(uint target, uint resources, bytes memory data) internal pure returns (bytes memory) {
628
- return createBlock(Keys.Call, bytes.concat(bytes32(target), bytes32(resources), toBytesBlock(data)));
629
- }
630
-
631
- /// @notice Encode a CONTEXT block.
632
- /// @param account Command account identifier.
633
- /// @param state Embedded state block stream.
634
- /// @param request Embedded request block stream.
635
- /// @return Encoded CONTEXT block bytes.
636
- function toContextBlock(
637
- bytes32 account,
638
- bytes memory state,
639
- bytes memory request
640
- ) internal pure returns (bytes memory) {
641
- return createBlock(Keys.Context, bytes.concat(account, toBytesBlock(state), toBytesBlock(request)));
642
- }
643
-
644
- /// @notice Encode a RELAY block.
645
- /// @param portal Destination portal identifier, often the destination host ID.
646
- /// @param resources Chain-specific resources for the destination context.
647
- /// @param request Nested request block stream.
648
- /// @return Encoded RELAY block bytes.
649
- function toRelayBlock(uint portal, uint resources, bytes memory request) internal pure returns (bytes memory) {
650
- return createBlock(Keys.Relay, bytes.concat(bytes32(portal), bytes32(resources), toBytesBlock(request)));
651
- }
652
-
653
- /// @notice Encode a DISPATCH block.
654
- /// @param portal Destination portal identifier, often the destination host ID.
655
- /// @param resources Chain-specific resources for the destination dispatch.
656
- /// @param payload Encoded payload.
657
- /// @return Encoded DISPATCH block bytes.
658
- function toDispatchBlock(uint portal, uint resources, bytes memory payload) internal pure returns (bytes memory) {
659
- return createBlock(Keys.Dispatch, bytes.concat(bytes32(portal), bytes32(resources), toBytesBlock(payload)));
660
- }
661
-
662
- // -------------------------------------------------------------------------
663
- // Raw calldata loaders
664
- // -------------------------------------------------------------------------
665
-
666
- /// @notice Read the next calldata word from the cursor and advance by `n` bytes.
667
- /// @dev Performs no bounds, key, length, or cursor checks. Always loads 32 bytes;
668
- /// callers may cast the returned word to `bytesN` when `n < 32`.
669
- /// @param cur Cursor whose current position is advanced by `n` bytes.
670
- /// @param n Number of bytes to advance.
671
- /// @return value Loaded word.
672
- function read(Cur memory cur, uint n) internal pure returns (bytes32 value) {
673
- uint abs = cur.offset + cur.i;
674
- assembly ("memory-safe") {
675
- value := calldataload(abs)
676
- }
677
- cur.i += n;
678
- }
679
-
680
- /// @notice Read the next byte from the cursor and advance by 1 byte.
681
- /// @dev Performs no bounds, key, length, or cursor checks.
682
- /// @param cur Cursor whose current position is advanced by 1 byte.
683
- /// @return value Loaded bytes1 value.
684
- function read1(Cur memory cur) internal pure returns (bytes1 value) {
685
- uint abs = cur.offset + cur.i;
686
- assembly ("memory-safe") {
687
- value := calldataload(abs)
688
- }
689
- cur.i += 1;
690
- }
691
-
692
- /// @notice Read the next 2 bytes from the cursor and advance by 2 bytes.
693
- /// @dev Performs no bounds, key, length, or cursor checks.
694
- /// @param cur Cursor whose current position is advanced by 2 bytes.
695
- /// @return value Loaded bytes2 value.
696
- function read2(Cur memory cur) internal pure returns (bytes2 value) {
697
- uint abs = cur.offset + cur.i;
698
- assembly ("memory-safe") {
699
- value := calldataload(abs)
700
- }
701
- cur.i += 2;
702
- }
703
-
704
- /// @notice Read the next 4 bytes from the cursor and advance by 4 bytes.
705
- /// @dev Performs no bounds, key, length, or cursor checks.
706
- /// @param cur Cursor whose current position is advanced by 4 bytes.
707
- /// @return value Loaded bytes4 value.
708
- function read4(Cur memory cur) internal pure returns (bytes4 value) {
709
- uint abs = cur.offset + cur.i;
710
- assembly ("memory-safe") {
711
- value := calldataload(abs)
712
- }
713
- cur.i += 4;
714
- }
715
-
716
- /// @notice Read the next 8 bytes from the cursor and advance by 8 bytes.
717
- /// @dev Performs no bounds, key, length, or cursor checks.
718
- /// @param cur Cursor whose current position is advanced by 8 bytes.
719
- /// @return value Loaded bytes8 value.
720
- function read8(Cur memory cur) internal pure returns (bytes8 value) {
721
- uint abs = cur.offset + cur.i;
722
- assembly ("memory-safe") {
723
- value := calldataload(abs)
724
- }
725
- cur.i += 8;
726
- }
727
-
728
- /// @notice Read the next 16 bytes from the cursor and advance by 16 bytes.
729
- /// @dev Performs no bounds, key, length, or cursor checks.
730
- /// @param cur Cursor whose current position is advanced by 16 bytes.
731
- /// @return value Loaded bytes16 value.
732
- function read16(Cur memory cur) internal pure returns (bytes16 value) {
733
- uint abs = cur.offset + cur.i;
734
- assembly ("memory-safe") {
735
- value := calldataload(abs)
736
- }
737
- cur.i += 16;
738
- }
739
-
740
- /// @notice Read the next 32-byte word from the cursor and advance by one word.
741
- /// @dev Performs no bounds, key, length, or cursor checks.
742
- /// @param cur Cursor whose current position is advanced by 32 bytes.
743
- /// @return value Loaded word.
744
- function read32(Cur memory cur) internal pure returns (bytes32 value) {
745
- uint abs = cur.offset + cur.i;
746
- assembly ("memory-safe") {
747
- value := calldataload(abs)
748
- }
749
- cur.i += 32;
750
- }
751
-
752
- /// @notice Read the next uint from the cursor and advance by one word.
753
- /// @dev Performs no bounds, key, length, or cursor checks.
754
- /// @param cur Cursor whose current position is advanced by 32 bytes.
755
- /// @return value Loaded uint value.
756
- function readUint(Cur memory cur) internal pure returns (uint value) {
757
- uint abs = cur.offset + cur.i;
758
- assembly ("memory-safe") {
759
- value := calldataload(abs)
760
- }
761
- cur.i += 32;
762
- }
763
-
764
- /// @notice Read the next two 32-byte words from the cursor and advance by 64 bytes.
765
- /// @dev Performs no bounds, key, length, or cursor checks.
766
- /// @param cur Cursor whose current position is advanced by 64 bytes.
767
- /// @return a First loaded word.
768
- /// @return b Second loaded word.
769
- function read64(Cur memory cur) internal pure returns (bytes32 a, bytes32 b) {
770
- uint abs = cur.offset + cur.i;
771
- assembly ("memory-safe") {
772
- a := calldataload(abs)
773
- b := calldataload(add(abs, 0x20))
774
- }
775
- cur.i += 64;
776
- }
777
-
778
- /// @notice Read the next three 32-byte words from the cursor and advance by 96 bytes.
779
- /// @dev Performs no bounds, key, length, or cursor checks.
780
- /// @param cur Cursor whose current position is advanced by 96 bytes.
781
- /// @return a First loaded word.
782
- /// @return b Second loaded word.
783
- /// @return c Third loaded word.
784
- function read96(Cur memory cur) internal pure returns (bytes32 a, bytes32 b, bytes32 c) {
785
- uint abs = cur.offset + cur.i;
786
- assembly ("memory-safe") {
787
- a := calldataload(abs)
788
- b := calldataload(add(abs, 0x20))
789
- c := calldataload(add(abs, 0x40))
790
- }
791
- cur.i += 96;
792
- }
793
-
794
- /// @notice Consume the next 32-byte word and require it to match `expected`.
795
- /// @dev Performs no bounds, key, length, or cursor checks beyond the value comparison.
796
- /// @param cur Cursor whose current position is advanced by 32 bytes.
797
- /// @param expected Required word value.
798
- function require32(Cur memory cur, bytes32 expected) internal pure {
799
- if (read32(cur) != expected) revert UnexpectedValue();
800
- }
801
-
802
- // -------------------------------------------------------------------------
803
- // unpack* - consume current block and decode payload fields
804
- // -------------------------------------------------------------------------
805
-
806
- // Generic fixed-width decoders
807
-
808
- /// @notice Consume a dynamic block with the given key and return the raw payload as a calldata slice.
809
- /// The payload length is variable; the returned slice covers the entire payload.
810
- /// @param cur Cursor; advanced past the block.
811
- /// @param key Expected dynamic block key.
812
- /// @return data Raw block payload bytes.
813
- function unpackRaw(Cur memory cur, bytes4 key) internal pure returns (bytes calldata data) {
814
- (uint abs, uint next) = expect(cur, cur.i, 0, key, 0, 0);
815
- data = msg.data[abs:cur.offset + next];
816
- cur.i = next;
817
- }
818
-
819
- /// @notice Consume a reserved BYTES block and return its raw payload.
820
- /// @param cur Cursor; advanced past the BYTES block.
821
- /// @return data Raw BYTES payload.
822
- function unpackBytes(Cur memory cur) internal pure returns (bytes calldata data) {
823
- return unpackRaw(cur, Keys.Bytes);
824
- }
825
-
826
- /// @notice Consume a reserved STRING block and return its UTF-8 payload.
827
- /// @param cur Cursor; advanced past the STRING block.
828
- /// @return data Decoded STRING payload.
829
- function unpackString(Cur memory cur) internal pure returns (string memory data) {
830
- return string(unpackRaw(cur, Keys.String));
831
- }
832
-
833
- /// @notice Consume a LABEL block and return its fields.
834
- /// @param cur Cursor; advanced past the LABEL block.
835
- /// @return id Node ID being labelled.
836
- /// @return namespace Label namespace.
837
- /// @return name Label value.
838
- function unpackLabel(Cur memory cur) internal pure returns (uint id, bytes32 namespace, string memory name) {
839
- uint end = cur.enter(Keys.Label, 64 + Sizes.Header, 0);
840
- id = cur.readUint();
841
- namespace = cur.read32();
842
- name = cur.unpackString();
843
- cur.ensureAt(end);
844
- }
845
-
846
- /// @notice Consume a SCHEMA block and return its fields.
847
- /// @param cur Cursor; advanced past the SCHEMA block.
848
- /// @return key Block key being defined.
849
- /// @return body Schema DSL string describing the block payload body.
850
- /// @return name Optional block alias.
851
- function unpackSchema(Cur memory cur) internal pure returns (bytes4 key, string memory body, bytes32 name) {
852
- uint end = cur.enter(Keys.Schema, 36 + Sizes.Header, 0);
853
- key = cur.read4();
854
- body = cur.unpackString();
855
- name = cur.read32();
856
- cur.ensureAt(end);
857
- }
858
-
859
- /// @notice Consume a dynamic block with a single bytes32 payload.
860
- /// @param cur Cursor; advanced past the block.
861
- /// @param key Expected dynamic block key.
862
- /// @return value Decoded bytes32.
863
- function unpack32(Cur memory cur, bytes4 key) internal pure returns (bytes32 value) {
864
- uint abs = consume(cur, 0, key, 32, 32);
865
- value = bytes32(msg.data[abs:abs + 32]);
866
- }
867
-
868
- /// @notice Consume a dynamic block with two bytes32 payload words.
869
- /// @param cur Cursor; advanced past the block.
870
- /// @param key Expected dynamic block key.
871
- /// @return a First decoded bytes32.
872
- /// @return b Second decoded bytes32.
873
- function unpack64(Cur memory cur, bytes4 key) internal pure returns (bytes32 a, bytes32 b) {
874
- uint abs = consume(cur, 0, key, 64, 64);
875
- a = bytes32(msg.data[abs:abs + 32]);
876
- b = bytes32(msg.data[abs + 32:abs + 64]);
877
- }
878
-
879
- /// @notice Consume a dynamic block with three bytes32 payload words.
880
- /// @param cur Cursor; advanced past the block.
881
- /// @param key Expected dynamic block key.
882
- /// @return a First decoded bytes32.
883
- /// @return b Second decoded bytes32.
884
- /// @return c Third decoded bytes32.
885
- function unpack96(Cur memory cur, bytes4 key) internal pure returns (bytes32 a, bytes32 b, bytes32 c) {
886
- uint abs = consume(cur, 0, key, 96, 96);
887
- a = bytes32(msg.data[abs:abs + 32]);
888
- b = bytes32(msg.data[abs + 32:abs + 64]);
889
- c = bytes32(msg.data[abs + 64:abs + 96]);
890
- }
891
-
892
- /// @notice Consume a dynamic block with a 128-byte payload (four 32-byte words).
893
- /// @param cur Cursor; advanced past the block.
894
- /// @param key Expected dynamic block key.
895
- /// @return a First decoded bytes32.
896
- /// @return b Second decoded bytes32.
897
- /// @return c Third decoded bytes32.
898
- /// @return d Fourth decoded bytes32.
899
- function unpack128(Cur memory cur, bytes4 key) internal pure returns (bytes32 a, bytes32 b, bytes32 c, bytes32 d) {
900
- uint abs = consume(cur, 0, key, 128, 128);
901
- a = bytes32(msg.data[abs:abs + 32]);
902
- b = bytes32(msg.data[abs + 32:abs + 64]);
903
- c = bytes32(msg.data[abs + 64:abs + 96]);
904
- d = bytes32(msg.data[abs + 96:abs + 128]);
905
- }
906
-
907
- /// @notice Consume a dynamic block with a 160-byte payload (five 32-byte words).
908
- /// @param cur Cursor; advanced past the block.
909
- /// @param key Expected dynamic block key.
910
- /// @return a First decoded bytes32.
911
- /// @return b Second decoded bytes32.
912
- /// @return c Third decoded bytes32.
913
- /// @return d Fourth decoded bytes32.
914
- /// @return e Fifth decoded bytes32.
915
- function unpack160(
916
- Cur memory cur,
917
- bytes4 key
918
- ) internal pure returns (bytes32 a, bytes32 b, bytes32 c, bytes32 d, bytes32 e) {
919
- uint abs = consume(cur, 0, key, 160, 160);
920
- a = bytes32(msg.data[abs:abs + 32]);
921
- b = bytes32(msg.data[abs + 32:abs + 64]);
922
- c = bytes32(msg.data[abs + 64:abs + 96]);
923
- d = bytes32(msg.data[abs + 96:abs + 128]);
924
- e = bytes32(msg.data[abs + 128:abs + 160]);
925
- }
926
-
927
- // Generic typed-shape decoders
928
-
929
- /// @notice Consume a fixed-size asset amount block and return asset and amount.
930
- /// @param cur Cursor; advanced past the block.
931
- /// @param key Expected block key.
932
- /// @return asset Asset identifier.
933
- /// @return amount Scalar amount value.
934
- function unpackAssetAmount(Cur memory cur, bytes4 key) internal pure returns (bytes32 asset, uint amount) {
935
- uint abs = consume(cur, 0, key, 64, 64);
936
- asset = bytes32(msg.data[abs:abs + 32]);
937
- amount = uint(bytes32(msg.data[abs + 32:abs + 64]));
938
- }
939
-
940
- /// @notice Consume a fixed-size account amount block and return account, asset, and amount.
941
- /// @param cur Cursor; advanced past the block.
942
- /// @param key Expected block key.
943
- /// @return account Account identifier.
944
- /// @return asset Asset identifier.
945
- /// @return amount Scalar amount value.
946
- function unpackAccountAmount(
947
- Cur memory cur,
948
- bytes4 key
949
- ) internal pure returns (bytes32 account, bytes32 asset, uint amount) {
950
- uint abs = consume(cur, 0, key, 96, 96);
951
- account = bytes32(msg.data[abs:abs + 32]);
952
- asset = bytes32(msg.data[abs + 32:abs + 64]);
953
- amount = uint(bytes32(msg.data[abs + 64:abs + 96]));
954
- }
955
-
956
- /// @notice Consume a fixed-size host amount block and return host, asset, and amount.
957
- /// @param cur Cursor; advanced past the block.
958
- /// @param key Expected block key.
959
- /// @return host Host node ID.
960
- /// @return asset Asset identifier.
961
- /// @return amount Scalar amount value.
962
- function unpackHostAmount(
963
- Cur memory cur,
964
- bytes4 key
965
- ) internal pure returns (uint host, bytes32 asset, uint amount) {
966
- uint abs = consume(cur, 0, key, 96, 96);
967
- host = uint(bytes32(msg.data[abs:abs + 32]));
968
- asset = bytes32(msg.data[abs + 32:abs + 64]);
969
- amount = uint(bytes32(msg.data[abs + 64:abs + 96]));
970
- }
971
-
972
- /// @notice Consume a fixed-size host account asset block and return host, account, and asset.
973
- /// @param cur Cursor; advanced past the block.
974
- /// @param key Expected block key.
975
- /// @return host Host node ID.
976
- /// @return account Account identifier.
977
- /// @return asset Asset identifier.
978
- function unpackHostAccountAsset(
979
- Cur memory cur,
980
- bytes4 key
981
- ) internal pure returns (uint host, bytes32 account, bytes32 asset) {
982
- uint abs = consume(cur, 0, key, 96, 96);
983
- host = uint(bytes32(msg.data[abs:abs + 32]));
984
- account = bytes32(msg.data[abs + 32:abs + 64]);
985
- asset = bytes32(msg.data[abs + 64:abs + 96]);
986
- }
987
-
988
- /// @notice Consume a fixed-size transaction block and return from, to, asset, and amount.
989
- /// @param cur Cursor; advanced past the block.
990
- /// @param key Expected block key.
991
- /// @return from Source account identifier.
992
- /// @return to Destination account identifier.
993
- /// @return asset Asset identifier.
994
- /// @return amount Scalar amount value.
995
- function unpackTransaction(
996
- Cur memory cur,
997
- bytes4 key
998
- ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
999
- uint abs = consume(cur, 0, key, 128, 128);
1000
- from = bytes32(msg.data[abs:abs + 32]);
1001
- to = bytes32(msg.data[abs + 32:abs + 64]);
1002
- asset = bytes32(msg.data[abs + 64:abs + 96]);
1003
- amount = uint(bytes32(msg.data[abs + 96:abs + 128]));
1004
- }
1005
-
1006
- // Type-specific fixed-width decoders
1007
-
1008
- /// @notice Consume an ACCOUNT block and return the account.
1009
- /// @param cur Cursor; advanced past the block.
1010
- /// @return account Account identifier.
1011
- function unpackAccount(Cur memory cur) internal pure returns (bytes32 account) {
1012
- account = unpack32(cur, Keys.Account);
1013
- }
1014
-
1015
- /// @notice Consume a NODE block and return the node ID.
1016
- /// @param cur Cursor; advanced past the block.
1017
- /// @return node Node identifier.
1018
- function unpackNode(Cur memory cur) internal pure returns (uint node) {
1019
- node = uint(unpack32(cur, Keys.Node));
1020
- }
1021
-
1022
- /// @notice Consume a FEE block and return the amount.
1023
- /// @param cur Cursor; advanced past the block.
1024
- /// @return amount Fee amount.
1025
- function unpackFee(Cur memory cur) internal pure returns (uint amount) {
1026
- amount = uint(unpack32(cur, Keys.Fee));
1027
- }
1028
-
1029
- /// @notice Consume an ASSET block and return the asset identifier.
1030
- /// @param cur Cursor; advanced past the block.
1031
- /// @return asset Asset identifier.
1032
- function unpackAsset(Cur memory cur) internal pure returns (bytes32 asset) {
1033
- asset = unpack32(cur, Keys.Asset);
1034
- }
1035
-
1036
- /// @notice Consume an ACCOUNT_ASSET form block and return its fields as separate values.
1037
- /// @param cur Cursor; advanced past the block.
1038
- /// @return account Account identifier.
1039
- /// @return asset Asset identifier.
1040
- function unpackAccountAsset(Cur memory cur) internal pure returns (bytes32 account, bytes32 asset) {
1041
- uint abs = consume(cur, 0, Keys.AccountAsset, 64, 64);
1042
- account = bytes32(msg.data[abs:abs + 32]);
1043
- asset = bytes32(msg.data[abs + 32:abs + 64]);
1044
- }
1045
-
1046
- /// @notice Consume an ACCOUNT_ASSET form block and return its fields as a struct.
1047
- /// @param cur Cursor; advanced past the block.
1048
- /// @return value Decoded account and asset.
1049
- function unpackAccountAssetValue(Cur memory cur) internal pure returns (AccountAsset memory value) {
1050
- (value.account, value.asset) = unpackAccountAsset(cur);
1051
- }
1052
-
1053
- /// @notice Consume a BOUNTY block and return the reward amount and relayer.
1054
- /// @param cur Cursor; advanced past the block.
1055
- /// @return amount Relayer reward amount.
1056
- /// @return relayer Relayer account identifier.
1057
- function unpackBounty(Cur memory cur) internal pure returns (uint amount, bytes32 relayer) {
1058
- (bytes32 x, bytes32 y) = unpack64(cur, Keys.Bounty);
1059
- amount = uint(x);
1060
- relayer = y;
1061
- }
1062
-
1063
- /// @notice Consume an AMOUNT block and return its fields as separate values.
1064
- /// @param cur Cursor; advanced past the block.
1065
- /// @return asset Asset identifier.
1066
- /// @return amount Token amount.
1067
- function unpackAmount(Cur memory cur) internal pure returns (bytes32 asset, uint amount) {
1068
- return unpackAssetAmount(cur, Keys.Amount);
1069
- }
1070
-
1071
- /// @notice Consume an AMOUNT block and return its fields as a struct.
1072
- /// @param cur Cursor; advanced past the block.
1073
- /// @return value Decoded asset and amount.
1074
- function unpackAmountValue(Cur memory cur) internal pure returns (AssetAmount memory value) {
1075
- (value.asset, value.amount) = unpackAssetAmount(cur, Keys.Amount);
1076
- }
1077
-
1078
- /// @notice Consume a BALANCE block and return its fields as separate values.
1079
- /// @param cur Cursor; advanced past the block.
1080
- /// @return asset Asset identifier.
1081
- /// @return amount Token amount.
1082
- function unpackBalance(Cur memory cur) internal pure returns (bytes32 asset, uint amount) {
1083
- return unpackAssetAmount(cur, Keys.Balance);
1084
- }
1085
-
1086
- /// @notice Consume a BALANCE block and return its fields as a struct.
1087
- /// @param cur Cursor; advanced past the block.
1088
- /// @return value Decoded asset and amount.
1089
- function unpackBalanceValue(Cur memory cur) internal pure returns (AssetAmount memory value) {
1090
- (value.asset, value.amount) = unpackAssetAmount(cur, Keys.Balance);
1091
- }
1092
-
1093
- /// @notice Consume a HOST_ACCOUNT_ASSET form block and return its fields as separate values.
1094
- /// @param cur Cursor; advanced past the block.
1095
- /// @return host Host node ID.
1096
- /// @return account Account identifier.
1097
- /// @return asset Asset identifier.
1098
- function unpackHostAccountAsset(Cur memory cur) internal pure returns (uint host, bytes32 account, bytes32 asset) {
1099
- return unpackHostAccountAsset(cur, Keys.HostAccountAsset);
1100
- }
1101
-
1102
- /// @notice Consume a HOST_ACCOUNT_ASSET form block and return its fields as a struct.
1103
- /// @param cur Cursor; advanced past the block.
1104
- /// @return value Decoded host, account, and asset.
1105
- function unpackHostAccountAssetValue(Cur memory cur) internal pure returns (HostAccountAsset memory value) {
1106
- (value.host, value.account, value.asset) = unpackHostAccountAsset(cur, Keys.HostAccountAsset);
1107
- }
1108
-
1109
- /// @notice Consume an ACCOUNT_AMOUNT form block and return its fields as separate values.
1110
- /// @param cur Cursor; advanced past the block.
1111
- /// @return account Account identifier.
1112
- /// @return asset Asset identifier.
1113
- /// @return amount Token amount.
1114
- function unpackAccountAmount(Cur memory cur) internal pure returns (bytes32 account, bytes32 asset, uint amount) {
1115
- return unpackAccountAmount(cur, Keys.AccountAmount);
1116
- }
1117
-
1118
- /// @notice Consume an ACCOUNT_AMOUNT form block and return its fields as a struct.
1119
- /// @param cur Cursor; advanced past the block.
1120
- /// @return value Decoded account, asset, and amount.
1121
- function unpackAccountAmountValue(Cur memory cur) internal pure returns (AccountAmount memory value) {
1122
- (value.account, value.asset, value.amount) = unpackAccountAmount(cur, Keys.AccountAmount);
1123
- }
1124
-
1125
- /// @notice Consume an ALLOCATION block and return its fields as separate values.
1126
- /// @param cur Cursor; advanced past the block.
1127
- /// @return host Host node ID.
1128
- /// @return asset Asset identifier.
1129
- /// @return amount Token amount.
1130
- function unpackAllocation(Cur memory cur) internal pure returns (uint host, bytes32 asset, uint amount) {
1131
- return unpackHostAmount(cur, Keys.Allocation);
1132
- }
1133
-
1134
- /// @notice Consume an ALLOCATION block and return its fields as a struct.
1135
- /// @param cur Cursor; advanced past the block.
1136
- /// @return value Decoded host, asset, and amount.
1137
- function unpackAllocationValue(Cur memory cur) internal pure returns (HostAmount memory value) {
1138
- (value.host, value.asset, value.amount) = unpackHostAmount(cur, Keys.Allocation);
1139
- }
1140
-
1141
- /// @notice Consume an ALLOWANCE block and return its fields as separate values.
1142
- /// @param cur Cursor; advanced past the block.
1143
- /// @return host Host node ID.
1144
- /// @return asset Asset identifier.
1145
- /// @return amount Token amount.
1146
- function unpackAllowance(Cur memory cur) internal pure returns (uint host, bytes32 asset, uint amount) {
1147
- return unpackHostAmount(cur, Keys.Allowance);
1148
- }
1149
-
1150
- /// @notice Consume an ALLOWANCE block and return its fields as a struct.
1151
- /// @param cur Cursor; advanced past the block.
1152
- /// @return value Decoded host, asset, and amount.
1153
- function unpackAllowanceValue(Cur memory cur) internal pure returns (HostAmount memory value) {
1154
- (value.host, value.asset, value.amount) = unpackHostAmount(cur, Keys.Allowance);
1155
- }
1156
-
1157
- /// @notice Consume a CUSTODY block and return its fields as separate values.
1158
- /// @param cur Cursor; advanced past the block.
1159
- /// @return host Host node ID.
1160
- /// @return asset Asset identifier.
1161
- /// @return amount Token amount.
1162
- function unpackCustody(Cur memory cur) internal pure returns (uint host, bytes32 asset, uint amount) {
1163
- return unpackHostAmount(cur, Keys.Custody);
1164
- }
1165
-
1166
- /// @notice Consume a CUSTODY block and return its fields as a struct.
1167
- /// @param cur Cursor; advanced past the block.
1168
- /// @return value Decoded host, asset, and amount.
1169
- function unpackCustodyValue(Cur memory cur) internal pure returns (HostAmount memory value) {
1170
- (value.host, value.asset, value.amount) = unpackHostAmount(cur, Keys.Custody);
1171
- }
1172
-
1173
- /// @notice Consume a TRANSACTION block and return its fields as separate values.
1174
- /// @param cur Cursor; advanced past the block.
1175
- /// @return from Source account identifier.
1176
- /// @return to Destination account identifier.
1177
- /// @return asset Asset identifier.
1178
- /// @return amount Token amount.
1179
- function unpackTransaction(
1180
- Cur memory cur
1181
- ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
1182
- return unpackTransaction(cur, Keys.Transaction);
1183
- }
1184
-
1185
- /// @notice Consume a TRANSACTION block and return all fields as a struct.
1186
- /// @param cur Cursor; advanced past the block.
1187
- /// @return value Decoded from, to, asset, and amount.
1188
- function unpackTxValue(Cur memory cur) internal pure returns (Tx memory value) {
1189
- (value.from, value.to, value.asset, value.amount) = unpackTransaction(cur);
1190
- }
1191
-
1192
- // Type-specific dynamic decoders
1193
-
1194
- /// @notice Consume a STEP block and return its sub-command invocation fields.
1195
- /// The `req` slice is the raw payload of the block's required BYTES child.
1196
- /// @param cur Cursor; advanced past the block.
1197
- /// @return target Destination node ID for the sub-command.
1198
- /// @return resources Packed resources assigned to the step.
1199
- /// @return req Embedded request bytes for the sub-command.
1200
- function unpackStep(Cur memory cur) internal pure returns (uint target, uint resources, bytes calldata req) {
1201
- uint end = cur.enter(Keys.Step, 64 + Sizes.Header, 0);
1202
- target = uint(cur.read32());
1203
- resources = uint(cur.read32());
1204
- req = cur.unpackBytes();
1205
- cur.ensureAt(end);
1206
- }
1207
-
1208
- /// @notice Consume a CALL block and return its target invocation fields.
1209
- /// The `data` slice is the raw payload of the block's required BYTES child.
1210
- /// @param cur Cursor; advanced past the block.
1211
- /// @return target Target node ID to call.
1212
- /// @return resources Packed resources assigned to the call.
1213
- /// @return data Raw calldata payload for the target.
1214
- function unpackCall(Cur memory cur) internal pure returns (uint target, uint resources, bytes calldata data) {
1215
- uint end = cur.enter(Keys.Call, 64 + Sizes.Header, 0);
1216
- target = uint(cur.read32());
1217
- resources = uint(cur.read32());
1218
- data = cur.unpackBytes();
1219
- cur.ensureAt(end);
1220
- }
1221
-
1222
- /// @notice Consume a CONTEXT block and return its command context fields.
1223
- /// The `state` and `request` slices are the raw payloads of the required BYTES children.
1224
- /// @param cur Cursor; advanced past the block.
1225
- /// @return account Command account identifier.
1226
- /// @return state Embedded state block stream.
1227
- /// @return request Embedded request block stream.
1228
- function unpackContext(
1229
- Cur memory cur
1230
- ) internal pure returns (bytes32 account, bytes calldata state, bytes calldata request) {
1231
- uint end = cur.enter(Keys.Context, 32 + 2 * Sizes.Header, 0);
1232
- account = cur.read32();
1233
- state = cur.unpackBytes();
1234
- request = cur.unpackBytes();
1235
- cur.ensureAt(end);
1236
- }
1237
-
1238
- /// @notice Consume a RELAY block and return its destination portal, resources, and request stream.
1239
- /// @param cur Cursor; advanced past the block.
1240
- /// @return portal Destination portal identifier, often the destination host ID.
1241
- /// @return resources Chain-specific resources for the destination context.
1242
- /// @return request Embedded request block stream.
1243
- function unpackRelay(Cur memory cur) internal pure returns (uint portal, uint resources, bytes calldata request) {
1244
- uint end = cur.enter(Keys.Relay, 64 + Sizes.Header, 0);
1245
- portal = cur.readUint();
1246
- resources = cur.readUint();
1247
- request = cur.unpackBytes();
1248
- cur.ensureAt(end);
1249
- }
1250
-
1251
- /// @notice Consume a DISPATCH block and return its destination portal, resources, and payload.
1252
- /// @param cur Cursor; advanced past the block.
1253
- /// @return portal Destination portal identifier, often the destination host ID.
1254
- /// @return resources Chain-specific resources for the destination dispatch.
1255
- /// @return payload Encoded payload.
1256
- function unpackDispatch(
1257
- Cur memory cur
1258
- ) internal pure returns (uint portal, uint resources, bytes calldata payload) {
1259
- uint end = cur.enter(Keys.Dispatch, 64 + Sizes.Header, 0);
1260
- portal = cur.readUint();
1261
- resources = cur.readUint();
1262
- payload = cur.unpackBytes();
1263
- cur.ensureAt(end);
1264
- }
1265
-
1266
- /// @notice Consume a RECOVER block and return its handler, resources, key, and witness bytes.
1267
- /// @param cur Cursor; advanced past the block.
1268
- /// @return handler Recovery handler port node ID.
1269
- /// @return resources Packed resources assigned to the recovery attempt.
1270
- /// @return key Recovery lookup key.
1271
- /// @return witness Witness bytes used by the recovery handler.
1272
- function unpackRecover(
1273
- Cur memory cur
1274
- ) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness) {
1275
- uint end = cur.enter(Keys.Recover, 96 + Sizes.Header, 0);
1276
- handler = cur.readUint();
1277
- resources = cur.readUint();
1278
- key = cur.read32();
1279
- witness = cur.unpackBytes();
1280
- cur.ensureAt(end);
1281
- }
1282
-
1283
- // Type-specific validators
1284
-
1285
- /// @notice Validate an AUTH block at position `i` and extract deadline and proof.
1286
- /// Does not advance the cursor.
1287
- /// @param cur Source cursor.
1288
- /// @param i Byte offset of the AUTH block.
1289
- /// @param cid Command ID that the AUTH block must reference.
1290
- /// @return deadline Expiry timestamp.
1291
- /// @return proof Raw proof bytes (layout: `[bytes20 signer][bytes65 sig]`).
1292
- function expectAuth(Cur memory cur, uint i, uint cid) internal pure returns (uint deadline, bytes calldata proof) {
1293
- (uint abs, uint next) = expect(cur, i, 0, Keys.Auth, 64 + Sizes.Header + Sizes.Proof, 0);
1294
- if (uint(bytes32(msg.data[abs:abs + 32])) != cid) revert UnexpectedValue();
1295
- deadline = uint(bytes32(msg.data[abs + 32:abs + 64]));
1296
-
1297
- (abs, ) = expect(cur, i + Sizes.Header + 64, next, Keys.Bytes, Sizes.Proof, Sizes.Proof);
1298
- proof = msg.data[abs:abs + Sizes.Proof];
1299
- }
1300
-
1301
- // -------------------------------------------------------------------------
1302
- // require* - validate + advance (like consume with content checks)
1303
- // -------------------------------------------------------------------------
1304
-
1305
- /// @notice Consume an asset block and assert it matches the expected asset.
1306
- /// @param cur Cursor; advanced past the block.
1307
- /// @param key Expected block type key.
1308
- /// @param asset Expected asset identifier.
1309
- /// @return amount Amount from the block.
1310
- function requireAssetAmount(Cur memory cur, bytes4 key, bytes32 asset) internal pure returns (uint amount) {
1311
- uint abs = consume(cur, 0, key, 64, 64);
1312
- if (bytes32(msg.data[abs:abs + 32]) != asset) revert UnexpectedValue();
1313
- amount = uint(bytes32(msg.data[abs + 32:abs + 64]));
1314
- }
1315
-
1316
- /// @notice Consume an asset amount block, assert it matches the expected asset, and require the amount to be 1.
1317
- /// @param cur Cursor; advanced past the block.
1318
- /// @param key Expected block type key.
1319
- /// @param asset Expected asset identifier.
1320
- function requireUnitAssetAmount(Cur memory cur, bytes4 key, bytes32 asset) internal pure {
1321
- uint abs = consume(cur, 0, key, 64, 64);
1322
- if (bytes32(msg.data[abs:abs + 32]) != asset) revert UnexpectedValue();
1323
- if (uint(bytes32(msg.data[abs + 32:abs + 64])) != 1) revert UnexpectedValue();
1324
- }
1325
-
1326
- /// @notice Consume a host amount block and assert it matches the expected host.
1327
- /// @param cur Cursor; advanced past the block.
1328
- /// @param key Expected block type key.
1329
- /// @param host Expected host node ID.
1330
- /// @return asset Asset identifier from the block.
1331
- /// @return amount Amount from the block.
1332
- function requireHostAmount(
1333
- Cur memory cur,
1334
- bytes4 key,
1335
- uint host
1336
- ) internal pure returns (bytes32 asset, uint amount) {
1337
- uint abs = consume(cur, 0, key, 96, 96);
1338
- if (uint(bytes32(msg.data[abs:abs + 32])) != host) revert UnexpectedValue();
1339
- asset = bytes32(msg.data[abs + 32:abs + 64]);
1340
- amount = uint(bytes32(msg.data[abs + 64:abs + 96]));
1341
- }
1342
-
1343
- /// @notice Consume a host amount block and assert it matches the expected host and asset.
1344
- /// @param cur Cursor; advanced past the block.
1345
- /// @param key Expected block type key.
1346
- /// @param host Expected host node ID.
1347
- /// @param asset Expected asset identifier.
1348
- /// @return amount Amount from the block.
1349
- function requireHostAmount(
1350
- Cur memory cur,
1351
- bytes4 key,
1352
- uint host,
1353
- bytes32 asset
1354
- ) internal pure returns (uint amount) {
1355
- uint abs = consume(cur, 0, key, 96, 96);
1356
- if (uint(bytes32(msg.data[abs:abs + 32])) != host) revert UnexpectedValue();
1357
- if (bytes32(msg.data[abs + 32:abs + 64]) != asset) revert UnexpectedValue();
1358
- amount = uint(bytes32(msg.data[abs + 64:abs + 96]));
1359
- }
1360
-
1361
- /// @notice Consume a host amount block, assert it matches the expected host and asset, and require the amount to be 1.
1362
- /// @param cur Cursor; advanced past the block.
1363
- /// @param key Expected block type key.
1364
- /// @param host Expected host node ID.
1365
- /// @param asset Expected asset identifier.
1366
- function requireUnitHostAmount(Cur memory cur, bytes4 key, uint host, bytes32 asset) internal pure {
1367
- uint abs = consume(cur, 0, key, 96, 96);
1368
- if (uint(bytes32(msg.data[abs:abs + 32])) != host) revert UnexpectedValue();
1369
- if (bytes32(msg.data[abs + 32:abs + 64]) != asset) revert UnexpectedValue();
1370
- if (uint(bytes32(msg.data[abs + 64:abs + 96])) != 1) revert UnexpectedValue();
1371
- }
1372
-
1373
- /// @notice Consume a host account asset block and assert it matches the expected host and account.
1374
- /// @param cur Cursor; advanced past the block.
1375
- /// @param key Expected block key.
1376
- /// @param host Expected host node ID.
1377
- /// @param account Expected account identifier.
1378
- /// @return asset Asset identifier from the block.
1379
- function requireHostAccountAsset(
1380
- Cur memory cur,
1381
- bytes4 key,
1382
- uint host,
1383
- bytes32 account
1384
- ) internal pure returns (bytes32 asset) {
1385
- uint abs = consume(cur, 0, key, 96, 96);
1386
- if (uint(bytes32(msg.data[abs:abs + 32])) != host) revert UnexpectedValue();
1387
- if (bytes32(msg.data[abs + 32:abs + 64]) != account) revert UnexpectedValue();
1388
- asset = bytes32(msg.data[abs + 64:abs + 96]);
1389
- }
1390
-
1391
- /// @notice Consume a host account asset block, assert it targets the expected host, and return account and asset.
1392
- /// @param cur Cursor; advanced past the block.
1393
- /// @param key Expected block key.
1394
- /// @param host Expected host node ID.
1395
- /// @return account Account identifier from the block.
1396
- /// @return asset Asset identifier from the block.
1397
- function requireHostAccountAsset(
1398
- Cur memory cur,
1399
- bytes4 key,
1400
- uint host
1401
- ) internal pure returns (bytes32 account, bytes32 asset) {
1402
- uint abs = consume(cur, 0, key, 96, 96);
1403
- if (uint(bytes32(msg.data[abs:abs + 32])) != host) revert UnexpectedValue();
1404
- account = bytes32(msg.data[abs + 32:abs + 64]);
1405
- asset = bytes32(msg.data[abs + 64:abs + 96]);
1406
- }
1407
-
1408
- /// @notice Consume a HOST_ACCOUNT_ASSET form block, assert it targets the expected host, and return account and asset.
1409
- /// @param cur Cursor; advanced past the block.
1410
- /// @param host Expected host node ID.
1411
- /// @return account Account identifier from the block.
1412
- /// @return asset Asset identifier from the block.
1413
- function requireHostAccountAsset(Cur memory cur, uint host) internal pure returns (bytes32 account, bytes32 asset) {
1414
- return requireHostAccountAsset(cur, Keys.HostAccountAsset, host);
1415
- }
1416
-
1417
- /// @notice Consume an AUTH block at the current position and verify the command ID.
1418
- /// @param cur Cursor; advanced past the block.
1419
- /// @param cid Expected command ID.
1420
- /// @return deadline Expiry timestamp.
1421
- /// @return proof Raw proof bytes.
1422
- function requireAuth(Cur memory cur, uint cid) internal pure returns (uint deadline, bytes calldata proof) {
1423
- (deadline, proof) = expectAuth(cur, cur.i, cid);
1424
- cur.i += Sizes.Auth;
1425
- }
1426
-
1427
- // -------------------------------------------------------------------------
1428
- // ensure* - validate constraint blocks against provided values
1429
- // -------------------------------------------------------------------------
1430
-
1431
- /// @notice Consume a BALANCE_LIMIT block and assert all constraint fields match the provided balance.
1432
- /// @param cur Cursor; advanced past the block.
1433
- /// @param asset Expected asset identifier.
1434
- /// @param amount Amount that must fall within the encoded min/max range.
1435
- function ensureBalanceLimit(Cur memory cur, bytes32 asset, uint amount) internal pure {
1436
- uint abs = consume(cur, 0, Keys.BalanceLimit, 96, 96);
1437
- if (bytes32(msg.data[abs:abs + 32]) != asset) revert UnexpectedValue();
1438
- if (uint(bytes32(msg.data[abs + 32:abs + 64])) > amount) revert UnexpectedValue();
1439
- if (uint(bytes32(msg.data[abs + 64:abs + 96])) < amount) revert UnexpectedValue();
1440
- }
1441
-
1442
- /// @notice Consume a CUSTODY_LIMIT block and assert all constraint fields match the provided custody.
1443
- /// @param cur Cursor; advanced past the block.
1444
- /// @param host Expected host node ID.
1445
- /// @param asset Expected asset identifier.
1446
- /// @param amount Amount that must fall within the encoded min/max range.
1447
- function ensureCustodyLimit(Cur memory cur, uint host, bytes32 asset, uint amount) internal pure {
1448
- uint abs = consume(cur, 0, Keys.CustodyLimit, 128, 128);
1449
- if (uint(bytes32(msg.data[abs:abs + 32])) != host) revert UnexpectedValue();
1450
- if (bytes32(msg.data[abs + 32:abs + 64]) != asset) revert UnexpectedValue();
1451
- if (uint(bytes32(msg.data[abs + 64:abs + 96])) > amount) revert UnexpectedValue();
1452
- if (uint(bytes32(msg.data[abs + 96:abs + 128])) < amount) revert UnexpectedValue();
1453
- }
1454
-
1455
- // -------------------------------------------------------------------------
1456
- // Transform helpers
1457
- // -------------------------------------------------------------------------
1458
-
1459
- /// @notice Consume a BALANCE block and scope its amount to a host.
1460
- /// @param cur Cursor; advanced past the BALANCE block.
1461
- /// @param host Host node ID to attach to the decoded balance.
1462
- /// @return value Host-scoped balance amount.
1463
- function unpackBalanceForHost(
1464
- Cur memory cur,
1465
- uint host
1466
- ) internal pure returns (HostAmount memory value) {
1467
- value.host = host;
1468
- (value.asset, value.amount) = cur.unpackBalance();
1469
- }
1470
-
1471
- /// @notice Consume a RELAY block and encode its destination context payload.
1472
- /// @param cur Cursor; advanced past the RELAY block.
1473
- /// @param account Account identifier to embed in the destination context.
1474
- /// @param state State block stream to embed in the destination context.
1475
- /// @return portal Destination portal identifier, often the destination host ID.
1476
- /// @return resources Chain-specific resources assigned to the destination context.
1477
- /// @return context Encoded CONTEXT block containing `account`, `state`, and relay request.
1478
- function relayToContext(
1479
- Cur memory cur,
1480
- bytes32 account,
1481
- bytes calldata state
1482
- ) internal pure returns (uint portal, uint resources, bytes memory context) {
1483
- bytes calldata request;
1484
- (portal, resources, request) = cur.unpackRelay();
1485
- context = toContextBlock(account, bytes(state), bytes(request));
1486
- }
1487
-
1488
- // -------------------------------------------------------------------------
1489
- // Search helpers
1490
- // -------------------------------------------------------------------------
1491
-
1492
- /// @notice Look for a NODE block anywhere in a calldata source and return its value.
1493
- /// Scans from the start of `source` to the end.
1494
- /// @param source Calldata block stream to search.
1495
- /// @param backup Value to return if no NODE block is found.
1496
- /// @return node Node ID from the NODE block, or `backup` if absent.
1497
- function resolveNode(bytes calldata source, uint backup) internal pure returns (uint node) {
1498
- Cur memory cur = open(source);
1499
- uint i = find(cur, 0, Keys.Node);
1500
- if (i == cur.len) return backup;
1501
-
1502
- (uint abs, ) = expect(cur, i, 0, Keys.Node, 32, 32);
1503
- return uint(bytes32(msg.data[abs:abs + 32]));
1504
- }
1505
-
1506
- /// @notice Look for a NODE block anywhere in a calldata source and require a non-zero result.
1507
- /// Scans from the start of `source` to the end.
1508
- /// @param source Calldata block stream to search.
1509
- /// @param backup Value to use if no NODE block is found.
1510
- /// @return node Node ID from the NODE block, or `backup` if absent.
1511
- function resolveNodeOrRevert(bytes calldata source, uint backup) internal pure returns (uint node) {
1512
- node = resolveNode(source, backup);
1513
- if (node == 0) revert ZeroNode();
1514
- }
1515
-
1516
- /// @notice Look for an ACCOUNT block anywhere in a calldata source and return its value.
1517
- /// Scans from the start of `source` to the end.
1518
- /// @param source Calldata block stream to search.
1519
- /// @param backup Account to return if no ACCOUNT block is found.
1520
- /// @return account Account from the ACCOUNT block, or `backup` if absent.
1521
- function resolveAccount(bytes calldata source, bytes32 backup) internal pure returns (bytes32 account) {
1522
- Cur memory cur = open(source);
1523
- uint i = find(cur, 0, Keys.Account);
1524
- if (i == cur.len) return backup;
1525
-
1526
- (uint abs, ) = expect(cur, i, 0, Keys.Account, 32, 32);
1527
- return bytes32(msg.data[abs:abs + 32]);
1528
- }
1529
- }