@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.
- package/CHANGELOG.md +101 -0
- package/Codec.sol +1 -2
- package/Endpoints.sol +2 -0
- package/README.md +61 -51
- package/Utils.sol +2 -1
- package/codec/Blocks.sol +276 -88
- package/codec/Buffers.sol +24 -20
- package/codec/Decoders.sol +35 -37
- package/codec/Descriptors.sol +75 -72
- package/codec/Keys.sol +5 -1
- package/codec/Schema.sol +5 -1
- package/codec/Specs.sol +19 -9
- package/codec/Writers.sol +14 -19
- package/commands/Allocate.sol +8 -7
- package/commands/Base.sol +14 -49
- package/commands/Bootstrap.sol +95 -0
- package/commands/Burn.sol +7 -7
- package/commands/Cashout.sol +85 -0
- package/commands/Credit.sol +18 -16
- package/commands/Debit.sol +23 -19
- package/commands/Deposit.sol +13 -13
- package/commands/Payout.sol +8 -8
- package/commands/Provision.sol +13 -13
- package/commands/Recover.sol +7 -7
- package/commands/Relay.sol +22 -23
- package/commands/Repay.sol +36 -34
- package/commands/Settle.sol +24 -22
- package/commands/Withdraw.sol +7 -7
- package/commands/admin/AllowAssets.sol +7 -7
- package/commands/admin/Allowance.sol +7 -7
- package/commands/admin/Annotate.sol +7 -7
- package/commands/admin/Appoint.sol +7 -7
- package/commands/admin/Authorize.sol +7 -7
- package/commands/admin/Base.sol +5 -8
- package/commands/admin/DenyAssets.sol +7 -7
- package/commands/admin/Dismiss.sol +7 -7
- package/commands/admin/Execute.sol +8 -8
- package/commands/admin/Unauthorize.sol +7 -7
- package/core/Calls.sol +3 -3
- package/core/Endpoint.sol +7 -7
- package/core/Pipeline.sol +19 -20
- package/execution/Budget.sol +2 -3
- package/execution/Execution.sol +271 -509
- package/guards/Base.sol +1 -1
- package/guards/Revoke.sol +7 -7
- package/package.json +1 -1
- package/ports/Allowance.sol +3 -3
- package/ports/Assets.sol +7 -7
- package/ports/Base.sol +1 -1
- package/ports/Credit.sol +3 -3
- package/ports/Debit.sol +3 -3
- package/ports/Dispatch.sol +3 -3
- package/ports/Pipe.sol +3 -3
- package/ports/Post.sol +3 -3
- package/ports/Redeem.sol +3 -3
- package/queries/Assets.sol +3 -3
- package/queries/Balances.sol +3 -3
- package/queries/Base.sol +1 -1
- package/utils/Accounts.sol +1 -3
- package/utils/Actions.sol +2 -0
- package/utils/Assets.sol +1 -10
- package/utils/Cursors.sol +60 -116
- package/utils/Errors.sol +50 -0
- package/utils/Ids.sol +2 -5
- package/utils/Lanes.sol +0 -2
- package/utils/Nodes.sol +1 -3
- package/utils/Utils.sol +2 -9
- package/codec/Readers.sol +0 -190
package/codec/Buffers.sol
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {ValueOverflow} from "../utils/Errors.sol";
|
|
5
5
|
|
|
6
6
|
/// @title Buffers
|
|
7
7
|
/// @notice Allocation and finalization helpers for mutable memory byte buffers.
|
|
8
|
-
/// @dev
|
|
9
|
-
/// `write` copies from memory, while `copy` copies directly from calldata.
|
|
8
|
+
/// @dev `write` copies from memory, while `copy` copies directly from calldata.
|
|
10
9
|
library Buffers {
|
|
11
|
-
using Cursors for uint;
|
|
12
|
-
|
|
13
|
-
uint8 internal constant Growable = 1;
|
|
14
|
-
|
|
15
10
|
/// @dev A reserved memory write exceeds the physical backing buffer.
|
|
16
11
|
error BufferOverflow();
|
|
17
12
|
/// @dev A buffer cursor does not match its logical or physical capacity.
|
|
@@ -19,12 +14,12 @@ library Buffers {
|
|
|
19
14
|
|
|
20
15
|
/// @notice Create a packed buffer cursor at write position zero.
|
|
21
16
|
/// @param len Initial logical byte capacity.
|
|
22
|
-
/// @param
|
|
23
|
-
/// @param growable Whether writes may expand the logical capacity.
|
|
17
|
+
/// @param stride Optional blocks per group represented by the buffer.
|
|
24
18
|
/// @param tag Cursor identity tag.
|
|
25
19
|
/// @return cur Packed buffer cursor.
|
|
26
|
-
function cursor(uint len,
|
|
27
|
-
|
|
20
|
+
function cursor(uint len, uint8 stride, uint8 tag) internal pure returns (uint cur) {
|
|
21
|
+
if (len > type(uint32).max) revert ValueOverflow();
|
|
22
|
+
cur = (len << 64) | (uint(stride) << 96) | (uint(tag) << 120);
|
|
28
23
|
}
|
|
29
24
|
|
|
30
25
|
/// @notice Reserve relative write space and return the updated packed buffer cursor.
|
|
@@ -43,24 +38,28 @@ library Buffers {
|
|
|
43
38
|
uint advance,
|
|
44
39
|
uint touch
|
|
45
40
|
) internal pure returns (uint updated, bytes memory dst, uint i) {
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
i = uint32(cur);
|
|
42
|
+
uint len = uint32(cur >> 64);
|
|
48
43
|
uint required = i + (advance > touch ? advance : touch);
|
|
49
44
|
bool empty = buffer.length == 0;
|
|
50
45
|
dst = buffer;
|
|
51
46
|
|
|
52
|
-
if (
|
|
47
|
+
if (required > len) {
|
|
53
48
|
len = len == 0 ? 64 : len * 2;
|
|
54
49
|
while (len < required) {
|
|
55
50
|
len *= 2;
|
|
56
51
|
}
|
|
57
|
-
|
|
52
|
+
if (len > type(uint32).max) revert ValueOverflow();
|
|
53
|
+
cur = (cur & ~(uint(type(uint32).max) << 64)) | (len << 64);
|
|
58
54
|
if (!empty) dst = resize(dst, i, len);
|
|
59
55
|
}
|
|
60
56
|
|
|
61
|
-
updated = cur
|
|
57
|
+
updated = cur + advance;
|
|
62
58
|
|
|
63
|
-
if (empty)
|
|
59
|
+
if (empty) {
|
|
60
|
+
uint padded = ((len + 31) & ~uint(31)) + 32;
|
|
61
|
+
dst = new bytes(padded);
|
|
62
|
+
}
|
|
64
63
|
if (required > dst.length) revert BufferOverflow();
|
|
65
64
|
}
|
|
66
65
|
|
|
@@ -81,7 +80,8 @@ library Buffers {
|
|
|
81
80
|
/// @param capacity Requested capacity of the new buffer.
|
|
82
81
|
/// @return resized Newly allocated buffer containing the written prefix.
|
|
83
82
|
function resize(bytes memory buffer, uint written, uint capacity) internal pure returns (bytes memory resized) {
|
|
84
|
-
|
|
83
|
+
uint padded = ((capacity + 31) & ~uint(31)) + 32;
|
|
84
|
+
resized = new bytes(padded);
|
|
85
85
|
assembly ("memory-safe") {
|
|
86
86
|
mcopy(add(resized, 0x20), add(buffer, 0x20), written)
|
|
87
87
|
}
|
|
@@ -171,9 +171,13 @@ library Buffers {
|
|
|
171
171
|
/// @param buffer Backing byte buffer.
|
|
172
172
|
/// @return out Empty bytes when unused, otherwise the written prefix.
|
|
173
173
|
function finish(uint cur, bytes memory buffer) internal pure returns (bytes memory out) {
|
|
174
|
-
|
|
174
|
+
uint i = uint32(cur);
|
|
175
|
+
uint len = uint32(cur >> 64);
|
|
175
176
|
if (i == 0) return new bytes(0);
|
|
176
177
|
if (i > len || i > buffer.length) revert IncompleteBuffer();
|
|
177
|
-
|
|
178
|
+
assembly ("memory-safe") {
|
|
179
|
+
mstore(buffer, i)
|
|
180
|
+
}
|
|
181
|
+
out = buffer;
|
|
178
182
|
}
|
|
179
183
|
}
|
package/codec/Decoders.sol
CHANGED
|
@@ -5,6 +5,7 @@ import {AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAcc
|
|
|
5
5
|
import {Blocks} from "./Blocks.sol";
|
|
6
6
|
import {Sizes, Specs} from "./Specs.sol";
|
|
7
7
|
import {Cursors, Cur} from "../utils/Cursors.sol";
|
|
8
|
+
import {UnconsumedData} from "../utils/Errors.sol";
|
|
8
9
|
|
|
9
10
|
using Decoders for Cur;
|
|
10
11
|
|
|
@@ -17,40 +18,11 @@ library Decoders {
|
|
|
17
18
|
// Cur memory adapters
|
|
18
19
|
// -------------------------------------------------------------------------
|
|
19
20
|
|
|
20
|
-
/// @notice
|
|
21
|
-
/// @param source Calldata region to wrap.
|
|
22
|
-
/// @return cur Cursor spanning the complete source.
|
|
23
|
-
function wrap(bytes calldata source) internal pure returns (Cur memory cur) {
|
|
24
|
-
cur.state = Cursors.wrap(source, 0, 0);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/// @notice Wrap the calldata tail beginning at relative position `i`.
|
|
28
|
-
/// @param source Calldata region containing the tail.
|
|
29
|
-
/// @param i Relative tail position.
|
|
30
|
-
/// @return cur Cursor spanning `source[i:]`.
|
|
31
|
-
function wrap(bytes calldata source, uint i) internal pure returns (Cur memory cur) {
|
|
32
|
-
cur.state = Cursors.wrap(source[i:], 0, 0);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/// @notice Open a non-empty calldata source as an ungrouped cursor.
|
|
21
|
+
/// @notice Open a calldata source without inspecting its contents.
|
|
36
22
|
/// @param source Calldata region to open.
|
|
37
23
|
/// @return cur Cursor spanning the complete source.
|
|
38
24
|
function open(bytes calldata source) internal pure returns (Cur memory cur) {
|
|
39
|
-
|
|
40
|
-
cur.state = Cursors.wrap(source, 0, 0);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/// @notice Open the first homogeneous batch in `source`.
|
|
44
|
-
/// @param source Calldata block stream to open.
|
|
45
|
-
/// @return cur Counted cursor spanning the first homogeneous batch.
|
|
46
|
-
function batch(bytes calldata source) internal pure returns (Cur memory cur) {
|
|
47
|
-
(uint abs, uint limit) = Cursors.bounds(source);
|
|
48
|
-
if (abs == limit) revert Blocks.EmptyRun();
|
|
49
|
-
|
|
50
|
-
bytes4 key = bytes4(source);
|
|
51
|
-
(uint count, uint end) = Blocks.run(abs, limit, key);
|
|
52
|
-
if (count == 0) revert Blocks.EmptyRun();
|
|
53
|
-
cur.state = Cursors.create(abs, end - abs, count, 0, 0);
|
|
25
|
+
cur.state = Cursors.wrap(source, 0);
|
|
54
26
|
}
|
|
55
27
|
|
|
56
28
|
/// @notice Return whether `cur` has unread bytes.
|
|
@@ -60,6 +32,12 @@ library Decoders {
|
|
|
60
32
|
return cur.state.more();
|
|
61
33
|
}
|
|
62
34
|
|
|
35
|
+
/// @notice Require the complete decoder source to have been consumed.
|
|
36
|
+
/// @param cur Decoder cursor to close.
|
|
37
|
+
function close(Cur memory cur) internal pure {
|
|
38
|
+
if (cur.state.more()) revert UnconsumedData();
|
|
39
|
+
}
|
|
40
|
+
|
|
63
41
|
/// @notice Return the cursor's current absolute calldata position.
|
|
64
42
|
/// @param cur Cursor to inspect.
|
|
65
43
|
/// @return Current absolute calldata position.
|
|
@@ -164,9 +142,9 @@ library Decoders {
|
|
|
164
142
|
/// @param cur Cursor whose calldata is returned.
|
|
165
143
|
/// @return Complete cursor region.
|
|
166
144
|
function raw(Cur memory cur) internal pure returns (bytes calldata) {
|
|
167
|
-
(
|
|
168
|
-
if (
|
|
169
|
-
return msg.data[
|
|
145
|
+
(uint abs, uint end) = cur.state.bounds();
|
|
146
|
+
if (end > msg.data.length) revert Blocks.MalformedBlocks();
|
|
147
|
+
return msg.data[abs:end];
|
|
170
148
|
}
|
|
171
149
|
|
|
172
150
|
/// @notice Return relative calldata range `[from, to)` from `cur`.
|
|
@@ -398,6 +376,26 @@ library Decoders {
|
|
|
398
376
|
node = Blocks.unpackNode(abs);
|
|
399
377
|
}
|
|
400
378
|
|
|
379
|
+
/// @notice Decode and consume one CASHOUT block.
|
|
380
|
+
/// @param cur Cursor advanced past the block.
|
|
381
|
+
/// @return amount Native-asset amount to withdraw.
|
|
382
|
+
function unpackCashout(Cur memory cur) internal pure returns (uint amount) {
|
|
383
|
+
uint abs;
|
|
384
|
+
(cur.state, abs) = cur.state.consume(Sizes.Cashout);
|
|
385
|
+
amount = Blocks.unpackCashout(abs);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/// @notice Decode and consume one BOOTSTRAP block.
|
|
389
|
+
/// @param cur Cursor advanced past the block.
|
|
390
|
+
/// @return asset Decoded asset identifier.
|
|
391
|
+
/// @return amount Decoded balance amount.
|
|
392
|
+
/// @return budget Decoded native-value budget contribution.
|
|
393
|
+
function unpackBootstrap(Cur memory cur) internal pure returns (bytes32 asset, uint amount, uint budget) {
|
|
394
|
+
uint abs;
|
|
395
|
+
(cur.state, abs) = cur.state.consume(Sizes.Bootstrap);
|
|
396
|
+
return Blocks.unpackBootstrap(abs);
|
|
397
|
+
}
|
|
398
|
+
|
|
401
399
|
/// @notice Decode and consume one ASSET block.
|
|
402
400
|
/// @param cur Cursor advanced past the block.
|
|
403
401
|
/// @return asset Decoded asset identifier.
|
|
@@ -738,14 +736,14 @@ library Decoders {
|
|
|
738
736
|
/// @notice Decode and consume one STEP block.
|
|
739
737
|
/// @param cur Cursor advanced past the block.
|
|
740
738
|
/// @return cmd Decoded command identifier.
|
|
741
|
-
/// @return
|
|
739
|
+
/// @return value Decoded native value.
|
|
742
740
|
/// @return input Decoded command input.
|
|
743
741
|
function unpackStep(
|
|
744
742
|
Cur memory cur
|
|
745
|
-
) internal pure returns (uint cmd,
|
|
743
|
+
) internal pure returns (uint cmd, uint128 value, bytes calldata input) {
|
|
746
744
|
uint abs = cur.state.absolute();
|
|
747
745
|
uint end;
|
|
748
|
-
(cmd,
|
|
746
|
+
(cmd, value, input, end) = Blocks.unpackStep(abs);
|
|
749
747
|
cur.state = cur.state.seekAbs(end);
|
|
750
748
|
}
|
|
751
749
|
|
package/codec/Descriptors.sol
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {Blocks} from "./Blocks.sol";
|
|
5
|
+
import {Buffers} from "./Buffers.sol";
|
|
6
|
+
import {Sizes, Specs} from "./Specs.sol";
|
|
5
7
|
import {Lanes} from "../utils/Lanes.sol";
|
|
6
8
|
|
|
7
9
|
/// @title Flags
|
|
@@ -19,107 +21,108 @@ library Flags {
|
|
|
19
21
|
/// @title Descriptors
|
|
20
22
|
/// @notice Packing and lane metadata helpers for endpoint descriptors.
|
|
21
23
|
library Descriptors {
|
|
22
|
-
/// @dev The requested lane is not part of an endpoint descriptor.
|
|
23
|
-
error InvalidLane();
|
|
24
|
-
|
|
25
24
|
/// @notice Create a descriptor from endpoint lane specifications and flags.
|
|
26
25
|
/// @dev Layout: `[state key:4][stride:1]`
|
|
27
26
|
/// `[input key:4][stride:1]`
|
|
28
27
|
/// `[output key:4][min:4][max:4][hint:3][stride:1]`
|
|
29
|
-
/// `[reserved:
|
|
30
|
-
/// `[transactions:1]`
|
|
28
|
+
/// `[reserved:5]`
|
|
31
29
|
/// `[flags:1]`. Flag bits: funded = 0, admin = 1; bits 6 and 7 are
|
|
32
30
|
/// reserved for endpoint-defined custom flags.
|
|
31
|
+
/// @dev TODO: Add per-lane cardinality metadata so off-chain consumers can
|
|
32
|
+
/// distinguish exactly-one lanes from batches. Command decoding must remain
|
|
33
|
+
/// the runtime source of truth; this metadata should not restore eager scans.
|
|
33
34
|
/// @param state State lane specification.
|
|
34
35
|
/// @param input Direct input lane specification.
|
|
35
36
|
/// @param output Output writer specification.
|
|
36
|
-
/// @param transactions Transactions produced per batch.
|
|
37
37
|
/// @param flags Endpoint behavior flags.
|
|
38
38
|
/// @return descriptor Packed endpoint descriptor.
|
|
39
39
|
function create(
|
|
40
40
|
uint state,
|
|
41
41
|
uint input,
|
|
42
42
|
uint output,
|
|
43
|
-
uint8 transactions,
|
|
44
43
|
uint8 flags
|
|
45
44
|
) internal pure returns (uint descriptor) {
|
|
46
45
|
output = Specs.normalize(output);
|
|
47
|
-
descriptor = pack(state, input, output, transactions, flags);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/// @dev Pack endpoint specs and flags into a descriptor.
|
|
51
|
-
/// @param state State specification.
|
|
52
|
-
/// @param input Input specification.
|
|
53
|
-
/// @param output Normalized direct output specification.
|
|
54
|
-
/// @param transactions Transactions produced per batch.
|
|
55
|
-
/// @param flags Endpoint behavior flags.
|
|
56
|
-
/// @return descriptor Packed endpoint descriptor.
|
|
57
|
-
function pack(
|
|
58
|
-
uint state,
|
|
59
|
-
uint input,
|
|
60
|
-
uint output,
|
|
61
|
-
uint8 transactions,
|
|
62
|
-
uint8 flags
|
|
63
|
-
) private pure returns (uint descriptor) {
|
|
64
46
|
descriptor |= uint(Specs.lane(state)) << 216;
|
|
65
47
|
descriptor |= uint(Specs.lane(input)) << 176;
|
|
66
48
|
descriptor |= (output >> 128) << 48;
|
|
67
|
-
descriptor |= uint(transactions) << 8;
|
|
68
49
|
descriptor |= flags;
|
|
69
50
|
}
|
|
70
51
|
|
|
71
|
-
/// @
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
52
|
+
/// @dev Wrap endpoint input with its descriptor stride and lane tag.
|
|
53
|
+
function inputCursor(bytes calldata source, uint descriptor) private pure returns (uint cur) {
|
|
54
|
+
uint tag = Lanes.Input;
|
|
55
|
+
assembly ("memory-safe") {
|
|
56
|
+
cur := or(
|
|
57
|
+
or(or(shl(32, source.offset), shl(64, source.length)), shl(96, byte(9, descriptor))),
|
|
58
|
+
shl(120, tag)
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// @dev Wrap command state with its descriptor stride and lane tag.
|
|
64
|
+
function stateCursor(bytes calldata source, uint descriptor) private pure returns (uint cur) {
|
|
65
|
+
uint tag = Lanes.State;
|
|
66
|
+
assembly ("memory-safe") {
|
|
67
|
+
cur := or(
|
|
68
|
+
or(or(shl(32, source.offset), shl(64, source.length)), shl(96, byte(4, descriptor))),
|
|
69
|
+
shl(120, tag)
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// @dev Initialize the output writer from the selected lower decoder lane.
|
|
75
|
+
/// The run count is an allocation hint only; decoding and finalization validate the source.
|
|
76
|
+
function writerCursor(uint decoders, uint descriptor) private pure returns (uint writer) {
|
|
77
|
+
uint outputStride = uint8(descriptor >> 48);
|
|
78
|
+
if (outputStride == 0) return 0;
|
|
79
|
+
|
|
80
|
+
uint decoderStride = uint8(decoders >> 96);
|
|
81
|
+
uint count;
|
|
82
|
+
if (decoderStride != 0) {
|
|
83
|
+
uint abs = uint32(decoders >> 32);
|
|
84
|
+
uint end = abs + uint32(decoders >> 64);
|
|
85
|
+
uint laneShift = uint8(decoders >> 120) == Lanes.Input ? 176 : 216;
|
|
86
|
+
count = Blocks.runCount(
|
|
87
|
+
abs,
|
|
88
|
+
end,
|
|
89
|
+
bytes4(uint32(descriptor >> (laneShift + 8)))
|
|
90
|
+
) / decoderStride * outputStride;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
uint capacity = count * (Sizes.Header + uint24(descriptor >> 56));
|
|
94
|
+
writer = Buffers.cursor(capacity, uint8(outputStride), 0);
|
|
77
95
|
}
|
|
78
96
|
|
|
79
|
-
/// @notice
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (lane == Lanes.State) return uint8(descriptor >> 216);
|
|
87
|
-
if (lane == Lanes.Input) return uint8(descriptor >> 176);
|
|
88
|
-
if (lane == Lanes.Output) return uint8(descriptor >> 48);
|
|
89
|
-
if (lane == Lanes.Transactions) return uint8(descriptor >> 8);
|
|
90
|
-
revert InvalidLane();
|
|
97
|
+
/// @notice Open descriptor-backed input and output cursors.
|
|
98
|
+
function openInput(
|
|
99
|
+
uint descriptor,
|
|
100
|
+
bytes calldata input
|
|
101
|
+
) internal pure returns (uint decoders, uint writer) {
|
|
102
|
+
decoders = inputCursor(input, descriptor);
|
|
103
|
+
writer = writerCursor(decoders, descriptor);
|
|
91
104
|
}
|
|
92
105
|
|
|
93
|
-
/// @notice
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (lane == Lanes.State) return bytes4(uint32(descriptor >> 224));
|
|
101
|
-
if (lane == Lanes.Input) return bytes4(uint32(descriptor >> 184));
|
|
102
|
-
if (lane == Lanes.Output) return bytes4(uint32(descriptor >> 144));
|
|
103
|
-
if (lane == Lanes.Transactions) return Specs.key(Specs.Transaction);
|
|
104
|
-
revert InvalidLane();
|
|
106
|
+
/// @notice Open descriptor-backed state and output cursors.
|
|
107
|
+
function openState(
|
|
108
|
+
uint descriptor,
|
|
109
|
+
bytes calldata state
|
|
110
|
+
) internal pure returns (uint decoders, uint writer) {
|
|
111
|
+
decoders = stateCursor(state, descriptor);
|
|
112
|
+
writer = writerCursor(decoders, descriptor);
|
|
105
113
|
}
|
|
106
114
|
|
|
107
|
-
/// @notice
|
|
108
|
-
/// @
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
/// @notice Open paired descriptor-backed state, input, and output cursors.
|
|
116
|
+
/// @dev Input remains low when present; otherwise state becomes the active lower lane.
|
|
117
|
+
function open(
|
|
118
|
+
uint descriptor,
|
|
119
|
+
bytes calldata state,
|
|
120
|
+
bytes calldata input
|
|
121
|
+
) internal pure returns (uint decoders, uint writer) {
|
|
122
|
+
decoders = inputCursor(input, descriptor) | (stateCursor(state, descriptor) << 128);
|
|
123
|
+
if (uint8(decoders >> 96) == 0) {
|
|
124
|
+
decoders = (decoders << 128) | (decoders >> 128);
|
|
117
125
|
}
|
|
118
|
-
|
|
119
|
-
uint count = groups * stride(descriptor, lane);
|
|
120
|
-
return Specs.allocation(Specs.Transaction, count);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
revert InvalidLane();
|
|
126
|
+
writer = writerCursor(decoders, descriptor);
|
|
124
127
|
}
|
|
125
128
|
}
|
package/codec/Keys.sol
CHANGED
|
@@ -11,6 +11,10 @@ library Keys {
|
|
|
11
11
|
bytes4 constant Empty = bytes4(0);
|
|
12
12
|
/// @dev Input amount - (bytes32 asset, uint amount)
|
|
13
13
|
bytes4 constant Amount = bytes4(keccak256("#amount"));
|
|
14
|
+
/// @dev Native-asset cashout request - (uint amount)
|
|
15
|
+
bytes4 constant Cashout = bytes4(keccak256("#cashout"));
|
|
16
|
+
/// @dev Pipeline bootstrap request - (bytes32 asset, uint amount, uint budget)
|
|
17
|
+
bytes4 constant Bootstrap = bytes4(keccak256("#bootstrap"));
|
|
14
18
|
/// @dev Ledger balance - (bytes32 asset, uint amount)
|
|
15
19
|
bytes4 constant Balance = bytes4(keccak256("#balance"));
|
|
16
20
|
/// @dev Liability-only debt state - (bytes32 liability, uint debt)
|
|
@@ -35,7 +39,7 @@ library Keys {
|
|
|
35
39
|
bytes4 constant Account = bytes4(keccak256("#account"));
|
|
36
40
|
/// @dev Transfer record passed through the pipeline - (bytes32 from, bytes32 to, bytes32 asset, uint amount)
|
|
37
41
|
bytes4 constant Transaction = bytes4(keccak256("#transaction"));
|
|
38
|
-
/// @dev Sub-command invocation - (uint cmd,
|
|
42
|
+
/// @dev Sub-command invocation - (uint cmd, uint128 value, #bytes as input)
|
|
39
43
|
bytes4 constant Step = bytes4(keccak256("#step"));
|
|
40
44
|
/// @dev Portal relay input - (uint portal, uint resources, #bytes as input)
|
|
41
45
|
bytes4 constant Relay = bytes4(keccak256("#relay"));
|
package/codec/Schema.sol
CHANGED
|
@@ -32,6 +32,8 @@ pragma solidity ^0.8.33;
|
|
|
32
32
|
// - `resources` fields are chain-specific resource words. A portal adapter
|
|
33
33
|
// interprets them for the destination runtime. EVM resources use the low
|
|
34
34
|
// 128 bits as native value.
|
|
35
|
+
// - STEP encodes native `value` directly as uint128; it does not carry a
|
|
36
|
+
// chain-specific resources word
|
|
35
37
|
// - dotted field names and aliases, e.g. `dst.portal` or `#bytes as dst.payload`,
|
|
36
38
|
// are offchain projection metadata only and do not change runtime encoding
|
|
37
39
|
// - `at N` assigns an offchain presentation position to one sibling; explicit
|
|
@@ -84,6 +86,7 @@ library Schemas {
|
|
|
84
86
|
string constant Account = "bytes32 account";
|
|
85
87
|
string constant Asset = "bytes32 asset";
|
|
86
88
|
string constant Status = "uint code";
|
|
89
|
+
string constant Cashout = "uint amount";
|
|
87
90
|
|
|
88
91
|
// Two-word payloads
|
|
89
92
|
|
|
@@ -95,6 +98,7 @@ library Schemas {
|
|
|
95
98
|
|
|
96
99
|
// Three-word payloads
|
|
97
100
|
|
|
101
|
+
string constant Bootstrap = "bytes32 asset, uint amount, uint budget";
|
|
98
102
|
string constant Allocation = "uint host, bytes32 asset, uint amount";
|
|
99
103
|
string constant Allowance = "uint host, bytes32 asset, uint amount";
|
|
100
104
|
string constant Custody = "uint host, bytes32 asset, uint amount";
|
|
@@ -110,8 +114,8 @@ library Schemas {
|
|
|
110
114
|
|
|
111
115
|
// Composite payloads
|
|
112
116
|
|
|
117
|
+
string constant Step = "uint cmd, uint128 value, #bytes as input";
|
|
113
118
|
string constant Call = "uint target, uint resources, #bytes as payload";
|
|
114
|
-
string constant Step = "uint cmd, uint resources, #bytes as input";
|
|
115
119
|
string constant Relay = "uint portal, uint resources, #bytes as input";
|
|
116
120
|
string constant Dispatch = "uint portal, uint resources, #bytes as payload";
|
|
117
121
|
string constant Context = "bytes32 account, #bytes as state, #bytes as input";
|
package/codec/Specs.sol
CHANGED
|
@@ -21,8 +21,14 @@ library Sizes {
|
|
|
21
21
|
uint constant B128 = Header + 4 * Word;
|
|
22
22
|
/// @dev 8 header + 160 payload = 168 bytes total.
|
|
23
23
|
uint constant B160 = Header + 5 * Word;
|
|
24
|
+
/// @dev Minimum STEP size: 8 header + 32 command + 16 value + 8 nested BYTES header.
|
|
25
|
+
uint constant Step = 2 * Header + Word + 16;
|
|
24
26
|
/// @dev STATUS block: 8 header + 32 status code = 40 bytes
|
|
25
27
|
uint constant Status = B32;
|
|
28
|
+
/// @dev CASHOUT block: 8 header + 32 native-asset amount = 40 bytes
|
|
29
|
+
uint constant Cashout = B32;
|
|
30
|
+
/// @dev BOOTSTRAP block: 8 header + 32 asset + 32 amount + 32 budget = 104 bytes
|
|
31
|
+
uint constant Bootstrap = B96;
|
|
26
32
|
/// @dev AMOUNT block: 8 header + 32 asset + 32 amount = 72 bytes
|
|
27
33
|
uint constant Amount = B64;
|
|
28
34
|
/// @dev BALANCE block: 8 header + 32 asset + 32 amount = 72 bytes
|
|
@@ -44,7 +50,7 @@ library Sizes {
|
|
|
44
50
|
/// `[key:4][min:4][max:4][hint:3][stride:1][reserved:16]`.
|
|
45
51
|
/// The upper eight bytes of a fixed-layout spec are its encoded block header,
|
|
46
52
|
/// allowing the entire spec word to be written directly as that header.
|
|
47
|
-
/// A maximum of zero means
|
|
53
|
+
/// A maximum of zero means the payload size is unbounded.
|
|
48
54
|
library Specs {
|
|
49
55
|
/// @dev A payload is incompatible with its block specification.
|
|
50
56
|
error InvalidSpec();
|
|
@@ -58,11 +64,14 @@ library Specs {
|
|
|
58
64
|
uint private constant Exact128 = 128 * SizeFields;
|
|
59
65
|
uint private constant UnboundedHint128 = uint(128) << 136;
|
|
60
66
|
uint private constant UnboundedMin40Hint256 = (uint(40) << 192) | (uint(256) << 136);
|
|
67
|
+
uint private constant UnboundedMin56Hint256 = (uint(56) << 192) | (uint(256) << 136);
|
|
61
68
|
uint private constant UnboundedMin72Hint256 = (uint(72) << 192) | (uint(256) << 136);
|
|
62
69
|
uint private constant UnboundedMin48Hint512 = (uint(48) << 192) | (uint(512) << 136);
|
|
63
70
|
uint private constant UnboundedMin104Hint256 = (uint(104) << 192) | (uint(256) << 136);
|
|
64
71
|
|
|
65
72
|
uint constant Empty = uint(bytes32(Keys.Empty));
|
|
73
|
+
uint constant Cashout = uint(bytes32(Keys.Cashout)) | Exact32;
|
|
74
|
+
uint constant Bootstrap = uint(bytes32(Keys.Bootstrap)) | Exact96;
|
|
66
75
|
uint constant Amount = uint(bytes32(Keys.Amount)) | Exact64;
|
|
67
76
|
uint constant Balance = uint(bytes32(Keys.Balance)) | Exact64;
|
|
68
77
|
uint constant Debt = uint(bytes32(Keys.Debt)) | Exact64;
|
|
@@ -76,7 +85,7 @@ library Specs {
|
|
|
76
85
|
uint constant String = uint(bytes32(Keys.String)) | UnboundedHint128;
|
|
77
86
|
uint constant Account = uint(bytes32(Keys.Account)) | Exact32;
|
|
78
87
|
uint constant Transaction = uint(bytes32(Keys.Transaction)) | Exact128;
|
|
79
|
-
uint constant Step = uint(bytes32(Keys.Step)) |
|
|
88
|
+
uint constant Step = uint(bytes32(Keys.Step)) | UnboundedMin56Hint256;
|
|
80
89
|
uint constant Relay = uint(bytes32(Keys.Relay)) | UnboundedMin72Hint256;
|
|
81
90
|
uint constant Context = uint(bytes32(Keys.Context)) | UnboundedMin48Hint512;
|
|
82
91
|
uint constant Recover = uint(bytes32(Keys.Recover)) | UnboundedMin104Hint256;
|
|
@@ -205,18 +214,19 @@ library Specs {
|
|
|
205
214
|
/// @param groups Number of groups.
|
|
206
215
|
/// @return Number of blocks across all groups.
|
|
207
216
|
function count(uint spec, uint groups) internal pure returns (uint) {
|
|
208
|
-
|
|
217
|
+
uint8 n = uint8(spec >> 128);
|
|
218
|
+
if (n == 0 && uint32(spec >> 224) != 0) n = 1;
|
|
219
|
+
return groups * n;
|
|
209
220
|
}
|
|
210
221
|
|
|
211
|
-
/// @notice Return the buffer
|
|
212
|
-
/// @dev Dynamic specs use their allocation hint and a maximum of zero means growable.
|
|
222
|
+
/// @notice Return the initial buffer capacity for `groups` of `spec`.
|
|
213
223
|
/// @param spec Packed block specification.
|
|
214
224
|
/// @param groups Number of groups to allocate.
|
|
215
225
|
/// @return capacity Initial encoded byte capacity.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
226
|
+
function allocation(uint spec, uint groups) internal pure returns (uint capacity) {
|
|
227
|
+
uint8 n = uint8(spec >> 128);
|
|
228
|
+
if (n == 0 && uint32(spec >> 224) != 0) n = 1;
|
|
229
|
+
capacity = groups * n * (Sizes.Header + uint24(spec >> 136));
|
|
220
230
|
}
|
|
221
231
|
|
|
222
232
|
/// @notice Return `spec` grouped with an explicit stride.
|
package/codec/Writers.sol
CHANGED
|
@@ -8,8 +8,7 @@ import {Sizes, Specs} from "./Specs.sol";
|
|
|
8
8
|
|
|
9
9
|
/// @notice Sequential block stream writer backed by a pre-allocated memory buffer.
|
|
10
10
|
struct Writer {
|
|
11
|
-
/// @dev Packed cursor metadata. `len` is logical capacity
|
|
12
|
-
/// indicates whether the backing buffer may grow.
|
|
11
|
+
/// @dev Packed cursor metadata. `len` is the current logical capacity.
|
|
13
12
|
uint cur;
|
|
14
13
|
/// @dev Destination buffer. Physical capacity may be padded up to a full 32-byte word;
|
|
15
14
|
/// final length is set to the packed write position by `finish`.
|
|
@@ -30,22 +29,18 @@ library Writers {
|
|
|
30
29
|
|
|
31
30
|
/// @notice Initialize writer metadata without allocating a backing buffer.
|
|
32
31
|
/// @param len Initial logical byte capacity of the writer.
|
|
33
|
-
/// @param growable Whether append helpers may expand the capacity.
|
|
34
32
|
/// @return writer Unallocated writer positioned at index 0.
|
|
35
|
-
function init(uint len
|
|
36
|
-
writer.cur = Buffers.cursor(len, 0,
|
|
33
|
+
function init(uint len) internal pure returns (Writer memory writer) {
|
|
34
|
+
writer.cur = Buffers.cursor(len, 0, 0);
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
/// @notice Initialize writer metadata for `groups` of blocks described by `spec`.
|
|
40
38
|
/// @param spec Packed block key, payload bounds, allocation hint, and flags.
|
|
41
39
|
/// @param groups Number of descriptor groups the writer is expected to encode.
|
|
42
|
-
/// @return writer Unallocated writer with capacity derived from the specification
|
|
43
|
-
/// or an inert empty writer when its capacity is zero.
|
|
40
|
+
/// @return writer Unallocated writer with initial capacity derived from the specification.
|
|
44
41
|
function init(uint spec, uint groups) internal pure returns (Writer memory writer) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
writer.cur = Buffers.cursor(capacity, Specs.count(spec, groups), growable, 0);
|
|
42
|
+
uint capacity = Specs.allocation(spec, groups);
|
|
43
|
+
writer.cur = Buffers.cursor(capacity, Specs.stride(Specs.normalize(spec)), 0);
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
// -------------------------------------------------------------------------
|
|
@@ -66,7 +61,7 @@ library Writers {
|
|
|
66
61
|
/// @param size Number of bytes to reserve and touch.
|
|
67
62
|
/// @return i Relative offset reserved for the write.
|
|
68
63
|
function reserve(Writer memory writer, uint size) private pure returns (uint i) {
|
|
69
|
-
|
|
64
|
+
(writer.cur, writer.dst, i) = Buffers.reserve(writer.cur, writer.dst, size, size);
|
|
70
65
|
}
|
|
71
66
|
|
|
72
67
|
// -------------------------------------------------------------------------
|
|
@@ -417,12 +412,12 @@ library Writers {
|
|
|
417
412
|
/// @notice Append a STEP block.
|
|
418
413
|
/// @param writer Destination writer.
|
|
419
414
|
/// @param cmd Command identifier to encode.
|
|
420
|
-
/// @param
|
|
415
|
+
/// @param value Native value to encode.
|
|
421
416
|
/// @param input Command input to encode.
|
|
422
|
-
function appendStep(Writer memory writer, uint cmd,
|
|
423
|
-
uint size = Sizes.
|
|
417
|
+
function appendStep(Writer memory writer, uint cmd, uint128 value, bytes memory input) internal pure {
|
|
418
|
+
uint size = Sizes.Step + input.length;
|
|
424
419
|
uint i = reserve(writer, size);
|
|
425
|
-
Blocks.writeStep(writer.dst, i, cmd,
|
|
420
|
+
Blocks.writeStep(writer.dst, i, cmd, value, input);
|
|
426
421
|
}
|
|
427
422
|
|
|
428
423
|
/// @notice Append a CALL block.
|
|
@@ -566,10 +561,10 @@ library Writers {
|
|
|
566
561
|
}
|
|
567
562
|
|
|
568
563
|
/// @notice Append a STEP block by copying its nested input from calldata.
|
|
569
|
-
function copyStep(Writer memory writer, uint cmd,
|
|
570
|
-
uint size = Sizes.
|
|
564
|
+
function copyStep(Writer memory writer, uint cmd, uint128 value, bytes calldata input) internal pure {
|
|
565
|
+
uint size = Sizes.Step + input.length;
|
|
571
566
|
uint i = reserve(writer, size);
|
|
572
|
-
Blocks.copyStep(writer.dst, i, cmd,
|
|
567
|
+
Blocks.copyStep(writer.dst, i, cmd, value, input);
|
|
573
568
|
}
|
|
574
569
|
|
|
575
570
|
/// @notice Append a CALL block by copying its nested payload from calldata.
|