@rootzero/contracts 1.25.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/Codec.sol +1 -2
  3. package/Endpoints.sol +2 -0
  4. package/README.md +61 -51
  5. package/Utils.sol +2 -1
  6. package/codec/Blocks.sol +276 -88
  7. package/codec/Buffers.sol +24 -20
  8. package/codec/Decoders.sol +35 -37
  9. package/codec/Descriptors.sol +75 -72
  10. package/codec/Keys.sol +5 -1
  11. package/codec/Schema.sol +5 -1
  12. package/codec/Specs.sol +19 -9
  13. package/codec/Writers.sol +14 -19
  14. package/commands/Allocate.sol +8 -7
  15. package/commands/Base.sol +14 -49
  16. package/commands/Bootstrap.sol +95 -0
  17. package/commands/Burn.sol +7 -7
  18. package/commands/Cashout.sol +85 -0
  19. package/commands/Credit.sol +18 -16
  20. package/commands/Debit.sol +23 -19
  21. package/commands/Deposit.sol +13 -13
  22. package/commands/Payout.sol +8 -8
  23. package/commands/Provision.sol +13 -13
  24. package/commands/Recover.sol +7 -7
  25. package/commands/Relay.sol +22 -23
  26. package/commands/Repay.sol +36 -34
  27. package/commands/Settle.sol +24 -22
  28. package/commands/Withdraw.sol +7 -7
  29. package/commands/admin/AllowAssets.sol +7 -7
  30. package/commands/admin/Allowance.sol +7 -7
  31. package/commands/admin/Annotate.sol +7 -7
  32. package/commands/admin/Appoint.sol +7 -7
  33. package/commands/admin/Authorize.sol +7 -7
  34. package/commands/admin/Base.sol +5 -8
  35. package/commands/admin/DenyAssets.sol +7 -7
  36. package/commands/admin/Dismiss.sol +7 -7
  37. package/commands/admin/Execute.sol +8 -8
  38. package/commands/admin/Unauthorize.sol +7 -7
  39. package/core/Calls.sol +3 -3
  40. package/core/Endpoint.sol +7 -7
  41. package/core/Pipeline.sol +19 -20
  42. package/execution/Budget.sol +2 -3
  43. package/execution/Execution.sol +271 -509
  44. package/guards/Base.sol +1 -1
  45. package/guards/Revoke.sol +7 -7
  46. package/package.json +1 -1
  47. package/ports/Allowance.sol +3 -3
  48. package/ports/Assets.sol +7 -7
  49. package/ports/Base.sol +1 -1
  50. package/ports/Credit.sol +3 -3
  51. package/ports/Debit.sol +3 -3
  52. package/ports/Dispatch.sol +3 -3
  53. package/ports/Pipe.sol +3 -3
  54. package/ports/Post.sol +3 -3
  55. package/ports/Redeem.sol +3 -3
  56. package/queries/Assets.sol +3 -3
  57. package/queries/Balances.sol +3 -3
  58. package/queries/Base.sol +1 -1
  59. package/utils/Accounts.sol +1 -3
  60. package/utils/Actions.sol +2 -0
  61. package/utils/Assets.sol +1 -10
  62. package/utils/Cursors.sol +60 -116
  63. package/utils/Errors.sol +50 -0
  64. package/utils/Ids.sol +2 -5
  65. package/utils/Lanes.sol +0 -2
  66. package/utils/Nodes.sol +1 -3
  67. package/utils/Utils.sol +2 -9
  68. package/codec/Readers.sol +0 -190
package/utils/Cursors.sol CHANGED
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
- import {clear32, max16, max32, max128} from "./Utils.sol";
4
+ import {MissingCursor, OutOfBounds, UnexpectedPosition, ValueOverflow} from "./Errors.sol";
5
5
 
6
6
  /// @notice Mutable memory wrapper around a packed cursor.
7
7
  /// @dev A second tagged cursor may occupy the upper 128-bit lane of `state`.
