@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,1606 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ import {Keys} from "./Keys.sol";
5
+ import {Sizes, Specs} from "./Specs.sol";
6
+ import {max32} from "../utils/Utils.sol";
7
+
8
+ /// @title Blocks
9
+ /// @notice Stateless helpers for inspecting and encoding protocol blocks.
10
+ /// @dev Blocks use `[key:4][payload length:4][payload]`. Calldata helpers use
11
+ /// absolute positions. Bounded navigation helpers also take an absolute `end`;
12
+ /// specialized absolute readers and unpackers intentionally omit logical-region
13
+ /// checks. Their caller must validate consumed positions through a surrounding
14
+ /// cursor, execution, or equivalent boundary.
15
+ ///
16
+ /// Fixed-width unpackers return decoded fields only because their following
17
+ /// position is statically `abs + Sizes.X`. Dynamic leaf and composite unpackers
18
+ /// return absolute `end` last because their encoded size is known only while
19
+ /// decoding. Built-in composites use optimized assembly for fixed fields and
20
+ /// semantic unpackers for child blocks. Custom schema decoders should favor
21
+ /// `expect`, readable calldata slices, semantic child unpackers, and a final
22
+ /// equality check proving that the children consume the complete payload.
23
+ ///
24
+ /// Generic and specialized writers are unchecked: callers must validate inputs
25
+ /// and reserve the complete destination region before calling them. Helpers are
26
+ /// ordered as inspection, generic writes, specialized writes, decoding, and
27
+ /// block factories; fixed layouts within a section are ordered from smaller to
28
+ /// larger payloads.
29
+ library Blocks {
30
+ /// @dev A block header or declared payload exceeds the source region.
31
+ error MalformedBlocks();
32
+ /// @dev A block key or payload size does not match its expected shape.
33
+ error InvalidBlock();
34
+ /// @dev A decoded value did not match the expected value.
35
+ error UnexpectedValue();
36
+ /// @dev A scoped block run contained no blocks.
37
+ error EmptyRun();
38
+ /// @dev A block run was scoped with a zero stride.
39
+ error ZeroStride();
40
+ /// @dev A block count is not divisible by its declared stride.
41
+ error BadRatio();
42
+
43
+ // -------------------------------------------------------------------------
44
+ // Calldata inspection and navigation
45
+ // -------------------------------------------------------------------------
46
+
47
+ /// @notice Decode a block header at an absolute calldata position.
48
+ /// @dev DANGER: This performs an unchecked calldata read and does not ensure the
49
+ /// complete header or payload lies within a logical calldata region.
50
+ /// @param abs Absolute calldata position of the header.
51
+ /// @return key Decoded block key.
52
+ /// @return len Decoded payload length.
53
+ function header(uint abs) internal pure returns (bytes4 key, uint len) {
54
+ uint head;
55
+ assembly ("memory-safe") {
56
+ head := calldataload(abs)
57
+ }
58
+ key = bytes4(uint32(head >> 224));
59
+ len = uint32(head >> 192);
60
+ }
61
+
62
+ /// @notice Decode a block header and validate its key at an absolute calldata position.
63
+ /// @dev DANGER: This performs an unchecked calldata read and does not ensure the
64
+ /// complete header or payload lies within a logical calldata region.
65
+ /// @param abs Absolute calldata position of the header.
66
+ /// @param expected Expected block key.
67
+ /// @return len Decoded payload length.
68
+ function header(uint abs, bytes4 expected) internal pure returns (uint len) {
69
+ uint head;
70
+ assembly ("memory-safe") {
71
+ head := calldataload(abs)
72
+ }
73
+ if (uint32(head >> 224) != uint32(expected)) revert InvalidBlock();
74
+ len = uint32(head >> 192);
75
+ }
76
+
77
+ /// @notice Validate a block header at an absolute calldata position.
78
+ /// @dev DANGER: This performs an unchecked calldata read and does not ensure `end`
79
+ /// lies within the caller's logical calldata region. Only the key, minimum,
80
+ /// and maximum fields of `spec` are used.
81
+ /// @param abs Absolute calldata position of the header.
82
+ /// @param spec Expected block specification.
83
+ /// @return body Absolute position of the first payload byte.
84
+ /// @return end Absolute position immediately after the payload.
85
+ function expect(uint abs, uint spec) internal pure returns (uint body, uint end) {
86
+ uint len = header(abs, Specs.key(spec));
87
+ if (!Specs.accepts(spec, len)) revert InvalidBlock();
88
+
89
+ body = abs + Sizes.Header;
90
+ end = body + len;
91
+ }
92
+
93
+ /// @dev Validate the key and exact payload size of a fixed-width block.
94
+ /// @param abs Absolute calldata position of the header.
95
+ /// @param spec Expected block specification.
96
+ /// @param size Expected payload length.
97
+ /// @return body Absolute position of the payload.
98
+ /// @return end Absolute position after the payload.
99
+ function expectFixed(uint abs, uint spec, uint size) private pure returns (uint body, uint end) {
100
+ if (header(abs, Specs.key(spec)) != size) revert InvalidBlock();
101
+ body = abs + Sizes.Header;
102
+ end = body + size;
103
+ }
104
+
105
+ /// @notice Return whether `abs` identifies a header with `key` before an absolute end.
106
+ /// @param abs Absolute calldata position to inspect.
107
+ /// @param end Absolute region boundary.
108
+ /// @param key Expected block key.
109
+ /// @return Whether a complete matching header exists.
110
+ function hasAt(uint abs, uint end, bytes4 key) internal pure returns (bool) {
111
+ if (abs > end || Sizes.Header > end - abs) return false;
112
+ return bytes4(read32(abs)) == key;
113
+ }
114
+
115
+ /// @notice Find the first block with `key` at or after absolute position `abs`.
116
+ /// @param abs Absolute search position.
117
+ /// @param end Absolute region boundary.
118
+ /// @param key Block key to find.
119
+ /// @return Absolute position of the matching block, or `end` when absent.
120
+ function find(uint abs, uint end, bytes4 key) internal pure returns (uint) {
121
+ while (abs < end) {
122
+ (bytes4 current, uint len) = header(abs);
123
+ if (Sizes.Header + len > end - abs) revert MalformedBlocks();
124
+ if (current == key) return abs;
125
+ abs += Sizes.Header + len;
126
+ }
127
+ return end;
128
+ }
129
+
130
+ /// @notice Count consecutive blocks with `key` from absolute position `abs`.
131
+ /// @param abs Absolute start position.
132
+ /// @param limit Absolute region boundary.
133
+ /// @param key Block key forming the run.
134
+ /// @return total Number of consecutive matching blocks.
135
+ /// @return end Absolute position after the run.
136
+ function run(uint abs, uint limit, bytes4 key) internal pure returns (uint total, uint end) {
137
+ end = abs;
138
+ while (end < limit) {
139
+ (bytes4 current, uint len) = header(end);
140
+ if (Sizes.Header + len > limit - end) revert MalformedBlocks();
141
+ if (current != key) break;
142
+ end += Sizes.Header + len;
143
+
144
+ unchecked {
145
+ ++total;
146
+ }
147
+ }
148
+ }
149
+
150
+ /// @notice Scope a consecutive block run into equal-sized groups.
151
+ /// @param abs Absolute start position.
152
+ /// @param limit Absolute region boundary.
153
+ /// @param key Block key forming the run.
154
+ /// @param stride Number of blocks per group.
155
+ /// @return groups Number of complete groups in the run.
156
+ /// @return end Absolute position immediately after the run.
157
+ function scope(
158
+ uint abs,
159
+ uint limit,
160
+ bytes4 key,
161
+ uint stride
162
+ ) internal pure returns (uint groups, uint end) {
163
+ if (stride == 0) revert ZeroStride();
164
+ uint count;
165
+ (count, end) = run(abs, limit, key);
166
+ if (count == 0) revert EmptyRun();
167
+ if (count % stride != 0) revert BadRatio();
168
+ groups = count / stride;
169
+ }
170
+
171
+ // Generic block writes
172
+
173
+ /// @notice Write a custom block with one payload word at `i`.
174
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B32` bytes first.
175
+ /// @param dst Destination buffer.
176
+ /// @param i Relative write position.
177
+ /// @param key Block key.
178
+ /// @param a Payload word.
179
+ function write32(bytes memory dst, uint i, bytes4 key, bytes32 a) internal pure {
180
+ uint head = (uint(uint32(key)) << 224) | (uint(32) << 192);
181
+ assembly ("memory-safe") {
182
+ let p := add(add(dst, 0x20), i)
183
+ mstore(p, head)
184
+ mstore(add(p, 0x08), a)
185
+ }
186
+ }
187
+
188
+ /// @notice Write a custom block with two payload words at `i`.
189
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B64` bytes first.
190
+ /// @param dst Destination buffer.
191
+ /// @param i Relative write position.
192
+ /// @param key Block key.
193
+ /// @param a First payload word.
194
+ /// @param b Second payload word.
195
+ function write64(bytes memory dst, uint i, bytes4 key, bytes32 a, bytes32 b) internal pure {
196
+ uint head = (uint(uint32(key)) << 224) | (uint(64) << 192);
197
+ assembly ("memory-safe") {
198
+ let p := add(add(dst, 0x20), i)
199
+ mstore(p, head)
200
+ mstore(add(p, 0x08), a)
201
+ mstore(add(p, 0x28), b)
202
+ }
203
+ }
204
+
205
+ /// @notice Write a custom block with three payload words at `i`.
206
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
207
+ /// @param dst Destination buffer.
208
+ /// @param i Relative write position.
209
+ /// @param key Block key.
210
+ /// @param a First payload word.
211
+ /// @param b Second payload word.
212
+ /// @param c Third payload word.
213
+ function write96(bytes memory dst, uint i, bytes4 key, bytes32 a, bytes32 b, bytes32 c) internal pure {
214
+ uint head = (uint(uint32(key)) << 224) | (uint(96) << 192);
215
+ assembly ("memory-safe") {
216
+ let p := add(add(dst, 0x20), i)
217
+ mstore(p, head)
218
+ mstore(add(p, 0x08), a)
219
+ mstore(add(p, 0x28), b)
220
+ mstore(add(p, 0x48), c)
221
+ }
222
+ }
223
+
224
+ /// @notice Write a custom block with a dynamic payload at `i`.
225
+ /// @dev DANGER: Unchecked memory write. The caller must validate the payload
226
+ /// length and reserve `Sizes.Header + payload.length` bytes first.
227
+ /// @param dst Destination buffer.
228
+ /// @param i Relative write position.
229
+ /// @param key Block key.
230
+ /// @param payload Block payload.
231
+ function write(bytes memory dst, uint i, bytes4 key, bytes memory payload) internal pure {
232
+ uint len = max32(payload.length);
233
+ uint head = (uint(uint32(key)) << 224) | (len << 192);
234
+ assembly ("memory-safe") {
235
+ let p := add(add(dst, 0x20), i)
236
+ mstore(p, head)
237
+ mcopy(add(p, 0x08), add(payload, 0x20), len)
238
+ }
239
+ }
240
+
241
+ // Fixed-width block writes
242
+
243
+ // One-word payloads
244
+
245
+ /// @notice Write an ACCOUNT block at `i`.
246
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B32` bytes first.
247
+ /// @param dst Destination buffer.
248
+ /// @param i Relative write position.
249
+ /// @param account Account identifier to encode.
250
+ function writeAccount(bytes memory dst, uint i, bytes32 account) internal pure {
251
+ uint spec = Specs.Account;
252
+ assembly ("memory-safe") {
253
+ let p := add(add(dst, 0x20), i)
254
+ mstore(p, spec)
255
+ mstore(add(p, 0x08), account)
256
+ }
257
+ }
258
+
259
+ /// @notice Write an ASSET block at `i`.
260
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B32` bytes first.
261
+ /// @param dst Destination buffer.
262
+ /// @param i Relative write position.
263
+ /// @param asset Asset identifier to encode.
264
+ function writeAsset(bytes memory dst, uint i, bytes32 asset) internal pure {
265
+ uint spec = Specs.Asset;
266
+ assembly ("memory-safe") {
267
+ let p := add(add(dst, 0x20), i)
268
+ mstore(p, spec)
269
+ mstore(add(p, 0x08), asset)
270
+ }
271
+ }
272
+
273
+ /// @notice Write a NODE block at `i`.
274
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B32` bytes first.
275
+ /// @param dst Destination buffer.
276
+ /// @param i Relative write position.
277
+ /// @param node Node identifier to encode.
278
+ function writeNode(bytes memory dst, uint i, uint node) internal pure {
279
+ uint spec = Specs.Node;
280
+ assembly ("memory-safe") {
281
+ let p := add(add(dst, 0x20), i)
282
+ mstore(p, spec)
283
+ mstore(add(p, 0x08), node)
284
+ }
285
+ }
286
+
287
+ /// @notice Write a STATUS block at `i`.
288
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B32` bytes first.
289
+ /// @param dst Destination buffer.
290
+ /// @param i Relative write position.
291
+ /// @param code Status code to encode.
292
+ function writeStatus(bytes memory dst, uint i, uint code) internal pure {
293
+ uint spec = Specs.Status;
294
+ assembly ("memory-safe") {
295
+ let p := add(add(dst, 0x20), i)
296
+ mstore(p, spec)
297
+ mstore(add(p, 0x08), code)
298
+ }
299
+ }
300
+
301
+ // Two-word payloads
302
+
303
+ /// @notice Write an AMOUNT block at `i`.
304
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B64` bytes first.
305
+ /// @param dst Destination buffer.
306
+ /// @param i Relative write position.
307
+ /// @param asset Asset identifier to encode.
308
+ /// @param amount Asset amount to encode.
309
+ function writeAmount(bytes memory dst, uint i, bytes32 asset, uint amount) internal pure {
310
+ uint spec = Specs.Amount;
311
+ assembly ("memory-safe") {
312
+ let p := add(add(dst, 0x20), i)
313
+ mstore(p, spec)
314
+ mstore(add(p, 0x08), asset)
315
+ mstore(add(p, 0x28), amount)
316
+ }
317
+ }
318
+
319
+ /// @notice Write a BALANCE block at `i`.
320
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B64` bytes first.
321
+ /// @param dst Destination buffer.
322
+ /// @param i Relative write position.
323
+ /// @param asset Asset identifier to encode.
324
+ /// @param amount Balance amount to encode.
325
+ function writeBalance(bytes memory dst, uint i, bytes32 asset, uint amount) internal pure {
326
+ uint spec = Specs.Balance;
327
+ assembly ("memory-safe") {
328
+ let p := add(add(dst, 0x20), i)
329
+ mstore(p, spec)
330
+ mstore(add(p, 0x08), asset)
331
+ mstore(add(p, 0x28), amount)
332
+ }
333
+ }
334
+
335
+ /// @notice Write an ACCOUNT_ASSET block at `i`.
336
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B64` bytes first.
337
+ /// @param dst Destination buffer.
338
+ /// @param i Relative write position.
339
+ /// @param account Account identifier to encode.
340
+ /// @param asset Asset identifier to encode.
341
+ function writeAccountAsset(bytes memory dst, uint i, bytes32 account, bytes32 asset) internal pure {
342
+ uint spec = Specs.AccountAsset;
343
+ assembly ("memory-safe") {
344
+ let p := add(add(dst, 0x20), i)
345
+ mstore(p, spec)
346
+ mstore(add(p, 0x08), account)
347
+ mstore(add(p, 0x28), asset)
348
+ }
349
+ }
350
+
351
+ // Three-word payloads
352
+
353
+ /// @notice Write an ALLOCATION block at `i`.
354
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
355
+ /// @param dst Destination buffer.
356
+ /// @param i Relative write position.
357
+ /// @param host Host identifier to encode.
358
+ /// @param asset Asset identifier to encode.
359
+ /// @param amount Allocation amount to encode.
360
+ function writeAllocation(bytes memory dst, uint i, uint host, bytes32 asset, uint amount) internal pure {
361
+ uint spec = Specs.Allocation;
362
+ assembly ("memory-safe") {
363
+ let p := add(add(dst, 0x20), i)
364
+ mstore(p, spec)
365
+ mstore(add(p, 0x08), host)
366
+ mstore(add(p, 0x28), asset)
367
+ mstore(add(p, 0x48), amount)
368
+ }
369
+ }
370
+
371
+ /// @notice Write an ALLOWANCE block at `i`.
372
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
373
+ /// @param dst Destination buffer.
374
+ /// @param i Relative write position.
375
+ /// @param host Host identifier to encode.
376
+ /// @param asset Asset identifier to encode.
377
+ /// @param amount Allowance amount to encode.
378
+ function writeAllowance(bytes memory dst, uint i, uint host, bytes32 asset, uint amount) internal pure {
379
+ uint spec = Specs.Allowance;
380
+ assembly ("memory-safe") {
381
+ let p := add(add(dst, 0x20), i)
382
+ mstore(p, spec)
383
+ mstore(add(p, 0x08), host)
384
+ mstore(add(p, 0x28), asset)
385
+ mstore(add(p, 0x48), amount)
386
+ }
387
+ }
388
+
389
+ /// @notice Write a CUSTODY block at `i`.
390
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
391
+ /// @param dst Destination buffer.
392
+ /// @param i Relative write position.
393
+ /// @param host Host identifier to encode.
394
+ /// @param asset Asset identifier to encode.
395
+ /// @param amount Custody amount to encode.
396
+ function writeCustody(bytes memory dst, uint i, uint host, bytes32 asset, uint amount) internal pure {
397
+ uint spec = Specs.Custody;
398
+ assembly ("memory-safe") {
399
+ let p := add(add(dst, 0x20), i)
400
+ mstore(p, spec)
401
+ mstore(add(p, 0x08), host)
402
+ mstore(add(p, 0x28), asset)
403
+ mstore(add(p, 0x48), amount)
404
+ }
405
+ }
406
+
407
+ /// @notice Write an ACCOUNT_AMOUNT block at `i`.
408
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
409
+ /// @param dst Destination buffer.
410
+ /// @param i Relative write position.
411
+ /// @param account Account identifier to encode.
412
+ /// @param asset Asset identifier to encode.
413
+ /// @param amount Account amount to encode.
414
+ function writeAccountAmount(bytes memory dst, uint i, bytes32 account, bytes32 asset, uint amount) internal pure {
415
+ uint spec = Specs.AccountAmount;
416
+ assembly ("memory-safe") {
417
+ let p := add(add(dst, 0x20), i)
418
+ mstore(p, spec)
419
+ mstore(add(p, 0x08), account)
420
+ mstore(add(p, 0x28), asset)
421
+ mstore(add(p, 0x48), amount)
422
+ }
423
+ }
424
+
425
+ /// @notice Write a HOST_AMOUNT block at `i`.
426
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
427
+ /// @param dst Destination buffer.
428
+ /// @param i Relative write position.
429
+ /// @param host Host identifier to encode.
430
+ /// @param asset Asset identifier to encode.
431
+ /// @param amount Host amount to encode.
432
+ function writeHostAmount(bytes memory dst, uint i, uint host, bytes32 asset, uint amount) internal pure {
433
+ uint spec = Specs.HostAmount;
434
+ assembly ("memory-safe") {
435
+ let p := add(add(dst, 0x20), i)
436
+ mstore(p, spec)
437
+ mstore(add(p, 0x08), host)
438
+ mstore(add(p, 0x28), asset)
439
+ mstore(add(p, 0x48), amount)
440
+ }
441
+ }
442
+
443
+ /// @notice Write a HOST_ACCOUNT_ASSET block at `i`.
444
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B96` bytes first.
445
+ /// @param dst Destination buffer.
446
+ /// @param i Relative write position.
447
+ /// @param host Host identifier to encode.
448
+ /// @param account Account identifier to encode.
449
+ /// @param asset Asset identifier to encode.
450
+ function writeHostAccountAsset(bytes memory dst, uint i, uint host, bytes32 account, bytes32 asset) internal pure {
451
+ uint spec = Specs.HostAccountAsset;
452
+ assembly ("memory-safe") {
453
+ let p := add(add(dst, 0x20), i)
454
+ mstore(p, spec)
455
+ mstore(add(p, 0x08), host)
456
+ mstore(add(p, 0x28), account)
457
+ mstore(add(p, 0x48), asset)
458
+ }
459
+ }
460
+
461
+ // Four-word payloads
462
+
463
+ /// @notice Write a TRANSACTION block at `i`.
464
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B128` bytes first.
465
+ /// @param dst Destination buffer.
466
+ /// @param i Relative write position.
467
+ /// @param from Debit account identifier.
468
+ /// @param to Credit account identifier.
469
+ /// @param asset Asset identifier.
470
+ /// @param amount Transaction amount.
471
+ function writeTransaction(
472
+ bytes memory dst,
473
+ uint i,
474
+ bytes32 from,
475
+ bytes32 to,
476
+ bytes32 asset,
477
+ uint amount
478
+ ) internal pure {
479
+ uint spec = Specs.Transaction;
480
+ assembly ("memory-safe") {
481
+ let p := add(add(dst, 0x20), i)
482
+ mstore(p, spec)
483
+ mstore(add(p, 0x08), from)
484
+ mstore(add(p, 0x28), to)
485
+ mstore(add(p, 0x48), asset)
486
+ mstore(add(p, 0x68), amount)
487
+ }
488
+ }
489
+
490
+ /// @notice Write a HOST_ACCOUNT_AMOUNT block at `i`.
491
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B128` bytes first.
492
+ /// @param dst Destination buffer.
493
+ /// @param i Relative write position.
494
+ /// @param host Host identifier.
495
+ /// @param account Account identifier.
496
+ /// @param asset Asset identifier.
497
+ /// @param amount Host account amount.
498
+ function writeHostAccountAmount(
499
+ bytes memory dst,
500
+ uint i,
501
+ uint host,
502
+ bytes32 account,
503
+ bytes32 asset,
504
+ uint amount
505
+ ) internal pure {
506
+ uint spec = Specs.HostAccountAmount;
507
+ assembly ("memory-safe") {
508
+ let p := add(add(dst, 0x20), i)
509
+ mstore(p, spec)
510
+ mstore(add(p, 0x08), host)
511
+ mstore(add(p, 0x28), account)
512
+ mstore(add(p, 0x48), asset)
513
+ mstore(add(p, 0x68), amount)
514
+ }
515
+ }
516
+
517
+ // Dynamic payloads
518
+
519
+ /// @notice Write a LIST block at `i`.
520
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
521
+ /// block size and ensure the payload length fits in uint32.
522
+ /// @param dst Destination buffer.
523
+ /// @param i Relative write position.
524
+ /// @param value Encoded list payload.
525
+ function writeList(bytes memory dst, uint i, bytes memory value) internal pure {
526
+ uint len = value.length;
527
+ uint key = uint32(Keys.List);
528
+ assembly ("memory-safe") {
529
+ let p := add(add(dst, 0x20), i)
530
+ mstore(p, or(shl(224, key), shl(192, len)))
531
+ mcopy(add(p, 0x08), add(value, 0x20), len)
532
+ }
533
+ }
534
+
535
+ /// @notice Write an EVM block at `i`.
536
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
537
+ /// block size and ensure the payload length fits in uint32.
538
+ /// @param dst Destination buffer.
539
+ /// @param i Relative write position.
540
+ /// @param value EVM payload.
541
+ function writeEvm(bytes memory dst, uint i, bytes memory value) internal pure {
542
+ uint len = value.length;
543
+ uint key = uint32(Keys.Evm);
544
+ assembly ("memory-safe") {
545
+ let p := add(add(dst, 0x20), i)
546
+ mstore(p, or(shl(224, key), shl(192, len)))
547
+ mcopy(add(p, 0x08), add(value, 0x20), len)
548
+ }
549
+ }
550
+
551
+ /// @notice Write a BYTES block at `i`.
552
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
553
+ /// block size and ensure the payload length fits in uint32.
554
+ /// @param dst Destination buffer.
555
+ /// @param i Relative write position.
556
+ /// @param value Byte payload.
557
+ function writeBytes(bytes memory dst, uint i, bytes memory value) internal pure {
558
+ uint len = value.length;
559
+ uint key = uint32(Keys.Bytes);
560
+ assembly ("memory-safe") {
561
+ let p := add(add(dst, 0x20), i)
562
+ mstore(p, or(shl(224, key), shl(192, len)))
563
+ mcopy(add(p, 0x08), add(value, 0x20), len)
564
+ }
565
+ }
566
+
567
+ /// @notice Write a STRING block at `i`.
568
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
569
+ /// block size and ensure the payload length fits in uint32.
570
+ /// @param dst Destination buffer.
571
+ /// @param i Relative write position.
572
+ /// @param value String payload.
573
+ function writeString(bytes memory dst, uint i, string memory value) internal pure {
574
+ uint len = bytes(value).length;
575
+ uint key = uint32(Keys.String);
576
+ assembly ("memory-safe") {
577
+ let p := add(add(dst, 0x20), i)
578
+ mstore(p, or(shl(224, key), shl(192, len)))
579
+ mcopy(add(p, 0x08), add(value, 0x20), len)
580
+ }
581
+ }
582
+
583
+ /// @notice Write a STEP block at `i`.
584
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
585
+ /// block size and ensure the encoded payload length fits in uint32.
586
+ /// @param dst Destination buffer.
587
+ /// @param i Relative write position.
588
+ /// @param cmd Command identifier.
589
+ /// @param resources Packed resources.
590
+ /// @param input Command input.
591
+ function writeStep(bytes memory dst, uint i, uint cmd, uint resources, bytes memory input) internal pure {
592
+ uint len = 64 + Sizes.Header + input.length;
593
+ uint key = uint32(Keys.Step);
594
+ uint byteskey = uint32(Keys.Bytes);
595
+ assembly ("memory-safe") {
596
+ let p := add(add(dst, 0x20), i)
597
+ mstore(p, or(shl(224, key), shl(192, len)))
598
+ mstore(add(p, 0x08), cmd)
599
+ mstore(add(p, 0x28), resources)
600
+
601
+ let q := add(p, 0x48)
602
+ let inputlen := mload(input)
603
+ mstore(q, or(shl(224, byteskey), shl(192, inputlen)))
604
+ mcopy(add(q, 0x08), add(input, 0x20), inputlen)
605
+ }
606
+ }
607
+
608
+ /// @notice Write a CALL block at `i`.
609
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
610
+ /// block size and ensure the encoded payload length fits in uint32.
611
+ /// @param dst Destination buffer.
612
+ /// @param i Relative write position.
613
+ /// @param target Call target.
614
+ /// @param resources Packed resources.
615
+ /// @param payload Call payload.
616
+ function writeCall(bytes memory dst, uint i, uint target, uint resources, bytes memory payload) internal pure {
617
+ uint len = 64 + Sizes.Header + payload.length;
618
+ uint key = uint32(Keys.Call);
619
+ uint byteskey = uint32(Keys.Bytes);
620
+ assembly ("memory-safe") {
621
+ let p := add(add(dst, 0x20), i)
622
+ mstore(p, or(shl(224, key), shl(192, len)))
623
+ mstore(add(p, 0x08), target)
624
+ mstore(add(p, 0x28), resources)
625
+
626
+ let q := add(p, 0x48)
627
+ let payloadlen := mload(payload)
628
+ mstore(q, or(shl(224, byteskey), shl(192, payloadlen)))
629
+ mcopy(add(q, 0x08), add(payload, 0x20), payloadlen)
630
+ }
631
+ }
632
+
633
+ /// @notice Write a RELAY block at `i`.
634
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
635
+ /// block size and ensure the encoded payload length fits in uint32.
636
+ /// @param dst Destination buffer.
637
+ /// @param i Relative write position.
638
+ /// @param portal Destination portal.
639
+ /// @param resources Packed resources.
640
+ /// @param input Relay input.
641
+ function writeRelay(bytes memory dst, uint i, uint portal, uint resources, bytes memory input) internal pure {
642
+ uint len = 64 + Sizes.Header + input.length;
643
+ uint key = uint32(Keys.Relay);
644
+ uint byteskey = uint32(Keys.Bytes);
645
+ assembly ("memory-safe") {
646
+ let p := add(add(dst, 0x20), i)
647
+ mstore(p, or(shl(224, key), shl(192, len)))
648
+ mstore(add(p, 0x08), portal)
649
+ mstore(add(p, 0x28), resources)
650
+
651
+ let q := add(p, 0x48)
652
+ let inputlen := mload(input)
653
+ mstore(q, or(shl(224, byteskey), shl(192, inputlen)))
654
+ mcopy(add(q, 0x08), add(input, 0x20), inputlen)
655
+ }
656
+ }
657
+
658
+ /// @notice Write a DISPATCH block at `i`.
659
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
660
+ /// block size and ensure the encoded payload length fits in uint32.
661
+ /// @param dst Destination buffer.
662
+ /// @param i Relative write position.
663
+ /// @param portal Destination portal.
664
+ /// @param resources Packed resources.
665
+ /// @param payload Dispatch payload.
666
+ function writeDispatch(bytes memory dst, uint i, uint portal, uint resources, bytes memory payload) internal pure {
667
+ uint len = 64 + Sizes.Header + payload.length;
668
+ uint key = uint32(Keys.Dispatch);
669
+ uint byteskey = uint32(Keys.Bytes);
670
+ assembly ("memory-safe") {
671
+ let p := add(add(dst, 0x20), i)
672
+ mstore(p, or(shl(224, key), shl(192, len)))
673
+ mstore(add(p, 0x08), portal)
674
+ mstore(add(p, 0x28), resources)
675
+
676
+ let q := add(p, 0x48)
677
+ let payloadlen := mload(payload)
678
+ mstore(q, or(shl(224, byteskey), shl(192, payloadlen)))
679
+ mcopy(add(q, 0x08), add(payload, 0x20), payloadlen)
680
+ }
681
+ }
682
+
683
+ /// @notice Write a CONTEXT block at `i`.
684
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
685
+ /// block size and ensure the encoded payload length fits in uint32.
686
+ /// @param dst Destination buffer.
687
+ /// @param i Relative write position.
688
+ /// @param account Account identifier.
689
+ /// @param state State payload.
690
+ /// @param input Input payload.
691
+ function writeContext(
692
+ bytes memory dst,
693
+ uint i,
694
+ bytes32 account,
695
+ bytes memory state,
696
+ bytes memory input
697
+ ) internal pure {
698
+ uint len = 32 + 2 * Sizes.Header + state.length + input.length;
699
+ uint key = uint32(Keys.Context);
700
+ uint byteskey = uint32(Keys.Bytes);
701
+ assembly ("memory-safe") {
702
+ let p := add(add(dst, 0x20), i)
703
+ mstore(p, or(shl(224, key), shl(192, len)))
704
+ mstore(add(p, 0x08), account)
705
+
706
+ let q := add(p, 0x28)
707
+ let statelen := mload(state)
708
+ mstore(q, or(shl(224, byteskey), shl(192, statelen)))
709
+ mcopy(add(q, 0x08), add(state, 0x20), statelen)
710
+
711
+ let r := add(add(q, 0x08), statelen)
712
+ let inputlen := mload(input)
713
+ mstore(r, or(shl(224, byteskey), shl(192, inputlen)))
714
+ mcopy(add(r, 0x08), add(input, 0x20), inputlen)
715
+ }
716
+ }
717
+
718
+ /// @notice Write a RECOVER block at `i`.
719
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
720
+ /// block size and ensure the encoded payload length fits in uint32.
721
+ /// @param dst Destination buffer.
722
+ /// @param i Relative write position.
723
+ /// @param handler Recovery handler.
724
+ /// @param resources Packed resources.
725
+ /// @param recoverykey Recovery key.
726
+ /// @param witness Recovery witness.
727
+ function writeRecover(
728
+ bytes memory dst,
729
+ uint i,
730
+ uint handler,
731
+ uint resources,
732
+ bytes32 recoverykey,
733
+ bytes memory witness
734
+ ) internal pure {
735
+ uint len = 96 + Sizes.Header + witness.length;
736
+ uint key = uint32(Keys.Recover);
737
+ uint byteskey = uint32(Keys.Bytes);
738
+ assembly ("memory-safe") {
739
+ let p := add(add(dst, 0x20), i)
740
+ mstore(p, or(shl(224, key), shl(192, len)))
741
+ mstore(add(p, 0x08), handler)
742
+ mstore(add(p, 0x28), resources)
743
+ mstore(add(p, 0x48), recoverykey)
744
+
745
+ let q := add(p, 0x68)
746
+ let witnesslen := mload(witness)
747
+ mstore(q, or(shl(224, byteskey), shl(192, witnesslen)))
748
+ mcopy(add(q, 0x08), add(witness, 0x20), witnesslen)
749
+ }
750
+ }
751
+
752
+ /// @notice Write a LABEL block at `i`.
753
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
754
+ /// block size and ensure the encoded payload length fits in uint32.
755
+ /// @param dst Destination buffer.
756
+ /// @param i Relative write position.
757
+ /// @param id Node identifier.
758
+ /// @param namespace Label namespace.
759
+ /// @param name Label text.
760
+ function writeLabel(bytes memory dst, uint i, uint id, bytes32 namespace, string memory name) internal pure {
761
+ uint len = 64 + Sizes.Header + bytes(name).length;
762
+ uint key = uint32(Keys.Label);
763
+ uint stringkey = uint32(Keys.String);
764
+ assembly ("memory-safe") {
765
+ let p := add(add(dst, 0x20), i)
766
+ mstore(p, or(shl(224, key), shl(192, len)))
767
+ mstore(add(p, 0x08), id)
768
+ mstore(add(p, 0x28), namespace)
769
+
770
+ let q := add(p, 0x48)
771
+ let namelen := mload(name)
772
+ mstore(q, or(shl(224, stringkey), shl(192, namelen)))
773
+ mcopy(add(q, 0x08), add(name, 0x20), namelen)
774
+ }
775
+ }
776
+
777
+ /// @notice Write a SCHEMA block at `i`.
778
+ /// @dev DANGER: Unchecked memory write. The caller must reserve the complete
779
+ /// block size and ensure the encoded payload length fits in uint32.
780
+ /// @param dst Destination buffer.
781
+ /// @param i Relative write position.
782
+ /// @param spec Block specification.
783
+ /// @param body Schema body.
784
+ /// @param name Schema name.
785
+ function writeSchema(bytes memory dst, uint i, uint spec, string memory body, bytes32 name) internal pure {
786
+ uint len = 64 + Sizes.Header + bytes(body).length;
787
+ uint key = uint32(Keys.Schema);
788
+ uint stringkey = uint32(Keys.String);
789
+ assembly ("memory-safe") {
790
+ let p := add(add(dst, 0x20), i)
791
+ mstore(p, or(shl(224, key), shl(192, len)))
792
+ mstore(add(p, 0x08), spec)
793
+
794
+ let q := add(p, 0x28)
795
+ let bodylen := mload(body)
796
+ mstore(q, or(shl(224, stringkey), shl(192, bodylen)))
797
+ mcopy(add(q, 0x08), add(body, 0x20), bodylen)
798
+ mstore(add(add(q, 0x08), bodylen), name)
799
+ }
800
+ }
801
+
802
+ // -------------------------------------------------------------------------
803
+ // Calldata decoding
804
+ // -------------------------------------------------------------------------
805
+
806
+ // Raw reads
807
+
808
+ /// @notice Read four bytes from an absolute calldata position.
809
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
810
+ /// @param abs Absolute calldata position.
811
+ /// @return value Decoded four-byte value.
812
+ function read4(uint abs) internal pure returns (bytes4 value) {
813
+ assembly ("memory-safe") {
814
+ value := calldataload(abs)
815
+ }
816
+ }
817
+
818
+ /// @notice Read one word from an absolute calldata position.
819
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
820
+ /// @param abs Absolute calldata position.
821
+ /// @return value Decoded word.
822
+ function read32(uint abs) internal pure returns (bytes32 value) {
823
+ assembly ("memory-safe") {
824
+ value := calldataload(abs)
825
+ }
826
+ }
827
+
828
+ /// @notice Require the word at an absolute calldata position to match `expected`.
829
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
830
+ /// @param abs Absolute calldata position.
831
+ /// @param expected Expected word.
832
+ function require32(uint abs, bytes32 expected) internal pure {
833
+ if (read32(abs) != expected) revert UnexpectedValue();
834
+ }
835
+
836
+ /// @notice Read one unsigned integer from an absolute calldata position.
837
+ /// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
838
+ /// @param abs Absolute calldata position.
839
+ /// @return value Decoded unsigned integer.
840
+ function readUint(uint abs) internal pure returns (uint value) {
841
+ assembly ("memory-safe") {
842
+ value := calldataload(abs)
843
+ }
844
+ }
845
+
846
+ // Generic block unpackers
847
+
848
+ /// @notice Validate a block against `spec` and return its payload.
849
+ /// @param abs Absolute block position.
850
+ /// @param spec Expected block specification.
851
+ /// @return value Decoded payload.
852
+ /// @return end Absolute position after the block.
853
+ function unpackRaw(uint abs, uint spec) internal pure returns (bytes calldata value, uint end) {
854
+ (abs, end) = expect(abs, spec);
855
+ value = msg.data[abs:end];
856
+ }
857
+
858
+ /// @notice Decode a spec-validated one-word block at `abs`.
859
+ /// @param abs Absolute block position.
860
+ /// @param spec Expected block specification.
861
+ /// @return a First payload word.
862
+ /// @return end Absolute position after the block.
863
+ function unpack32(uint abs, uint spec) internal pure returns (bytes32 a, uint end) {
864
+ (abs, end) = expectFixed(abs, spec, 32);
865
+ a = read32(abs);
866
+ }
867
+
868
+ /// @notice Decode a spec-validated two-word block at `abs`.
869
+ /// @param abs Absolute block position.
870
+ /// @param spec Expected block specification.
871
+ /// @return a First payload word.
872
+ /// @return b Second payload word.
873
+ /// @return end Absolute position after the block.
874
+ function unpack64(uint abs, uint spec) internal pure returns (bytes32 a, bytes32 b, uint end) {
875
+ (abs, end) = expectFixed(abs, spec, 64);
876
+ assembly ("memory-safe") {
877
+ a := calldataload(abs)
878
+ b := calldataload(add(abs, 0x20))
879
+ }
880
+ }
881
+
882
+ /// @notice Decode a spec-validated three-word block at `abs`.
883
+ /// @param abs Absolute block position.
884
+ /// @param spec Expected block specification.
885
+ /// @return a First payload word.
886
+ /// @return b Second payload word.
887
+ /// @return c Third payload word.
888
+ /// @return end Absolute position after the block.
889
+ function unpack96(
890
+ uint abs,
891
+ uint spec
892
+ ) internal pure returns (bytes32 a, bytes32 b, bytes32 c, uint end) {
893
+ (abs, end) = expectFixed(abs, spec, 96);
894
+ assembly ("memory-safe") {
895
+ a := calldataload(abs)
896
+ b := calldataload(add(abs, 0x20))
897
+ c := calldataload(add(abs, 0x40))
898
+ }
899
+ }
900
+
901
+ /// @notice Decode a spec-validated four-word block at `abs`.
902
+ /// @param abs Absolute block position.
903
+ /// @param spec Expected block specification.
904
+ /// @return a First payload word.
905
+ /// @return b Second payload word.
906
+ /// @return c Third payload word.
907
+ /// @return d Fourth payload word.
908
+ /// @return end Absolute position after the block.
909
+ function unpack128(
910
+ uint abs,
911
+ uint spec
912
+ ) internal pure returns (bytes32 a, bytes32 b, bytes32 c, bytes32 d, uint end) {
913
+ (abs, end) = expectFixed(abs, spec, 128);
914
+ assembly ("memory-safe") {
915
+ a := calldataload(abs)
916
+ b := calldataload(add(abs, 0x20))
917
+ c := calldataload(add(abs, 0x40))
918
+ d := calldataload(add(abs, 0x60))
919
+ }
920
+ }
921
+
922
+ /// @notice Decode a spec-validated five-word block at `abs`.
923
+ /// @param abs Absolute block position.
924
+ /// @param spec Expected block specification.
925
+ /// @return a First payload word.
926
+ /// @return b Second payload word.
927
+ /// @return c Third payload word.
928
+ /// @return d Fourth payload word.
929
+ /// @return e Fifth payload word.
930
+ /// @return end Absolute position after the block.
931
+ function unpack160(
932
+ uint abs,
933
+ uint spec
934
+ ) internal pure returns (bytes32 a, bytes32 b, bytes32 c, bytes32 d, bytes32 e, uint end) {
935
+ (abs, end) = expectFixed(abs, spec, 160);
936
+ assembly ("memory-safe") {
937
+ a := calldataload(abs)
938
+ b := calldataload(add(abs, 0x20))
939
+ c := calldataload(add(abs, 0x40))
940
+ d := calldataload(add(abs, 0x60))
941
+ e := calldataload(add(abs, 0x80))
942
+ }
943
+ }
944
+
945
+ /// @notice Decode a spec-validated asset and amount pair.
946
+ /// @param abs Absolute block position.
947
+ /// @param spec Expected block specification.
948
+ /// @return asset Decoded asset identifier.
949
+ /// @return amount Decoded amount.
950
+ /// @return end Absolute position after the block.
951
+ function unpackAssetAmount(
952
+ uint abs,
953
+ uint spec
954
+ ) internal pure returns (bytes32 asset, uint amount, uint end) {
955
+ bytes32 value;
956
+ (asset, value, end) = unpack64(abs, spec);
957
+ amount = uint(value);
958
+ }
959
+
960
+ /// @notice Decode a spec-validated account, asset, and amount tuple.
961
+ /// @param abs Absolute block position.
962
+ /// @param spec Expected block specification.
963
+ /// @return account Decoded account identifier.
964
+ /// @return asset Decoded asset identifier.
965
+ /// @return amount Decoded amount.
966
+ /// @return end Absolute position after the block.
967
+ function unpackAccountAmount(
968
+ uint abs,
969
+ uint spec
970
+ ) internal pure returns (bytes32 account, bytes32 asset, uint amount, uint end) {
971
+ bytes32 value;
972
+ (account, asset, value, end) = unpack96(abs, spec);
973
+ amount = uint(value);
974
+ }
975
+
976
+ /// @notice Decode a spec-validated host, asset, and amount tuple.
977
+ /// @param abs Absolute block position.
978
+ /// @param spec Expected block specification.
979
+ /// @return host Decoded host identifier.
980
+ /// @return asset Decoded asset identifier.
981
+ /// @return amount Decoded amount.
982
+ /// @return end Absolute position after the block.
983
+ function unpackHostAmount(
984
+ uint abs,
985
+ uint spec
986
+ ) internal pure returns (uint host, bytes32 asset, uint amount, uint end) {
987
+ bytes32 value;
988
+ bytes32 raw;
989
+ (raw, asset, value, end) = unpack96(abs, spec);
990
+ host = uint(raw);
991
+ amount = uint(value);
992
+ }
993
+
994
+ /// @notice Decode a spec-validated host, account, and asset tuple.
995
+ /// @param abs Absolute block position.
996
+ /// @param spec Expected block specification.
997
+ /// @return host Decoded host identifier.
998
+ /// @return account Decoded account identifier.
999
+ /// @return asset Decoded asset identifier.
1000
+ /// @return end Absolute position after the block.
1001
+ function unpackHostAccountAsset(
1002
+ uint abs,
1003
+ uint spec
1004
+ ) internal pure returns (uint host, bytes32 account, bytes32 asset, uint end) {
1005
+ bytes32 raw;
1006
+ (raw, account, asset, end) = unpack96(abs, spec);
1007
+ host = uint(raw);
1008
+ }
1009
+
1010
+ /// @notice Decode a spec-validated transaction tuple.
1011
+ /// @param abs Absolute block position.
1012
+ /// @param spec Expected block specification.
1013
+ /// @return from Decoded debit account.
1014
+ /// @return to Decoded credit account.
1015
+ /// @return asset Decoded asset identifier.
1016
+ /// @return amount Decoded transaction amount.
1017
+ /// @return end Absolute position after the block.
1018
+ function unpackTransaction(
1019
+ uint abs,
1020
+ uint spec
1021
+ ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount, uint end) {
1022
+ bytes32 value;
1023
+ (from, to, asset, value, end) = unpack128(abs, spec);
1024
+ amount = uint(value);
1025
+ }
1026
+
1027
+ // Fixed-width block unpackers
1028
+
1029
+ /// @dev The fixed-width decoders below validate only the block key and
1030
+ /// payload length. Callers must ensure the complete block lies within
1031
+ /// their logical calldata region.
1032
+
1033
+ // One-word payloads
1034
+
1035
+ /// @notice Decode a low-level fixed-width ACCOUNT block at `abs`.
1036
+ /// @param abs Absolute block position.
1037
+ /// @return account Decoded account identifier.
1038
+ function unpackAccount(uint abs) internal pure returns (bytes32 account) {
1039
+ uint head;
1040
+ assembly ("memory-safe") {
1041
+ head := calldataload(abs)
1042
+ }
1043
+ if (head >> 192 != Specs.Account >> 192) revert InvalidBlock();
1044
+ assembly ("memory-safe") {
1045
+ account := calldataload(add(abs, 0x08))
1046
+ }
1047
+ }
1048
+
1049
+ /// @notice Decode a low-level fixed-width ASSET block at `abs`.
1050
+ /// @param abs Absolute block position.
1051
+ /// @return asset Decoded asset identifier.
1052
+ function unpackAsset(uint abs) internal pure returns (bytes32 asset) {
1053
+ uint head;
1054
+ assembly ("memory-safe") {
1055
+ head := calldataload(abs)
1056
+ }
1057
+ if (head >> 192 != Specs.Asset >> 192) revert InvalidBlock();
1058
+ assembly ("memory-safe") {
1059
+ asset := calldataload(add(abs, 0x08))
1060
+ }
1061
+ }
1062
+
1063
+ /// @notice Decode a low-level fixed-width NODE block at `abs`.
1064
+ /// @param abs Absolute block position.
1065
+ /// @return node Decoded node identifier.
1066
+ function unpackNode(uint abs) internal pure returns (uint node) {
1067
+ uint head;
1068
+ assembly ("memory-safe") {
1069
+ head := calldataload(abs)
1070
+ }
1071
+ if (head >> 192 != Specs.Node >> 192) revert InvalidBlock();
1072
+ assembly ("memory-safe") {
1073
+ node := calldataload(add(abs, 0x08))
1074
+ }
1075
+ }
1076
+
1077
+ /// @notice Decode a low-level fixed-width STATUS block at `abs`.
1078
+ /// @param abs Absolute block position.
1079
+ /// @return code Decoded status code.
1080
+ function unpackStatus(uint abs) internal pure returns (uint code) {
1081
+ uint head;
1082
+ assembly ("memory-safe") {
1083
+ head := calldataload(abs)
1084
+ }
1085
+ if (head >> 192 != Specs.Status >> 192) revert InvalidBlock();
1086
+ assembly ("memory-safe") {
1087
+ code := calldataload(add(abs, 0x08))
1088
+ }
1089
+ }
1090
+
1091
+ // Two-word payloads
1092
+
1093
+ /// @notice Decode a low-level fixed-width AMOUNT block at `abs`.
1094
+ /// @param abs Absolute block position.
1095
+ /// @return asset Decoded asset identifier.
1096
+ /// @return amount Decoded amount.
1097
+ function unpackAmount(uint abs) internal pure returns (bytes32 asset, uint amount) {
1098
+ uint head;
1099
+ assembly ("memory-safe") {
1100
+ head := calldataload(abs)
1101
+ }
1102
+ if (head >> 192 != Specs.Amount >> 192) revert InvalidBlock();
1103
+ assembly ("memory-safe") {
1104
+ asset := calldataload(add(abs, 0x08))
1105
+ amount := calldataload(add(abs, 0x28))
1106
+ }
1107
+ }
1108
+
1109
+ /// @notice Decode a low-level fixed-width BALANCE block at `abs`.
1110
+ /// @param abs Absolute block position.
1111
+ /// @return asset Decoded asset identifier.
1112
+ /// @return amount Decoded balance.
1113
+ function unpackBalance(uint abs) internal pure returns (bytes32 asset, uint amount) {
1114
+ uint head;
1115
+ assembly ("memory-safe") {
1116
+ head := calldataload(abs)
1117
+ }
1118
+ if (head >> 192 != Specs.Balance >> 192) revert InvalidBlock();
1119
+
1120
+ assembly ("memory-safe") {
1121
+ asset := calldataload(add(abs, 0x08))
1122
+ amount := calldataload(add(abs, 0x28))
1123
+ }
1124
+ }
1125
+
1126
+ /// @notice Decode a low-level fixed-width ACCOUNT_ASSET block at `abs`.
1127
+ /// @param abs Absolute block position.
1128
+ /// @return account Decoded account identifier.
1129
+ /// @return asset Decoded asset identifier.
1130
+ function unpackAccountAsset(uint abs) internal pure returns (bytes32 account, bytes32 asset) {
1131
+ uint head;
1132
+ assembly ("memory-safe") {
1133
+ head := calldataload(abs)
1134
+ }
1135
+ if (head >> 192 != Specs.AccountAsset >> 192) revert InvalidBlock();
1136
+ assembly ("memory-safe") {
1137
+ account := calldataload(add(abs, 0x08))
1138
+ asset := calldataload(add(abs, 0x28))
1139
+ }
1140
+ }
1141
+
1142
+ // Three-word payloads
1143
+
1144
+ /// @notice Decode a low-level fixed-width ALLOCATION block at `abs`.
1145
+ /// @param abs Absolute block position.
1146
+ /// @return host Decoded host identifier.
1147
+ /// @return asset Decoded asset identifier.
1148
+ /// @return amount Decoded allocation.
1149
+ function unpackAllocation(uint abs) internal pure returns (uint host, bytes32 asset, uint amount) {
1150
+ uint head;
1151
+ assembly ("memory-safe") {
1152
+ head := calldataload(abs)
1153
+ }
1154
+ if (head >> 192 != Specs.Allocation >> 192) revert InvalidBlock();
1155
+ assembly ("memory-safe") {
1156
+ host := calldataload(add(abs, 0x08))
1157
+ asset := calldataload(add(abs, 0x28))
1158
+ amount := calldataload(add(abs, 0x48))
1159
+ }
1160
+ }
1161
+
1162
+ /// @notice Decode a low-level fixed-width ALLOWANCE block at `abs`.
1163
+ /// @param abs Absolute block position.
1164
+ /// @return host Decoded host identifier.
1165
+ /// @return asset Decoded asset identifier.
1166
+ /// @return amount Decoded allowance.
1167
+ function unpackAllowance(uint abs) internal pure returns (uint host, bytes32 asset, uint amount) {
1168
+ uint head;
1169
+ assembly ("memory-safe") {
1170
+ head := calldataload(abs)
1171
+ }
1172
+ if (head >> 192 != Specs.Allowance >> 192) revert InvalidBlock();
1173
+ assembly ("memory-safe") {
1174
+ host := calldataload(add(abs, 0x08))
1175
+ asset := calldataload(add(abs, 0x28))
1176
+ amount := calldataload(add(abs, 0x48))
1177
+ }
1178
+ }
1179
+
1180
+ /// @notice Decode a low-level fixed-width CUSTODY block at `abs`.
1181
+ /// @param abs Absolute block position.
1182
+ /// @return host Decoded host identifier.
1183
+ /// @return asset Decoded asset identifier.
1184
+ /// @return amount Decoded custody amount.
1185
+ function unpackCustody(uint abs) internal pure returns (uint host, bytes32 asset, uint amount) {
1186
+ uint head;
1187
+ assembly ("memory-safe") {
1188
+ head := calldataload(abs)
1189
+ }
1190
+ if (head >> 192 != Specs.Custody >> 192) revert InvalidBlock();
1191
+ assembly ("memory-safe") {
1192
+ host := calldataload(add(abs, 0x08))
1193
+ asset := calldataload(add(abs, 0x28))
1194
+ amount := calldataload(add(abs, 0x48))
1195
+ }
1196
+ }
1197
+
1198
+ /// @notice Decode a low-level fixed-width ACCOUNT_AMOUNT block at `abs`.
1199
+ /// @param abs Absolute block position.
1200
+ /// @return account Decoded account identifier.
1201
+ /// @return asset Decoded asset identifier.
1202
+ /// @return amount Decoded amount.
1203
+ function unpackAccountAmount(uint abs) internal pure returns (bytes32 account, bytes32 asset, uint amount) {
1204
+ uint head;
1205
+ assembly ("memory-safe") {
1206
+ head := calldataload(abs)
1207
+ }
1208
+ if (head >> 192 != Specs.AccountAmount >> 192) revert InvalidBlock();
1209
+ assembly ("memory-safe") {
1210
+ account := calldataload(add(abs, 0x08))
1211
+ asset := calldataload(add(abs, 0x28))
1212
+ amount := calldataload(add(abs, 0x48))
1213
+ }
1214
+ }
1215
+
1216
+ /// @notice Decode a low-level fixed-width HOST_AMOUNT block at `abs`.
1217
+ /// @param abs Absolute block position.
1218
+ /// @return host Decoded host identifier.
1219
+ /// @return asset Decoded asset identifier.
1220
+ /// @return amount Decoded amount.
1221
+ function unpackHostAmount(uint abs) internal pure returns (uint host, bytes32 asset, uint amount) {
1222
+ uint head;
1223
+ assembly ("memory-safe") {
1224
+ head := calldataload(abs)
1225
+ }
1226
+ if (head >> 192 != Specs.HostAmount >> 192) revert InvalidBlock();
1227
+ assembly ("memory-safe") {
1228
+ host := calldataload(add(abs, 0x08))
1229
+ asset := calldataload(add(abs, 0x28))
1230
+ amount := calldataload(add(abs, 0x48))
1231
+ }
1232
+ }
1233
+
1234
+ /// @notice Decode a low-level fixed-width HOST_ACCOUNT_ASSET block at `abs`.
1235
+ /// @param abs Absolute block position.
1236
+ /// @return host Decoded host identifier.
1237
+ /// @return account Decoded account identifier.
1238
+ /// @return asset Decoded asset identifier.
1239
+ function unpackHostAccountAsset(uint abs) internal pure returns (uint host, bytes32 account, bytes32 asset) {
1240
+ uint head;
1241
+ assembly ("memory-safe") {
1242
+ head := calldataload(abs)
1243
+ }
1244
+ if (head >> 192 != Specs.HostAccountAsset >> 192) revert InvalidBlock();
1245
+ assembly ("memory-safe") {
1246
+ host := calldataload(add(abs, 0x08))
1247
+ account := calldataload(add(abs, 0x28))
1248
+ asset := calldataload(add(abs, 0x48))
1249
+ }
1250
+ }
1251
+
1252
+ // Four-word payloads
1253
+
1254
+ /// @notice Decode a low-level fixed-width TRANSACTION block at `abs`.
1255
+ /// @param abs Absolute block position.
1256
+ /// @return from Decoded debit account.
1257
+ /// @return to Decoded credit account.
1258
+ /// @return asset Decoded asset identifier.
1259
+ /// @return amount Decoded transaction amount.
1260
+ function unpackTransaction(uint abs) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
1261
+ uint head;
1262
+ assembly ("memory-safe") {
1263
+ head := calldataload(abs)
1264
+ }
1265
+ if (head >> 192 != Specs.Transaction >> 192) revert InvalidBlock();
1266
+ assembly ("memory-safe") {
1267
+ from := calldataload(add(abs, 0x08))
1268
+ to := calldataload(add(abs, 0x28))
1269
+ asset := calldataload(add(abs, 0x48))
1270
+ amount := calldataload(add(abs, 0x68))
1271
+ }
1272
+ }
1273
+
1274
+ /// @notice Decode a low-level fixed-width HOST_ACCOUNT_AMOUNT block at `abs`.
1275
+ /// @param abs Absolute block position.
1276
+ /// @return host Decoded host identifier.
1277
+ /// @return account Decoded account identifier.
1278
+ /// @return asset Decoded asset identifier.
1279
+ /// @return amount Decoded amount.
1280
+ function unpackHostAccountAmount(
1281
+ uint abs
1282
+ ) internal pure returns (uint host, bytes32 account, bytes32 asset, uint amount) {
1283
+ uint head;
1284
+ assembly ("memory-safe") {
1285
+ head := calldataload(abs)
1286
+ }
1287
+ if (head >> 192 != Specs.HostAccountAmount >> 192) revert InvalidBlock();
1288
+ assembly ("memory-safe") {
1289
+ host := calldataload(add(abs, 0x08))
1290
+ account := calldataload(add(abs, 0x28))
1291
+ asset := calldataload(add(abs, 0x48))
1292
+ amount := calldataload(add(abs, 0x68))
1293
+ }
1294
+ }
1295
+
1296
+ // Dynamic leaf blocks
1297
+
1298
+ /// @notice Decode one LIST payload and its absolute end position.
1299
+ /// @param abs Absolute block position.
1300
+ /// @return value Decoded list payload.
1301
+ /// @return end Absolute position after the block.
1302
+ function unpackList(uint abs) internal pure returns (bytes calldata value, uint end) {
1303
+ return unpackRaw(abs, Keys.List);
1304
+ }
1305
+
1306
+ /// @notice Decode one EVM payload and its absolute end position.
1307
+ /// @param abs Absolute block position.
1308
+ /// @return value Decoded EVM payload.
1309
+ /// @return end Absolute position after the block.
1310
+ function unpackEvm(uint abs) internal pure returns (bytes calldata value, uint end) {
1311
+ return unpackRaw(abs, Keys.Evm);
1312
+ }
1313
+
1314
+ /// @notice Decode one BYTES payload and its absolute end position.
1315
+ /// @param abs Absolute block position.
1316
+ /// @return value Decoded byte payload.
1317
+ /// @return end Absolute position after the block.
1318
+ function unpackBytes(uint abs) internal pure returns (bytes calldata value, uint end) {
1319
+ return unpackRaw(abs, Keys.Bytes);
1320
+ }
1321
+
1322
+ /// @notice Decode one STRING payload and its absolute end position.
1323
+ /// @param abs Absolute block position.
1324
+ /// @return value Decoded string bytes.
1325
+ /// @return end Absolute position after the block.
1326
+ function unpackString(uint abs) internal pure returns (bytes calldata value, uint end) {
1327
+ return unpackRaw(abs, Keys.String);
1328
+ }
1329
+
1330
+ /// @dev Decode a dynamic leaf block after validating its key.
1331
+ /// @param abs Absolute block position.
1332
+ /// @param expected Expected block key.
1333
+ /// @return value Decoded payload.
1334
+ /// @return end Absolute position after the block.
1335
+ function unpackRaw(uint abs, bytes4 expected) private pure returns (bytes calldata value, uint end) {
1336
+ uint len = header(abs, expected);
1337
+ assembly ("memory-safe") {
1338
+ value.offset := add(abs, 0x08)
1339
+ value.length := len
1340
+ }
1341
+ end = abs + Sizes.Header + len;
1342
+ }
1343
+
1344
+ // Composite blocks
1345
+
1346
+ // One fixed word
1347
+
1348
+ /// @notice Decode one CONTEXT block and all nested byte blocks.
1349
+ /// @param abs Absolute block position.
1350
+ /// @return account Decoded account identifier.
1351
+ /// @return state Decoded state payload.
1352
+ /// @return input Decoded input payload.
1353
+ /// @return end Absolute position after the block.
1354
+ function unpackContext(
1355
+ uint abs
1356
+ ) internal pure returns (bytes32 account, bytes calldata state, bytes calldata input, uint end) {
1357
+ uint limit;
1358
+ (abs, limit) = expect(abs, Specs.Context);
1359
+ assembly ("memory-safe") {
1360
+ account := calldataload(abs)
1361
+ }
1362
+ (state, end) = unpackBytes(abs + 32);
1363
+ (input, end) = unpackBytes(end);
1364
+ if (end != limit) revert InvalidBlock();
1365
+ }
1366
+
1367
+ // Two fixed words
1368
+
1369
+ /// @notice Decode one STEP block and its nested input.
1370
+ /// @param abs Absolute block position.
1371
+ /// @return cmd Decoded command identifier.
1372
+ /// @return resources Decoded packed resources.
1373
+ /// @return input Decoded command input.
1374
+ /// @return end Absolute position after the block.
1375
+ function unpackStep(
1376
+ uint abs
1377
+ ) internal pure returns (uint cmd, uint resources, bytes calldata input, uint end) {
1378
+ uint limit;
1379
+ (abs, limit) = expect(abs, Specs.Step);
1380
+ assembly ("memory-safe") {
1381
+ cmd := calldataload(abs)
1382
+ resources := calldataload(add(abs, 0x20))
1383
+ }
1384
+ (input, end) = unpackBytes(abs + 64);
1385
+ if (end != limit) revert InvalidBlock();
1386
+ }
1387
+
1388
+ /// @notice Decode one CALL block and its nested payload.
1389
+ /// @param abs Absolute block position.
1390
+ /// @return target Decoded call target.
1391
+ /// @return resources Decoded packed resources.
1392
+ /// @return payload Decoded call payload.
1393
+ /// @return end Absolute position after the block.
1394
+ function unpackCall(
1395
+ uint abs
1396
+ ) internal pure returns (uint target, uint resources, bytes calldata payload, uint end) {
1397
+ uint limit;
1398
+ (abs, limit) = expect(abs, Specs.Call);
1399
+ assembly ("memory-safe") {
1400
+ target := calldataload(abs)
1401
+ resources := calldataload(add(abs, 0x20))
1402
+ }
1403
+ (payload, end) = unpackBytes(abs + 64);
1404
+ if (end != limit) revert InvalidBlock();
1405
+ }
1406
+
1407
+ /// @notice Decode one RELAY block and its nested input.
1408
+ /// @param abs Absolute block position.
1409
+ /// @return portal Decoded destination portal.
1410
+ /// @return resources Decoded packed resources.
1411
+ /// @return input Decoded relay input.
1412
+ /// @return end Absolute position after the block.
1413
+ function unpackRelay(
1414
+ uint abs
1415
+ ) internal pure returns (uint portal, uint resources, bytes calldata input, uint end) {
1416
+ uint limit;
1417
+ (abs, limit) = expect(abs, Specs.Relay);
1418
+ assembly ("memory-safe") {
1419
+ portal := calldataload(abs)
1420
+ resources := calldataload(add(abs, 0x20))
1421
+ }
1422
+ (input, end) = unpackBytes(abs + 64);
1423
+ if (end != limit) revert InvalidBlock();
1424
+ }
1425
+
1426
+ /// @notice Decode one DISPATCH block and its nested payload.
1427
+ /// @param abs Absolute block position.
1428
+ /// @return portal Decoded destination portal.
1429
+ /// @return resources Decoded packed resources.
1430
+ /// @return payload Decoded dispatch payload.
1431
+ /// @return end Absolute position after the block.
1432
+ function unpackDispatch(
1433
+ uint abs
1434
+ ) internal pure returns (uint portal, uint resources, bytes calldata payload, uint end) {
1435
+ uint limit;
1436
+ (abs, limit) = expect(abs, Specs.Dispatch);
1437
+ assembly ("memory-safe") {
1438
+ portal := calldataload(abs)
1439
+ resources := calldataload(add(abs, 0x20))
1440
+ }
1441
+ (payload, end) = unpackBytes(abs + 64);
1442
+ if (end != limit) revert InvalidBlock();
1443
+ }
1444
+
1445
+ /// @notice Decode one LABEL block and its nested name.
1446
+ /// @param abs Absolute block position.
1447
+ /// @return id Decoded node identifier.
1448
+ /// @return namespace Decoded label namespace.
1449
+ /// @return name Decoded label text.
1450
+ /// @return end Absolute position after the block.
1451
+ function unpackLabel(uint abs) internal pure returns (uint id, bytes32 namespace, string memory name, uint end) {
1452
+ uint limit;
1453
+ (abs, limit) = expect(abs, Specs.Label);
1454
+ assembly ("memory-safe") {
1455
+ id := calldataload(abs)
1456
+ namespace := calldataload(add(abs, 0x20))
1457
+ }
1458
+ bytes calldata value;
1459
+ (value, end) = unpackString(abs + 64);
1460
+ if (end != limit) revert InvalidBlock();
1461
+ name = string(value);
1462
+ }
1463
+
1464
+ /// @notice Decode one SCHEMA block and its nested body.
1465
+ /// @param abs Absolute block position.
1466
+ /// @return spec Decoded block specification.
1467
+ /// @return body Decoded schema body.
1468
+ /// @return name Decoded schema name.
1469
+ /// @return end Absolute position after the block.
1470
+ function unpackSchema(uint abs) internal pure returns (uint spec, string memory body, bytes32 name, uint end) {
1471
+ uint limit;
1472
+ (abs, limit) = expect(abs, Specs.Schema);
1473
+ assembly ("memory-safe") {
1474
+ spec := calldataload(abs)
1475
+ }
1476
+ bytes calldata value;
1477
+ (value, end) = unpackString(abs + 32);
1478
+ if (end + 32 != limit) revert InvalidBlock();
1479
+ assembly ("memory-safe") {
1480
+ name := calldataload(end)
1481
+ }
1482
+ end = limit;
1483
+ body = string(value);
1484
+ }
1485
+
1486
+ // Three fixed words
1487
+
1488
+ /// @notice Decode one RECOVER block and its nested witness.
1489
+ /// @param abs Absolute block position.
1490
+ /// @return handler Decoded recovery handler.
1491
+ /// @return resources Decoded packed resources.
1492
+ /// @return key Decoded recovery key.
1493
+ /// @return witness Decoded recovery witness.
1494
+ /// @return end Absolute position after the block.
1495
+ function unpackRecover(
1496
+ uint abs
1497
+ ) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness, uint end) {
1498
+ uint limit;
1499
+ (abs, limit) = expect(abs, Specs.Recover);
1500
+ assembly ("memory-safe") {
1501
+ handler := calldataload(abs)
1502
+ resources := calldataload(add(abs, 0x20))
1503
+ key := calldataload(add(abs, 0x40))
1504
+ }
1505
+ (witness, end) = unpackBytes(abs + 96);
1506
+ if (end != limit) revert InvalidBlock();
1507
+ }
1508
+
1509
+ // -------------------------------------------------------------------------
1510
+ // Block factory helpers
1511
+ // -------------------------------------------------------------------------
1512
+
1513
+ /// @notice Encode a block with a raw payload.
1514
+ /// @param key Block type key.
1515
+ /// @param payload Raw payload bytes.
1516
+ /// @return Encoded block bytes.
1517
+ function create(bytes4 key, bytes memory payload) internal pure returns (bytes memory) {
1518
+ return bytes.concat(key, bytes4(uint32(payload.length)), payload);
1519
+ }
1520
+
1521
+ /// @notice Encode a BYTES block with a raw payload.
1522
+ /// @param value Raw payload bytes.
1523
+ /// @return Encoded BYTES block bytes.
1524
+ function data(bytes memory value) internal pure returns (bytes memory) {
1525
+ return create(Keys.Bytes, value);
1526
+ }
1527
+
1528
+ /// @notice Encode a STRING block with a UTF-8 payload.
1529
+ /// @param value String payload.
1530
+ /// @return Encoded STRING block bytes.
1531
+ function text(string memory value) internal pure returns (bytes memory) {
1532
+ return create(Keys.String, bytes(value));
1533
+ }
1534
+
1535
+ /// @notice Encode a BALANCE block.
1536
+ /// @param asset Asset identifier.
1537
+ /// @param amount Token amount.
1538
+ /// @return Encoded BALANCE block bytes.
1539
+ function balance(bytes32 asset, uint amount) internal pure returns (bytes memory) {
1540
+ return bytes.concat(Keys.Balance, bytes4(uint32(64)), asset, bytes32(amount));
1541
+ }
1542
+
1543
+ /// @notice Encode a CUSTODY block.
1544
+ /// @param host Host node ID holding the custody.
1545
+ /// @param asset Asset identifier.
1546
+ /// @param amount Token amount.
1547
+ /// @return Encoded CUSTODY block bytes.
1548
+ function custody(uint host, bytes32 asset, uint amount) internal pure returns (bytes memory) {
1549
+ return bytes.concat(Keys.Custody, bytes4(uint32(96)), bytes32(host), asset, bytes32(amount));
1550
+ }
1551
+
1552
+ /// @notice Encode a TRANSACTION block.
1553
+ /// @param from Source account identifier.
1554
+ /// @param to Destination account identifier.
1555
+ /// @param asset Asset identifier.
1556
+ /// @param amount Transfer amount.
1557
+ /// @return Encoded TRANSACTION block bytes.
1558
+ function transaction(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal pure returns (bytes memory) {
1559
+ return bytes.concat(Keys.Transaction, bytes4(uint32(128)), from, to, asset, bytes32(amount));
1560
+ }
1561
+
1562
+ /// @notice Encode a STEP block.
1563
+ /// @param cmd Command identifier.
1564
+ /// @param resources Packed resources assigned to the step.
1565
+ /// @param input Raw nested input payload.
1566
+ /// @return Encoded STEP block bytes.
1567
+ function step(uint cmd, uint resources, bytes memory input) internal pure returns (bytes memory) {
1568
+ return create(Keys.Step, bytes.concat(bytes32(cmd), bytes32(resources), data(input)));
1569
+ }
1570
+
1571
+ /// @notice Encode a CALL block.
1572
+ /// @param target Target node identifier.
1573
+ /// @param resources Packed resources assigned to the call.
1574
+ /// @param payload Raw calldata payload for the target.
1575
+ /// @return Encoded CALL block bytes.
1576
+ function call(uint target, uint resources, bytes memory payload) internal pure returns (bytes memory) {
1577
+ return create(Keys.Call, bytes.concat(bytes32(target), bytes32(resources), data(payload)));
1578
+ }
1579
+
1580
+ /// @notice Encode a CONTEXT block.
1581
+ /// @param account Command account identifier.
1582
+ /// @param state Embedded state block stream.
1583
+ /// @param input Embedded input block stream.
1584
+ /// @return Encoded CONTEXT block bytes.
1585
+ function context(bytes32 account, bytes memory state, bytes memory input) internal pure returns (bytes memory) {
1586
+ return create(Keys.Context, bytes.concat(account, data(state), data(input)));
1587
+ }
1588
+
1589
+ /// @notice Encode a RELAY block.
1590
+ /// @param portal Destination portal identifier, often the destination host ID.
1591
+ /// @param resources Chain-specific resources for the destination context.
1592
+ /// @param input Nested input block stream.
1593
+ /// @return Encoded RELAY block bytes.
1594
+ function relay(uint portal, uint resources, bytes memory input) internal pure returns (bytes memory) {
1595
+ return create(Keys.Relay, bytes.concat(bytes32(portal), bytes32(resources), data(input)));
1596
+ }
1597
+
1598
+ /// @notice Encode a DISPATCH block.
1599
+ /// @param portal Destination portal identifier, often the destination host ID.
1600
+ /// @param resources Chain-specific resources for the destination dispatch.
1601
+ /// @param payload Encoded payload.
1602
+ /// @return Encoded DISPATCH block bytes.
1603
+ function dispatch(uint portal, uint resources, bytes memory payload) internal pure returns (bytes memory) {
1604
+ return create(Keys.Dispatch, bytes.concat(bytes32(portal), bytes32(resources), data(payload)));
1605
+ }
1606
+ }