@rootzero/contracts 1.13.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -3
- package/Codec.sol +21 -0
- package/Commands.sol +14 -0
- package/Core.sol +2 -3
- package/Endpoints.sol +1 -5
- package/README.md +34 -30
- package/Utils.sol +2 -4
- package/codec/Blocks.sol +1606 -0
- package/codec/Buffers.sol +165 -0
- package/codec/Decoders.sol +558 -0
- package/codec/Descriptors.sol +124 -0
- package/{blocks → codec}/Keys.sol +4 -16
- package/codec/Readers.sol +114 -0
- package/{blocks → codec}/Schema.sol +38 -80
- package/codec/Specs.sol +218 -0
- package/codec/Writers.sol +487 -0
- package/commands/Allocate.sol +21 -20
- package/commands/Base.sol +71 -37
- package/commands/Burn.sol +18 -13
- package/commands/Credit.sol +21 -20
- package/commands/Debit.sol +25 -28
- package/commands/Deposit.sol +34 -35
- package/commands/Payout.sol +21 -15
- package/commands/Provision.sol +37 -38
- package/commands/Recover.sol +20 -19
- package/commands/Relay.sol +24 -22
- package/commands/Withdraw.sol +15 -18
- package/commands/admin/AllowAssets.sol +19 -16
- package/commands/admin/Allowance.sol +18 -13
- package/commands/admin/Appoint.sol +17 -15
- package/commands/admin/Authorize.sol +23 -14
- package/commands/admin/Base.sol +1 -1
- package/commands/admin/DenyAssets.sol +19 -16
- package/commands/admin/Dismiss.sol +17 -15
- package/commands/admin/Execute.sol +20 -19
- package/commands/admin/Label.sol +17 -13
- package/commands/admin/Schemas.sol +18 -14
- package/commands/admin/Unauthorize.sol +23 -14
- package/core/Calls.sol +3 -11
- package/core/Endpoint.sol +42 -127
- package/core/Pipeline.sol +16 -15
- package/core/Types.sol +1 -1
- package/docs/Schema.md +35 -29
- package/events/Endpoint.sol +2 -2
- package/events/Schema.sol +5 -5
- package/execution/Budget.sol +40 -0
- package/execution/Execution.sol +1083 -0
- package/guards/Base.sol +8 -9
- package/guards/Revoke.sol +11 -9
- package/package.json +1 -1
- package/ports/AllowAssets.sol +12 -15
- package/ports/Allowance.sol +11 -9
- package/ports/Base.sol +18 -11
- package/ports/Credit.sol +11 -9
- package/ports/Debit.sol +11 -9
- package/ports/DenyAssets.sol +10 -13
- package/ports/Dispatch.sol +13 -15
- package/ports/Pipe.sol +14 -12
- package/ports/Redeem.sol +12 -9
- package/ports/Settle.sol +11 -9
- package/queries/Assets.sol +15 -15
- package/queries/Balances.sol +17 -17
- package/queries/Base.sol +11 -12
- package/utils/Actions.sol +1 -0
- package/utils/Cursors.sol +308 -0
- package/utils/Lanes.sol +14 -0
- package/utils/Selectors.sol +2 -2
- package/utils/Utils.sol +46 -0
- package/Cursors.sol +0 -16
- package/blocks/Cursors.sol +0 -1529
- package/blocks/Writers.sol +0 -1036
- package/core/Payable.sol +0 -53
- package/utils/Value.sol +0 -43
package/queries/Balances.sol
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {Specs} from "../Codec.sol";
|
|
5
|
+
import {Execution, Executions, Lanes} from "../execution/Execution.sol";
|
|
5
6
|
import {QueryBase} from "./Base.sol";
|
|
6
7
|
|
|
7
|
-
using
|
|
8
|
-
using Writers for Writer;
|
|
8
|
+
using Executions for Execution;
|
|
9
9
|
|
|
10
|
+
/// @notice Hook implemented by hosts that expose account balance queries.
|
|
10
11
|
abstract contract GetBalancesHook {
|
|
11
12
|
/// @notice Resolve one account's balance for one supported asset.
|
|
12
13
|
/// Concrete implementations define how assets are resolved.
|
|
@@ -18,28 +19,27 @@ abstract contract GetBalancesHook {
|
|
|
18
19
|
|
|
19
20
|
/// @title GetBalances
|
|
20
21
|
/// @notice Rootzero query that resolves balances for one or more `(account, asset)` tuples.
|
|
21
|
-
/// The
|
|
22
|
-
/// The response returns one `ACCOUNT_AMOUNT` form block per requested position, preserving
|
|
22
|
+
/// The input is a run of `ACCOUNT_ASSET` form blocks.
|
|
23
|
+
/// The response returns one `ACCOUNT_AMOUNT` form block per requested position, preserving input order.
|
|
23
24
|
abstract contract GetBalances is QueryBase, GetBalancesHook {
|
|
24
|
-
|
|
25
|
+
uint private immutable descriptor;
|
|
25
26
|
|
|
26
27
|
constructor() {
|
|
27
|
-
(, descriptor) = query("getBalances",
|
|
28
|
+
(, descriptor) = query("getBalances", Specs.AccountAsset, Specs.AccountAmount);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/// @notice Resolve balances for a run of requested `(account, asset)` tuples.
|
|
31
|
-
/// @param
|
|
32
|
-
/// @return Block-stream response containing one `accountAmount(account, asset, amount)` block per
|
|
33
|
-
function getBalances(bytes calldata
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
(bytes32 account, bytes32 asset) = input.unpackAccountAsset();
|
|
32
|
+
/// @param input Block-stream input consisting of `accountAsset(account, asset)*`.
|
|
33
|
+
/// @return Block-stream response containing one `accountAmount(account, asset, amount)` block per input block.
|
|
34
|
+
function getBalances(bytes calldata input) external view returns (bytes memory) {
|
|
35
|
+
Execution memory exec = openInput(input, descriptor, 0);
|
|
36
|
+
|
|
37
|
+
while (exec.more()) {
|
|
38
|
+
(bytes32 account, bytes32 asset) = exec.unpackAccountAsset(Lanes.Input);
|
|
39
39
|
uint amount = getBalance(account, asset);
|
|
40
|
-
|
|
40
|
+
exec.outputAccountAmount(account, asset, amount);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
return
|
|
43
|
+
return close(exec);
|
|
44
44
|
}
|
|
45
45
|
}
|
package/queries/Base.sol
CHANGED
|
@@ -2,30 +2,29 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import { EndpointBase } from "../core/Endpoint.sol";
|
|
5
|
+
import { Specs } from "../codec/Specs.sol";
|
|
5
6
|
import { Nodes } from "../utils/Nodes.sol";
|
|
6
7
|
import { Selectors } from "../utils/Selectors.sol";
|
|
7
8
|
|
|
8
9
|
/// @title QueryBase
|
|
9
10
|
/// @notice Abstract base for rootzero query contracts.
|
|
10
|
-
/// Queries are view-only entry points that consume a block-stream
|
|
11
|
+
/// Queries are view-only entry points that consume a block-stream input and
|
|
11
12
|
/// return a block-stream response.
|
|
12
13
|
abstract contract QueryBase is EndpointBase {
|
|
13
14
|
|
|
14
15
|
/// @notice Publish query metadata and a default label.
|
|
15
|
-
/// @param name
|
|
16
|
-
///
|
|
17
|
-
/// @param
|
|
18
|
-
/// @param
|
|
16
|
+
/// @param name Query entrypoint name and default label. It must exactly
|
|
17
|
+
/// match the Solidity query function name used by the canonical ABI.
|
|
18
|
+
/// @param input Input block specification.
|
|
19
|
+
/// @param output Output block specification.
|
|
19
20
|
/// @return id Query node ID.
|
|
20
21
|
/// @return descriptor Packed endpoint lane metadata and flags.
|
|
21
22
|
function query(
|
|
22
23
|
string memory name,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
id = Nodes.toQuery(selector, address(this));
|
|
29
|
-
descriptor = endpoint(id, name, bytes9(0), input, output, false, false);
|
|
24
|
+
uint input,
|
|
25
|
+
uint output
|
|
26
|
+
) internal returns (uint id, uint descriptor) {
|
|
27
|
+
id = Nodes.toQuery(Selectors.query(name), address(this));
|
|
28
|
+
descriptor = endpoint(id, name, Specs.Empty, input, output, 0, 0);
|
|
30
29
|
}
|
|
31
30
|
}
|
package/utils/Actions.sol
CHANGED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {clear32, max16, max32, max128} from "./Utils.sol";
|
|
5
|
+
|
|
6
|
+
/// @notice Mutable memory wrapper around a packed cursor.
|
|
7
|
+
/// @dev A second tagged cursor may occupy the upper 128-bit lane of `state`.
|
|
8
|
+
/// Cursor operations target the lower lane; `Cursors.select` swaps the requested
|
|
9
|
+
/// tagged cursor into that position.
|
|
10
|
+
struct Cur {
|
|
11
|
+
uint state;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/// @title Cursors
|
|
15
|
+
/// @notice Packed cursor state and navigation for grouped byte regions.
|
|
16
|
+
/// @dev Each 128-bit cursor uses the following layout:
|
|
17
|
+
/// bits 0-31 i
|
|
18
|
+
/// bits 32-63 offset
|
|
19
|
+
/// bits 64-95 len
|
|
20
|
+
/// bits 96-111 groups
|
|
21
|
+
/// bits 112-119 flags (consumer-defined)
|
|
22
|
+
/// bits 120-127 tag
|
|
23
|
+
/// A packed word may contain a lower cursor in bits 0-127 and a higher cursor
|
|
24
|
+
/// in bits 128-255. Operations target the lower cursor; `select` swaps a
|
|
25
|
+
/// requested tagged cursor into that position.
|
|
26
|
+
/// The zero word represents an absent cursor.
|
|
27
|
+
library Cursors {
|
|
28
|
+
/// @dev A cursor position exceeds its logical length.
|
|
29
|
+
error OutOfBounds();
|
|
30
|
+
|
|
31
|
+
/// @dev Two optional group counts are both set but do not match.
|
|
32
|
+
error BadRatio();
|
|
33
|
+
|
|
34
|
+
/// @dev A cursor is not positioned at the expected offset.
|
|
35
|
+
error UnexpectedPosition();
|
|
36
|
+
|
|
37
|
+
/// @dev Paired cursors must have different identity tags.
|
|
38
|
+
error DuplicateTag(uint8 tag);
|
|
39
|
+
|
|
40
|
+
/// @dev Neither packed cursor has the requested tag.
|
|
41
|
+
error MissingTag(uint8 tag);
|
|
42
|
+
|
|
43
|
+
// Creation and sources
|
|
44
|
+
|
|
45
|
+
/// @notice Create a cursor positioned at its beginning.
|
|
46
|
+
/// @param offset Absolute source or buffer offset.
|
|
47
|
+
/// @param len Logical byte length.
|
|
48
|
+
/// @param groups Logical group count.
|
|
49
|
+
/// @param flags Consumer-defined flags.
|
|
50
|
+
/// @param tag Cursor identity tag.
|
|
51
|
+
/// @return cur Packed cursor.
|
|
52
|
+
function create(uint offset, uint len, uint groups, uint8 flags, uint8 tag) internal pure returns (uint cur) {
|
|
53
|
+
cur |= max32(offset) << 32;
|
|
54
|
+
cur |= max32(len) << 64;
|
|
55
|
+
cur |= max16(groups) << 96;
|
|
56
|
+
cur |= uint(flags) << 112;
|
|
57
|
+
cur |= uint(tag) << 120;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// @notice Return the absolute calldata position where `source` begins.
|
|
61
|
+
/// @param source Calldata slice whose base is requested.
|
|
62
|
+
/// @return abs Absolute calldata position.
|
|
63
|
+
function base(bytes calldata source) internal pure returns (uint abs) {
|
|
64
|
+
assembly ("memory-safe") {
|
|
65
|
+
abs := source.offset
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// @notice Return the absolute calldata start and exclusive end of `source`.
|
|
70
|
+
/// @param source Calldata slice whose bounds are requested.
|
|
71
|
+
/// @return abs Absolute start position.
|
|
72
|
+
/// @return end Absolute exclusive end position.
|
|
73
|
+
function bounds(bytes calldata source) internal pure returns (uint abs, uint end) {
|
|
74
|
+
abs = base(source);
|
|
75
|
+
end = abs + source.length;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// @notice Create a cursor backed by a calldata slice.
|
|
79
|
+
/// @param source Calldata slice represented by the cursor.
|
|
80
|
+
/// @param flags Consumer-defined flags.
|
|
81
|
+
/// @param tag Cursor identity tag.
|
|
82
|
+
/// @return cur Packed cursor positioned at the slice beginning.
|
|
83
|
+
function wrap(bytes calldata source, uint8 flags, uint8 tag) internal pure returns (uint cur) {
|
|
84
|
+
cur = create(base(source), source.length, 0, flags, tag);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Inspection
|
|
88
|
+
|
|
89
|
+
/// @notice Decode the positional fields from the lower cursor.
|
|
90
|
+
/// @param cur Packed cursor or cursor pair.
|
|
91
|
+
/// @return i Current relative position.
|
|
92
|
+
/// @return offset Absolute base offset.
|
|
93
|
+
/// @return len Logical byte length.
|
|
94
|
+
function decode(uint cur) internal pure returns (uint i, uint offset, uint len) {
|
|
95
|
+
i = uint32(cur);
|
|
96
|
+
offset = uint32(cur >> 32);
|
|
97
|
+
len = uint32(cur >> 64);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// @notice Return the absolute position of the lower cursor as `offset + i`.
|
|
101
|
+
/// @dev Performs no bounds check.
|
|
102
|
+
/// @param cur Packed cursor or cursor pair.
|
|
103
|
+
/// @return Absolute current position.
|
|
104
|
+
function absolute(uint cur) internal pure returns (uint) {
|
|
105
|
+
return uint32(cur) + uint32(cur >> 32);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// @notice Decode the consumer metadata and identity tag from the lower cursor.
|
|
109
|
+
/// @param cur Packed cursor or cursor pair.
|
|
110
|
+
/// @return groups Logical group count.
|
|
111
|
+
/// @return flags Consumer-defined flags.
|
|
112
|
+
/// @return tag Cursor identity tag.
|
|
113
|
+
function meta(uint cur) internal pure returns (uint groups, uint8 flags, uint8 tag) {
|
|
114
|
+
groups = uint16(cur >> 96);
|
|
115
|
+
flags = uint8(cur >> 112);
|
|
116
|
+
tag = uint8(cur >> 120);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/// @notice Return whether both packed cursors remain at their initial positions.
|
|
120
|
+
/// @param cur Packed cursor or cursor pair.
|
|
121
|
+
/// @return Whether both lane positions are zero.
|
|
122
|
+
function initial(uint cur) internal pure returns (bool) {
|
|
123
|
+
return uint32(cur) == 0 && uint32(cur >> 128) == 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// @notice Return whether the lower cursor's current position precedes its length.
|
|
127
|
+
/// @param cur Packed cursor or cursor pair.
|
|
128
|
+
/// @return Whether the lower cursor has bytes remaining.
|
|
129
|
+
function more(uint cur) internal pure returns (bool) {
|
|
130
|
+
return uint32(cur) < uint32(cur >> 64);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/// @notice Return whether either packed cursor has remaining bytes.
|
|
134
|
+
/// @param cur Packed cursor or cursor pair.
|
|
135
|
+
/// @return Whether either lane has bytes remaining.
|
|
136
|
+
function any(uint cur) internal pure returns (bool) {
|
|
137
|
+
return more(cur) || more(cur >> 128);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/// @notice Require the lower cursor to be positioned at `i`.
|
|
141
|
+
/// @param cur Packed cursor or cursor pair.
|
|
142
|
+
/// @param i Expected relative position.
|
|
143
|
+
function expect(uint cur, uint i) internal pure {
|
|
144
|
+
if (uint32(cur) != i) revert UnexpectedPosition();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// @notice Return whether the lower cursor contains `flag`.
|
|
148
|
+
/// @param cur Packed cursor or cursor pair.
|
|
149
|
+
/// @param flag Consumer-defined flag bit or bit set.
|
|
150
|
+
/// @return Whether any requested flag bit is present.
|
|
151
|
+
function flagged(uint cur, uint8 flag) internal pure returns (bool) {
|
|
152
|
+
return uint8(cur >> 112) & flag != 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Navigation
|
|
156
|
+
|
|
157
|
+
/// @dev Return `cur` after ensuring its lower position does not exceed its length.
|
|
158
|
+
/// @param cur Packed cursor or cursor pair.
|
|
159
|
+
/// @return Validated cursor unchanged.
|
|
160
|
+
function validate(uint cur) private pure returns (uint) {
|
|
161
|
+
if (uint32(cur) > uint32(cur >> 64)) revert OutOfBounds();
|
|
162
|
+
return cur;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// @notice Move the lower cursor forward to `i`.
|
|
166
|
+
/// @param cur Packed cursor or cursor pair.
|
|
167
|
+
/// @param i New relative position; must not move backward.
|
|
168
|
+
/// @return updated Cursor with the new lower position.
|
|
169
|
+
function seek(uint cur, uint i) internal pure returns (uint updated) {
|
|
170
|
+
uint current = uint32(cur);
|
|
171
|
+
uint len = uint32(cur >> 64);
|
|
172
|
+
if (i < current || i > len) revert OutOfBounds();
|
|
173
|
+
updated = clear32(cur, 0) | i;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/// @notice Replace the lower cursor's position using an absolute position.
|
|
177
|
+
/// @param cur Packed cursor or cursor pair.
|
|
178
|
+
/// @param abs New absolute position.
|
|
179
|
+
/// @return updated Cursor with the corresponding relative position.
|
|
180
|
+
function seekAbs(uint cur, uint abs) internal pure returns (uint updated) {
|
|
181
|
+
uint offset = uint32(cur >> 32);
|
|
182
|
+
if (abs < offset) revert OutOfBounds();
|
|
183
|
+
updated = seek(cur, abs - offset);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/// @notice Advance the current position of the lower cursor.
|
|
187
|
+
/// @param cur Packed cursor or cursor pair.
|
|
188
|
+
/// @param amount Number of bytes to advance.
|
|
189
|
+
/// @return updated Cursor advanced by `amount`.
|
|
190
|
+
function advance(uint cur, uint amount) internal pure returns (uint updated) {
|
|
191
|
+
uint i = uint32(validate(cur));
|
|
192
|
+
uint len = uint32(cur >> 64);
|
|
193
|
+
if (amount > len - i) revert OutOfBounds();
|
|
194
|
+
updated = cur + amount;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/// @notice Replace the logical length of the lower cursor.
|
|
198
|
+
/// @dev A cursor cannot be resized below its current position.
|
|
199
|
+
/// @param cur Packed cursor or cursor pair.
|
|
200
|
+
/// @param len New logical length.
|
|
201
|
+
/// @return updated Cursor with the replaced length.
|
|
202
|
+
function resize(uint cur, uint len) internal pure returns (uint updated) {
|
|
203
|
+
if (uint32(cur) > max32(len)) revert OutOfBounds();
|
|
204
|
+
updated = clear32(cur, 64) | (len << 64);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/// @notice Create a child cursor over `[start, end)` within the lower cursor.
|
|
208
|
+
/// @dev The child starts at position zero, has no groups, and uses the
|
|
209
|
+
/// supplied tag. Any higher cursor is omitted.
|
|
210
|
+
/// @param cur Parent cursor or cursor pair.
|
|
211
|
+
/// @param start Child start relative to the parent base.
|
|
212
|
+
/// @param end Child exclusive end relative to the parent base.
|
|
213
|
+
/// @param tag Child identity tag.
|
|
214
|
+
/// @return child Packed child cursor.
|
|
215
|
+
function slice(uint cur, uint start, uint end, uint8 tag) internal pure returns (uint child) {
|
|
216
|
+
(, uint offset, uint len) = decode(validate(cur));
|
|
217
|
+
if (start > end || end > len) revert OutOfBounds();
|
|
218
|
+
child = create(offset + start, end - start, 0, 0, tag);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Pairing and selection
|
|
222
|
+
|
|
223
|
+
/// @notice Reconcile both packed cursor lanes with an expected group count.
|
|
224
|
+
/// @dev Zero lanes and lanes with zero groups do not constrain the result.
|
|
225
|
+
/// @param cur Packed cursor or cursor pair.
|
|
226
|
+
/// @param expected Expected group count; zero accepts the encoded count.
|
|
227
|
+
/// @return groups Reconciled effective group count.
|
|
228
|
+
function reconcile(uint cur, uint expected) internal pure returns (uint groups) {
|
|
229
|
+
uint low = uint16(cur >> 96);
|
|
230
|
+
uint high = uint16(cur >> 224);
|
|
231
|
+
if (low != 0 && high != 0 && low != high) revert BadRatio();
|
|
232
|
+
|
|
233
|
+
groups = low != 0 ? low : high;
|
|
234
|
+
if (groups != 0 && expected != 0 && groups != expected) revert BadRatio();
|
|
235
|
+
if (groups == 0) groups = expected;
|
|
236
|
+
max16(groups);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/// @notice Combine two cursors into one packed word.
|
|
240
|
+
/// @dev Zero represents absence and acts as the identity value.
|
|
241
|
+
/// @param low Cursor placed in the lower lane.
|
|
242
|
+
/// @param high Cursor placed in the higher lane.
|
|
243
|
+
/// @return cur Packed cursor pair, or the nonzero cursor when one is absent.
|
|
244
|
+
function pair(uint low, uint high) internal pure returns (uint cur) {
|
|
245
|
+
low = validate(max128(low));
|
|
246
|
+
high = validate(max128(high));
|
|
247
|
+
|
|
248
|
+
if (low == 0) return high;
|
|
249
|
+
if (high == 0) return low;
|
|
250
|
+
|
|
251
|
+
uint8 tag = uint8(low >> 120);
|
|
252
|
+
if (tag == uint8(high >> 120)) revert DuplicateTag(tag);
|
|
253
|
+
|
|
254
|
+
cur = low | (high << 128);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/// @notice Swap the lower and higher cursors.
|
|
258
|
+
/// @param cur Packed cursor pair.
|
|
259
|
+
/// @return updated Pair with its lanes exchanged.
|
|
260
|
+
function swap(uint cur) internal pure returns (uint updated) {
|
|
261
|
+
updated = (cur << 128) | (cur >> 128);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/// @notice Return whether either packed cursor has the nonzero `expected` tag.
|
|
265
|
+
/// @dev Tag zero denotes an untagged cursor and is never matched by this helper.
|
|
266
|
+
/// @param cur Packed cursor or cursor pair.
|
|
267
|
+
/// @param expected Nonzero identity tag to find.
|
|
268
|
+
/// @return Whether either lane has the requested tag.
|
|
269
|
+
function contains(uint cur, uint8 expected) internal pure returns (bool) {
|
|
270
|
+
return expected != 0 && (uint8(cur >> 120) == expected || uint8(cur >> 248) == expected);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/// @notice Move the cursor with `expected` into the lower position.
|
|
274
|
+
/// @dev If both cursors share the tag, the existing lower cursor is retained.
|
|
275
|
+
/// @param cur Packed cursor or cursor pair.
|
|
276
|
+
/// @param expected Identity tag to select.
|
|
277
|
+
/// @return updated Cursor word with the selected lane in the lower position.
|
|
278
|
+
function select(uint cur, uint8 expected) internal pure returns (uint updated) {
|
|
279
|
+
if (uint8(cur >> 120) == expected) return cur;
|
|
280
|
+
|
|
281
|
+
updated = swap(cur);
|
|
282
|
+
if (uint8(updated >> 120) != expected) revert MissingTag(expected);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Consumption
|
|
286
|
+
|
|
287
|
+
/// @notice Return a cursor's absolute position and advance it.
|
|
288
|
+
/// @dev Intended for fixed-width consumers that know their complete encoded size.
|
|
289
|
+
/// @param cur Packed cursor or cursor pair.
|
|
290
|
+
/// @param amount Number of bytes to consume.
|
|
291
|
+
/// @return updated Cursor advanced by `amount`.
|
|
292
|
+
/// @return abs Absolute pre-advance position.
|
|
293
|
+
function consume(uint cur, uint amount) internal pure returns (uint updated, uint abs) {
|
|
294
|
+
abs = Cursors.absolute(cur);
|
|
295
|
+
updated = advance(cur, amount);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// @notice Select a tagged cursor, return its absolute position, and advance it.
|
|
299
|
+
/// @param cur Packed cursor or cursor pair.
|
|
300
|
+
/// @param tag Identity tag to select.
|
|
301
|
+
/// @param amount Number of bytes to consume.
|
|
302
|
+
/// @return updated Cursor pair with the selected lane advanced.
|
|
303
|
+
/// @return abs Absolute pre-advance position in the selected lane.
|
|
304
|
+
function consume(uint cur, uint8 tag, uint amount) internal pure returns (uint updated, uint abs) {
|
|
305
|
+
updated = select(cur, tag);
|
|
306
|
+
(updated, abs) = consume(updated, amount);
|
|
307
|
+
}
|
|
308
|
+
}
|
package/utils/Lanes.sol
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
/// @notice Conventional identifiers shared by endpoint execution lanes.
|
|
5
|
+
library Lanes {
|
|
6
|
+
/// @dev Decoder lane containing endpoint input blocks.
|
|
7
|
+
uint8 internal constant Input = 1;
|
|
8
|
+
/// @dev Decoder lane containing command state blocks.
|
|
9
|
+
uint8 internal constant State = 2;
|
|
10
|
+
/// @dev Writer lane containing regular endpoint output blocks.
|
|
11
|
+
uint8 internal constant Output = 3;
|
|
12
|
+
/// @dev Writer lane containing deferred transaction blocks.
|
|
13
|
+
uint8 internal constant Transactions = 4;
|
|
14
|
+
}
|
package/utils/Selectors.sol
CHANGED
|
@@ -6,9 +6,9 @@ pragma solidity ^0.8.33;
|
|
|
6
6
|
library Selectors {
|
|
7
7
|
/// @notice Derive the ABI selector for a command entrypoint.
|
|
8
8
|
/// @param name Command function name.
|
|
9
|
-
/// @return Selector for `name(
|
|
9
|
+
/// @return Selector for `name(bytes32,bytes,bytes)`.
|
|
10
10
|
function command(string memory name) internal pure returns (bytes4) {
|
|
11
|
-
return derive(name, "(
|
|
11
|
+
return derive(name, "(bytes32,bytes,bytes)");
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/// @notice Derive the ABI selector for a port entrypoint.
|
package/utils/Utils.sol
CHANGED
|
@@ -83,6 +83,52 @@ function max160(uint value) pure returns (uint) {
|
|
|
83
83
|
return value;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// Packed fields
|
|
87
|
+
|
|
88
|
+
/// @notice Clear the 8-bit field beginning at `shift`.
|
|
89
|
+
function clear8(uint value, uint shift) pure returns (uint) {
|
|
90
|
+
return value & ~(uint(type(uint8).max) << shift);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// @notice Clear the 16-bit field beginning at `shift`.
|
|
94
|
+
function clear16(uint value, uint shift) pure returns (uint) {
|
|
95
|
+
return value & ~(uint(type(uint16).max) << shift);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// @notice Clear the 32-bit field beginning at `shift`.
|
|
99
|
+
function clear32(uint value, uint shift) pure returns (uint) {
|
|
100
|
+
return value & ~(uint(type(uint32).max) << shift);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// @notice Clear the 64-bit field beginning at `shift`.
|
|
104
|
+
function clear64(uint value, uint shift) pure returns (uint) {
|
|
105
|
+
return value & ~(uint(type(uint64).max) << shift);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// @notice Replace the 8-bit field beginning at `shift` with `field`.
|
|
109
|
+
/// @dev Reverts when `field` does not fit in 8 bits.
|
|
110
|
+
function replace8(uint value, uint shift, uint field) pure returns (uint) {
|
|
111
|
+
return clear8(value, shift) | (max8(field) << shift);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// @notice Replace the 16-bit field beginning at `shift` with `field`.
|
|
115
|
+
/// @dev Reverts when `field` does not fit in 16 bits.
|
|
116
|
+
function replace16(uint value, uint shift, uint field) pure returns (uint) {
|
|
117
|
+
return clear16(value, shift) | (max16(field) << shift);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// @notice Replace the 32-bit field beginning at `shift` with `field`.
|
|
121
|
+
/// @dev Reverts when `field` does not fit in 32 bits.
|
|
122
|
+
function replace32(uint value, uint shift, uint field) pure returns (uint) {
|
|
123
|
+
return clear32(value, shift) | (max32(field) << shift);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// @notice Replace the 64-bit field beginning at `shift` with `field`.
|
|
127
|
+
/// @dev Reverts when `field` does not fit in 64 bits.
|
|
128
|
+
function replace64(uint value, uint shift, uint field) pure returns (uint) {
|
|
129
|
+
return clear64(value, shift) | (max64(field) << shift);
|
|
130
|
+
}
|
|
131
|
+
|
|
86
132
|
/// @notice Assert that `n` is evenly divisible by `divisor`.
|
|
87
133
|
/// No-op when `divisor` is zero.
|
|
88
134
|
function divisible(uint n, uint divisor) pure {
|
package/Cursors.sol
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
-
pragma solidity ^0.8.33;
|
|
3
|
-
|
|
4
|
-
// Aggregator: re-exports all block stream primitives (Cursors, Readers, Writers, Schema, Keys, Sizes).
|
|
5
|
-
// Import this file to get access to the full block encoding/decoding surface in one import.
|
|
6
|
-
|
|
7
|
-
import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
|
|
8
|
-
import { Forms, Sizes } from "./blocks/Schema.sol";
|
|
9
|
-
import { Keys } from "./blocks/Keys.sol";
|
|
10
|
-
import { Schemas } from "./blocks/Schema.sol";
|
|
11
|
-
import { Cursors, Cur, Readers, Reader } from "./blocks/Cursors.sol";
|
|
12
|
-
import { Writer, Writers, Hints } from "./blocks/Writers.sol";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|