@@ -17,7 +17,8 @@ struct Cur {
17
17
  /// bits 0-31 i
18
18
  /// bits 32-63 offset
19
19
  /// bits 64-95 len
20
- /// bits 96-111 count (opaque consumer metadata)
20
+ /// bits 96-103 stride (optional blocks per group)
21
+ /// bits 104-111 reserved
21
22
  /// bits 112-119 flags (consumer-defined)
22
23
  /// bits 120-127 tag
23
24
  ///
@@ -27,15 +28,6 @@ struct Cur {
27
28
  /// inspection operations target it, and `select` swaps a requested tagged
28
29
  /// cursor into that position while preserving the pair.
29
30
  ///
30
- /// A mark is a standalone cursor value used as an immutable positional
31
- /// reference. It retains the cursor's offset, length, count, flags, and tag,
32
- /// but may carry a different `i`. A mark has no intrinsic boundary or movement
33
- /// semantics; callers may later use its position for comparison, validation,
34
- /// seeking, or another operation. Because it has the ordinary single-cursor
35
- /// layout, existing positional decoding and absolute-position rules also apply
36
- /// to marks. A zero mark identifies the empty cursor at position zero; `before`
37
- /// therefore treats it as already reached.
38
- ///
39
31
  /// Cursor navigation assumes packed cursor inputs satisfy `i <= len`.
40
32
  /// Constructors and composition helpers establish this invariant, and navigation
41
33
  /// helpers preserve it. Manually constructing or modifying packed cursor words
@@ -43,33 +35,20 @@ struct Cur {
43
35
  ///
44
36
  /// The zero word represents an absent cursor.
45
37
  library Cursors {
46
- /// @dev A cursor position exceeds its logical length.
47
- error OutOfBounds();
48
-
49
- /// @dev A cursor is not positioned at the expected offset.
50
- error UnexpectedPosition();
51
-
52
- /// @dev Paired cursors must have different identity tags.
53
- error DuplicateTag(uint8 tag);
54
-
55
- /// @dev Neither packed cursor matches the requested identity.
56
- error MissingCursor();
57
-
58
38
  // Creation and sources
59
39
 
60
40
  /// @notice Create a cursor positioned at its beginning.
61
41
  /// @param offset Absolute source or buffer offset.
62
42
  /// @param len Logical byte length.
63
- /// @param items Opaque item count associated with the region.
43
+ /// @param stride Optional blocks per group associated with the region.
64
44
  /// @param flags Consumer-defined flags.
65
45
  /// @param tag Cursor identity tag.
66
46
  /// @return cur Packed cursor.
67
- function create(uint offset, uint len, uint items, uint8 flags, uint8 tag) internal pure returns (uint cur) {
68
- cur |= uint(max32(offset)) << 32;
69
- cur |= uint(max32(len)) << 64;
70
- cur |= uint(max16(items)) << 96;
71
- cur |= uint(flags) << 112;
72
- cur |= uint(tag) << 120;
47
+ function create(uint offset, uint len, uint8 stride, uint8 flags, uint8 tag) internal pure returns (uint cur) {
48
+ if (offset > type(uint32).max || len > type(uint32).max) {
49
+ revert ValueOverflow();
50
+ }
51
+ cur = (offset << 32) | (len << 64) | (uint(stride) << 96) | (uint(flags) << 112) | (uint(tag) << 120);
73
52
  }
74
53
 
75
54
  /// @notice Return the absolute calldata position where `source` begins.
@@ -86,17 +65,30 @@ library Cursors {
86
65
  /// @return abs Absolute start position.
87
66
  /// @return end Absolute exclusive end position.
88
67
  function bounds(bytes calldata source) internal pure returns (uint abs, uint end) {
89
- abs = base(source);
90
- end = abs + source.length;
68
+ assembly ("memory-safe") {
69
+ abs := source.offset
70
+ end := add(abs, source.length)
71
+ }
72
+ }
73
+
74
+ /// @notice Return the absolute start and exclusive end of the lower cursor frame.
75
+ /// @dev Ignores the cursor's current relative position and any upper cursor.
76
+ /// @param cur Packed cursor or cursor pair whose active frame is inspected.
77
+ /// @return abs Absolute frame start position.
78
+ /// @return end Absolute exclusive frame end position.
79
+ function bounds(uint cur) internal pure returns (uint abs, uint end) {
80
+ abs = uint32(cur >> 32);
81
+ end = abs + uint32(cur >> 64);
91
82
  }
92
83
 
93
84
  /// @notice Create a cursor backed by a calldata slice.
94
85
  /// @param source Calldata slice represented by the cursor.
95
- /// @param flags Consumer-defined flags.
96
86
  /// @param tag Cursor identity tag.
97
87
  /// @return cur Packed cursor positioned at the slice beginning.
98
- function wrap(bytes calldata source, uint8 flags, uint8 tag) internal pure returns (uint cur) {
99
- cur = create(base(source), source.length, 0, flags, tag);
88
+ function wrap(bytes calldata source, uint8 tag) internal pure returns (uint cur) {
89
+ assembly ("memory-safe") {
90
+ cur := or(or(shl(32, source.offset), shl(64, source.length)), shl(120, tag))
91
+ }
100
92
  }
101
93
 
102
94
  // Inspection
@@ -115,9 +107,9 @@ library Cursors {
115
107
  /// @notice Return the active cursor without its position.
116
108
  /// @dev Ignores the upper cursor when `cur` is a pair.
117
109
  /// @param cur Packed cursor or cursor pair.
118
- /// @return The lower cursor's offset, length, count, flags, and tag.
110
+ /// @return The lower cursor's offset, length, stride, flags, and tag.
119
111
  function frame(uint cur) internal pure returns (uint) {
120
- return clear32(uint128(cur), 0);
112
+ return uint128(cur) & ~uint(type(uint32).max);
121
113
  }
122
114
 
123
115
  /// @notice Return the absolute position of the lower cursor as `offset + i`.
@@ -128,22 +120,17 @@ library Cursors {
128
120
  return uint32(cur) + uint32(cur >> 32);
129
121
  }
130
122
 
131
- /// @notice Decode the consumer metadata and identity tag from the lower cursor.
123
+ /// @notice Decode the optional stride, consumer flags, and identity tag.
132
124
  /// @param cur Packed cursor or cursor pair.
133
- /// @return items Opaque item count.
125
+ /// @return stride Optional blocks per group.
134
126
  /// @return flags Consumer-defined flags.
135
127
  /// @return tag Cursor identity tag.
136
- function meta(uint cur) internal pure returns (uint items, uint8 flags, uint8 tag) {
137
- items = uint16(cur >> 96);
128
+ function meta(uint cur) internal pure returns (uint8 stride, uint8 flags, uint8 tag) {
129
+ stride = uint8(cur >> 96);
138
130
  flags = uint8(cur >> 112);
139
131
  tag = uint8(cur >> 120);
140
132
  }
141
133
 
142
- /// @notice Return the opaque item count attached to the active cursor.
143
- function count(uint cur) internal pure returns (uint) {
144
- return uint16(cur >> 96);
145
- }
146
-
147
134
  /// @notice Return whether both packed cursors remain at their initial positions.
148
135
  /// @param cur Packed cursor or cursor pair.
149
136
  /// @return Whether both lane positions are zero.
@@ -162,7 +149,7 @@ library Cursors {
162
149
  /// @param cur Packed cursor or cursor pair.
163
150
  /// @return Whether either lane has bytes remaining.
164
151
  function any(uint cur) internal pure returns (bool) {
165
- return more(cur) || more(cur >> 128);
152
+ return uint32(cur) < uint32(cur >> 64) || uint32(cur >> 128) < uint32(cur >> 192);
166
153
  }
167
154
 
168
155
  /// @notice Require the lower cursor to be positioned at `i`.
@@ -176,7 +163,7 @@ library Cursors {
176
163
  /// @param cur Packed cursor or cursor pair.
177
164
  /// @param abs Expected absolute position.
178
165
  function expectAbs(uint cur, uint abs) internal pure {
179
- if (absolute(cur) != abs) revert UnexpectedPosition();
166
+ if (uint32(cur) + uint32(cur >> 32) != abs) revert UnexpectedPosition();
180
167
  }
181
168
 
182
169
  /// @notice Return whether the lower cursor contains `flag`.
@@ -189,14 +176,6 @@ library Cursors {
189
176
 
190
177
  // Navigation
191
178
 
192
- /// @dev Return `cur` after ensuring its lower position does not exceed its length.
193
- /// @param cur Packed cursor or cursor pair.
194
- /// @return Validated cursor unchanged.
195
- function validate(uint cur) private pure returns (uint) {
196
- if (uint32(cur) > uint32(cur >> 64)) revert OutOfBounds();
197
- return cur;
198
- }
199
-
200
179
  /// @notice Move the lower cursor forward to `i`.
201
180
  /// @param cur Packed cursor or cursor pair.
202
181
  /// @param i New relative position; must not move backward.
@@ -205,7 +184,7 @@ library Cursors {
205
184
  uint current = uint32(cur);
206
185
  uint len = uint32(cur >> 64);
207
186
  if (i < current || i > len) revert OutOfBounds();
208
- updated = clear32(cur, 0) | i;
187
+ updated = (cur & ~uint(type(uint32).max)) | i;
209
188
  }
210
189
 
211
190
  /// @notice Replace the lower cursor's position using an absolute position.
@@ -215,7 +194,9 @@ library Cursors {
215
194
  function seekAbs(uint cur, uint abs) internal pure returns (uint updated) {
216
195
  uint offset = uint32(cur >> 32);
217
196
  if (abs < offset) revert OutOfBounds();
218
- updated = seek(cur, abs - offset);
197
+ uint i = abs - offset;
198
+ if (i < uint32(cur) || i > uint32(cur >> 64)) revert OutOfBounds();
199
+ updated = (cur & ~uint(type(uint32).max)) | i;
219
200
  }
220
201
 
221
202
  /// @notice Advance the current position of the lower cursor.
@@ -236,8 +217,9 @@ library Cursors {
236
217
  /// @param len New logical length.
237
218
  /// @return updated Cursor with the replaced length.
238
219
  function resize(uint cur, uint len) internal pure returns (uint updated) {
239
- if (uint32(cur) > max32(len)) revert OutOfBounds();
240
- updated = clear32(cur, 64) | (len << 64);
220
+ if (len > type(uint32).max) revert ValueOverflow();
221
+ if (uint32(cur) > len) revert OutOfBounds();
222
+ updated = (cur & ~(uint(type(uint32).max) << 64)) | (len << 64);
241
223
  }
242
224
 
243
225
  /// @notice Create a child cursor over `[start, end)` within the lower cursor.
@@ -250,30 +232,15 @@ library Cursors {
250
232
  /// @param tag Child identity tag.
251
233
  /// @return child Packed child cursor.
252
234
  function slice(uint cur, uint start, uint end, uint8 tag) internal pure returns (uint child) {
253
- (, uint offset, uint len) = decode(cur);
235
+ uint offset = uint32(cur >> 32);
236
+ uint len = uint32(cur >> 64);
254
237
  if (start > end || end > len) revert OutOfBounds();
255
- child = create(offset + start, end - start, 0, 0, tag);
238
+ uint childOffset = offset + start;
239
+ if (childOffset > type(uint32).max) revert ValueOverflow();
240
+ child = (childOffset << 32) | ((end - start) << 64) | (uint(tag) << 120);
256
241
  }
257
242
 
258
- // Pairing and selection
259
-
260
- /// @notice Combine two cursors into one packed word.
261
- /// @dev Zero represents absence and acts as the identity value.
262
- /// @param low Cursor placed in the lower lane.
263
- /// @param high Cursor placed in the higher lane.
264
- /// @return cur Packed cursor pair, or the nonzero cursor when one is absent.
265
- function pair(uint low, uint high) internal pure returns (uint cur) {
266
- low = validate(max128(low));
267
- high = validate(max128(high));
268
-
269
- if (low == 0) return high;
270
- if (high == 0) return low;
271
-
272
- uint8 tag = uint8(low >> 120);
273
- if (tag == uint8(high >> 120)) revert DuplicateTag(tag);
274
-
275
- cur = low | (high << 128);
276
- }
243
+ // Selection
277
244
 
278
245
  /// @notice Swap the lower and higher cursors.
279
246
  /// @param cur Packed cursor pair.
@@ -299,41 +266,10 @@ library Cursors {
299
266
  function select(uint cur, uint8 expected) internal pure returns (uint updated) {
300
267
  if (uint8(cur >> 120) == expected) return cur;
301
268
 
302
- updated = swap(cur);
269
+ updated = (cur << 128) | (cur >> 128);
303
270
  if (uint8(updated >> 120) != expected) revert MissingCursor();
304
271
  }
305
272
 
306
- // Marks
307
-
308
- /// @notice Select the live cursor whose frame matches the active cursor in `mark`.
309
- /// @dev Only the lower 128 bits of `mark` are considered. The returned value
310
- /// preserves the cursor pair and places the matching cursor in the lower half.
311
- /// A zero frame may select an empty cursor lane.
312
- /// @param cur Packed cursor or cursor pair to search.
313
- /// @param mark Cursor-shaped positional reference to match.
314
- /// @return located Cursor pair with the matching cursor active.
315
- function locate(uint cur, uint mark) internal pure returns (uint located) {
316
- uint expected = frame(mark);
317
- if (frame(cur) == expected) return cur;
318
-
319
- located = swap(cur);
320
- if (frame(located) != expected) revert MissingCursor();
321
- }
322
-
323
- /// @notice Return whether a matched cursor is positioned before `mark`.
324
- /// @dev Returns false at the mark and reverts after it. Only the active lower
325
- /// cursor in `mark` participates in the comparison. A zero mark represents
326
- /// the already-reached position of an empty cursor.
327
- /// @param cur Packed cursor or cursor pair containing the marked cursor.
328
- /// @param mark Cursor-shaped positional reference.
329
- /// @return Whether the live cursor position precedes the marked position.
330
- function before(uint cur, uint mark) internal pure returns (bool) {
331
- uint i = uint32(locate(cur, mark));
332
- uint target = uint32(mark);
333
- if (i > target) revert OutOfBounds();
334
- return i < target;
335
- }
336
-
337
273
  // Consumption
338
274
 
339
275
  /// @notice Return a cursor's absolute position and advance it.
@@ -343,8 +279,11 @@ library Cursors {
343
279
  /// @return updated Cursor advanced by `amount`.
344
280
  /// @return abs Absolute pre-advance position.
345
281
  function consume(uint cur, uint amount) internal pure returns (uint updated, uint abs) {
346
- abs = Cursors.absolute(cur);
347
- updated = advance(cur, amount);
282
+ uint i = uint32(cur);
283
+ uint len = uint32(cur >> 64);
284
+ if (amount > len - i) revert OutOfBounds();
285
+ abs = uint32(cur >> 32) + i;
286
+ updated = cur + amount;
348
287
  }
349
288
 
350
289
  /// @notice Select a tagged cursor, return its absolute position, and advance it.
@@ -355,6 +294,11 @@ library Cursors {
355
294
  /// @return abs Absolute pre-advance position in the selected lane.
356
295
  function consume(uint cur, uint8 tag, uint amount) internal pure returns (uint updated, uint abs) {
357
296
  updated = select(cur, tag);
358
- (updated, abs) = consume(updated, amount);
297
+
298
+ uint i = uint32(updated);
299
+ uint len = uint32(updated >> 64);
300
+ if (amount > len - i) revert OutOfBounds();
301
+ abs = uint32(updated >> 32) + i;
302
+ updated += amount;
359
303
  }
360
304
  }
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity ^0.8.33;
3
+
4
+ /// @dev Thrown when an operation attempts to spend more value than remains.
5
+ error InsufficientValue();
6
+
7
+ /// @dev Thrown when a decoder or execution is finalized with unread data.
8
+ error UnconsumedData();
9
+
10
+ /// @dev Thrown when an ID does not match the expected convention or type.
11
+ error InvalidId();
12
+
13
+ /// @dev Thrown when an operation exceeds its logical data boundary.
14
+ error OutOfBounds();
15
+
16
+ /// @dev Thrown when a value exceeds the target integer width.
17
+ error ValueOverflow();
18
+
19
+ /// @dev Thrown when a value is not evenly divisible by its divisor.
20
+ error NotDivisible();
21
+
22
+ /// @dev Thrown when an identifier contains a zero address.
23
+ error ZeroAddress();
24
+
25
+ /// @dev Thrown when an address does not contain deployed bytecode.
26
+ error InvalidContract();
27
+
28
+ /// @dev Thrown when an account ID does not match the expected family or type.
29
+ error InvalidAccount();
30
+
31
+ /// @dev Thrown when an asset ID does not match the expected type or chain.
32
+ error InvalidAsset();
33
+
34
+ /// @dev Thrown when an asset is not authorized for an operation.
35
+ error UnauthorizedAsset();
36
+
37
+ /// @dev Thrown when a required nonzero amount is zero.
38
+ error ZeroAmount();
39
+
40
+ /// @dev Thrown when an amount falls outside its allowed range.
41
+ error BadAmount(uint amount);
42
+
43
+ /// @dev Thrown when an opaque ID preimage is missing or unsupported.
44
+ error InvalidPreimage();
45
+
46
+ /// @dev Thrown when a cursor is not positioned at the expected offset.
47
+ error UnexpectedPosition();
48
+
49
+ /// @dev Thrown when no packed cursor matches a requested identity.
50
+ error MissingCursor();
package/utils/Ids.sol CHANGED
@@ -1,6 +1,8 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
+ import {InvalidId, InvalidPreimage} from "./Errors.sol";
5
+
4
6
  /// @title Ids
5
7
  /// @notice Shared helpers for the protocol-wide 256-bit ID convention.
6
8
  ///
@@ -10,11 +12,6 @@ pragma solidity ^0.8.33;
10
12
  /// Opaque keccak preimages start with `0x01`, and the ID is derived as:
11
13
  /// `0x00 || bytes31(keccak256(preimage))`
12
14
  library Ids {
13
- /// @dev Thrown when an ID does not match the expected convention.
14
- error InvalidId();
15
- /// @dev Thrown when an opaque ID preimage is missing or uses an unsupported format/hash tag.
16
- error InvalidPreimage();
17
-
18
15
  /// @dev Preimage format/hash tag for keccak256-derived opaque IDs.
19
16
  uint8 constant Keccak = 0x01;
20
17
 
package/utils/Lanes.sol CHANGED
@@ -9,6 +9,4 @@ library Lanes {
9
9
  uint8 internal constant State = 2;
10
10
  /// @dev Writer lane containing regular endpoint output blocks.
11
11
  uint8 internal constant Output = 3;
12
- /// @dev Writer lane containing deferred transaction blocks.
13
- uint8 internal constant Transactions = 4;
14
12
  }
package/utils/Nodes.sol CHANGED
@@ -2,6 +2,7 @@
2
2
  pragma solidity ^0.8.33;
3
3
 
4
4
  import {Layout} from "./Layout.sol";
5
+ import {InvalidId} from "./Errors.sol";
5
6
  import {Ids} from "./Ids.sol";
6
7
  import {ensureAddr, isFamily, matchesBase, toLocalBase} from "./Utils.sol";
7
8
 
@@ -20,9 +21,6 @@ import {ensureAddr, isFamily, matchesBase, toLocalBase} from "./Utils.sol";
20
21
  ///
21
22
  /// The helpers in this library validate and deconstruct structured node IDs.
22
23
  library Nodes {
23
- /// @dev Thrown when an ID does not match the expected node type or chain.
24
- error InvalidId();
25
-
26
24
  /// @dev 24-bit family tag shared by all node types (Evm + Node category).
27
25
  uint24 constant Family = (uint24(Layout.Evm) << 8) | uint24(Layout.Node);
28
26
  /// @dev Full 4-byte type prefix for chain/domain nodes.
package/utils/Utils.sol CHANGED
@@ -1,18 +1,11 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-only
2
2
  pragma solidity ^0.8.33;
3
3
 
4
+ import {InvalidContract, NotDivisible, ValueOverflow, ZeroAddress} from "./Errors.sol";
5
+
4
6
  // Basis-points denominator: 10_000 BPS == 100.00%.
5
7
  uint16 constant MAX_BPS = 10_000;
6
8
 
7
- /// @dev Thrown by max* helpers when a value exceeds the target integer width.
8
- error ValueOverflow();
9
- /// @dev Thrown by `divisible` when `n` is not evenly divisible by `divisor`.
10
- error NotDivisible();
11
- /// @dev Thrown when an ID claims to carry an address but the embedded address is zero.
12
- error ZeroAddress();
13
- /// @dev Thrown when an address does not contain deployed bytecode.
14
- error InvalidContract();
15
-
16
9
  /// @notice Assert that `value` fits in uint8 and return it as uint8.
17
10
  function max8(uint value) pure returns (uint8) {
18
11
  if (value > type(uint8).max) {
package/codec/Readers.sol DELETED
@@ -1,190 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-only
2
- pragma solidity ^0.8.33;
3
-
4
- import {Sizes, Specs} from "./Specs.sol";
5
- import {Keys} from "./Keys.sol";
6
-
7
- /// @notice Mutable reader over a block stream stored in memory.
8
- /// All positions (`i`) are byte offsets relative to the start of `source`.
9
- struct Reader {
10
- /// @dev Current read position, relative to the source start.
11
- uint i;
12
- /// @dev Memory bytes containing the complete source region.
13
- bytes source;
14
- }
15
-
16
- using Readers for Reader;
17
-
18
- /// @title Readers
19
- /// @notice Memory block stream parser for the rootzero protocol.
20
- /// A `Reader` advances through an existing `bytes memory` source without copying its contents.
21
- /// Blocks are encoded as `[bytes4 key][bytes4 payloadLen][payload]`.
22
- library Readers {
23
- /// @dev The current block has a truncated header or payload, an unexpected key,
24
- /// or a payload size outside the accepted range.
25
- error InvalidBlock();
26
-
27
- /// @notice Create a reader backed by a memory byte array.
28
- /// @param source Memory bytes containing the block stream.
29
- /// @return cur Reader positioned at the beginning of `source`.
30
- function open(bytes memory source) internal pure returns (Reader memory cur) {
31
- cur.source = source;
32
- }
33
-
34
- /// @notice Return whether the reader has consumed its entire source.
35
- /// @param cur Reader whose position should be checked.
36
- /// @return Whether `cur.i` equals the source length.
37
- function done(Reader memory cur) internal pure returns (bool) {
38
- return cur.i == cur.source.length;
39
- }
40
-
41
- /// @notice Return whether the reader has bytes left to consume.
42
- /// @param cur Reader whose position should be checked.
43
- /// @return Whether `cur.i` differs from the source length.
44
- function more(Reader memory cur) internal pure returns (bool) {
45
- return cur.i != cur.source.length;
46
- }
47
-
48
- /// @notice Return whether the current block has `key` and an empty payload.
49
- /// @param cur Reader inspected without advancing.
50
- /// @param key Expected block key.
51
- /// @return Whether a complete matching empty block header occurs at the current position.
52
- function isEmpty(Reader memory cur, bytes4 key) internal pure returns (bool) {
53
- bytes memory source = cur.source;
54
- uint i = cur.i;
55
- if (i > source.length || source.length - i < Sizes.Header) return false;
56
-
57
- uint header;
58
- assembly ("memory-safe") {
59
- header := mload(add(add(source, 0x20), i))
60
- }
61
- return bytes4(uint32(header >> 224)) == key && uint32(header >> 192) == 0;
62
- }
63
-
64
- /// @notice Consume a matching empty block from the reader when present.
65
- /// @param cur Reader advanced only when the matching block is empty.
66
- /// @param key Expected block key.
67
- /// @return Whether an empty block was consumed.
68
- function tryConsumeEmpty(Reader memory cur, bytes4 key) internal pure returns (bool) {
69
- bytes memory source = cur.source;
70
- uint i = cur.i;
71
- if (i > source.length || source.length - i < Sizes.Header) revert InvalidBlock();
72
-
73
- bytes4 current;
74
- uint len;
75
- assembly ("memory-safe") {
76
- let header := mload(add(add(source, 0x20), i))
77
- current := header
78
- len := and(shr(192, header), 0xffffffff)
79
- }
80
-
81
- if (len > source.length - i - Sizes.Header) revert InvalidBlock();
82
- if (current != key || len != 0) return false;
83
- cur.i += Sizes.Header;
84
- return true;
85
- }
86
-
87
- /// @notice Validate and consume the current block, advancing `cur.i` past it.
88
- /// @param cur Reader to advance.
89
- /// @param key Expected block key.
90
- /// @param min Minimum payload length.
91
- /// @param max Maximum payload length; zero means unbounded.
92
- /// @return abs Absolute memory address of the payload start.
93
- function consume(
94
- Reader memory cur,
95
- bytes4 key,
96
- uint min,
97
- uint max
98
- ) private pure returns (uint abs) {
99
- bytes memory source = cur.source;
100
- uint i = cur.i;
101
-
102
- if (i > source.length || source.length - i < Sizes.Header) revert InvalidBlock();
103
-
104
- bytes4 current;
105
- uint len;
106
- assembly ("memory-safe") {
107
- let header := mload(add(add(source, 0x20), i))
108
- current := header
109
- len := and(shr(192, header), 0xffffffff)
110
- abs := add(add(source, 0x28), i)
111
- }
112
-
113
- if (current != key || len < min || (max != 0 && len > max)) revert InvalidBlock();
114
- if (len > source.length - i - Sizes.Header) revert InvalidBlock();
115
- cur.i = i + Sizes.Header + len;
116
- }
117
-
118
- /// @notice Validate and consume the current block described by `spec`.
119
- function consume(Reader memory cur, uint spec) internal pure returns (uint abs) {
120
- (bytes4 key, uint32 min, uint32 max) = Specs.decode(spec);
121
- return consume(cur, key, min, max);
122
- }
123
-
124
- /// @notice Consume a BALANCE block and return its fields.
125
- /// @param cur Reader; advanced past the block.
126
- /// @return asset Asset identifier.
127
- /// @return amount Token amount.
128
- function unpackBalance(Reader memory cur) internal pure returns (bytes32 asset, uint amount) {
129
- uint abs = consume(cur, Keys.Balance, 64, 64);
130
- assembly ("memory-safe") {
131
- asset := mload(abs)
132
- amount := mload(add(abs, 0x20))
133
- }
134
- }
135
-
136
- /// @notice Consume a DEBT block and return its fields.
137
- /// @param cur Reader; advanced past the block.
138
- /// @return liability Liability identifier.
139
- /// @return debt Debt quantity.
140
- function unpackDebt(Reader memory cur) internal pure returns (bytes32 liability, uint debt) {
141
- uint abs = consume(cur, Keys.Debt, 64, 64);
142
- assembly ("memory-safe") {
143
- liability := mload(abs)
144
- debt := mload(add(abs, 0x20))
145
- }
146
- }
147
-
148
- /// @notice Consume a HOST_ASSET block and return its fields.
149
- /// @param cur Reader; advanced past the block.
150
- /// @return host Host identifier.
151
- /// @return asset Asset identifier.
152
- function unpackHostAsset(Reader memory cur) internal pure returns (uint host, bytes32 asset) {
153
- uint abs = consume(cur, Keys.HostAsset, 64, 64);
154
- assembly ("memory-safe") {
155
- host := mload(abs)
156
- asset := mload(add(abs, 0x20))
157
- }
158
- }
159
-
160
- /// @notice Consume a POSITION block and return its fields.
161
- function unpackPosition(
162
- Reader memory cur
163
- ) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
164
- uint abs = consume(cur, Keys.Position, 128, 128);
165
- assembly ("memory-safe") {
166
- asset := mload(abs)
167
- amount := mload(add(abs, 0x20))
168
- liability := mload(add(abs, 0x40))
169
- debt := mload(add(abs, 0x60))
170
- }
171
- }
172
-
173
- /// @notice Consume a TRANSACTION block and return its fields.
174
- /// @param cur Reader; advanced past the block.
175
- /// @return from Source account identifier.
176
- /// @return to Destination account identifier.
177
- /// @return asset Asset identifier.
178
- /// @return amount Token amount.
179
- function unpackTransaction(
180
- Reader memory cur
181
- ) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
182
- uint abs = consume(cur, Keys.Transaction, 128, 128);
183
- assembly ("memory-safe") {
184
- from := mload(abs)
185
- to := mload(add(abs, 0x20))
186
- asset := mload(add(abs, 0x40))
187
- amount := mload(add(abs, 0x60))
188
- }
189
- }
190
- }