@rootzero/contracts 1.15.0 → 1.17.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 +90 -0
- package/Codec.sol +1 -1
- package/Commands.sol +1 -1
- package/Core.sol +4 -4
- package/Endpoints.sol +9 -7
- package/Events.sol +0 -1
- package/README.md +88 -30
- package/Utils.sol +1 -1
- package/codec/Blocks.sol +111 -21
- package/codec/Buffers.sol +3 -3
- package/codec/Decoders.sol +48 -10
- package/codec/Descriptors.sol +0 -1
- package/codec/Keys.sol +4 -2
- package/codec/Readers.sol +25 -0
- package/codec/Schema.sol +6 -1
- package/codec/Specs.sol +7 -2
- package/codec/Writers.sol +28 -2
- package/commands/Base.sol +8 -15
- package/commands/Burn.sol +2 -2
- package/commands/Credit.sol +38 -3
- package/commands/Debit.sol +50 -14
- package/commands/Deposit.sol +4 -4
- package/commands/Provision.sol +4 -4
- package/commands/Recover.sol +15 -8
- package/commands/Relay.sol +37 -12
- package/commands/Settle.sol +130 -0
- package/commands/Withdraw.sol +2 -2
- package/commands/admin/AllowAssets.sol +2 -2
- package/commands/admin/Allowance.sol +3 -3
- package/commands/admin/Annotate.sol +2 -2
- package/commands/admin/Appoint.sol +2 -2
- package/commands/admin/Authorize.sol +2 -2
- package/commands/admin/DenyAssets.sol +2 -2
- package/commands/admin/Dismiss.sol +2 -2
- package/commands/admin/Execute.sol +3 -3
- package/commands/admin/Unauthorize.sol +2 -2
- package/core/Endpoint.sol +15 -13
- package/core/Pipeline.sol +6 -6
- package/core/Settlement.sol +37 -8
- package/core/Types.sol +21 -1
- package/docs/Schema.md +52 -2
- package/execution/Budget.sol +12 -4
- package/execution/Execution.sol +119 -11
- package/guards/Base.sol +2 -2
- package/guards/Revoke.sol +21 -0
- package/package.json +1 -1
- package/ports/Base.sol +2 -2
- package/ports/Dispatch.sol +6 -6
- package/ports/{Settle.sol → Post.sol} +10 -10
- package/queries/Base.sol +2 -2
- package/utils/Actions.sol +1 -0
- package/utils/Cursors.sol +16 -30
- package/events/Position.sol +0 -22
package/codec/Decoders.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 {AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, Tx} from "../core/Types.sol";
|
|
4
|
+
import {AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAccountAsset, Position, Tx} from "../core/Types.sol";
|
|
5
5
|
import {Blocks} from "./Blocks.sol";
|
|
6
6
|
import {Sizes, Specs} from "./Specs.sol";
|
|
7
7
|
import {Cursors, Cur} from "../utils/Cursors.sol";
|
|
@@ -32,20 +32,17 @@ library Decoders {
|
|
|
32
32
|
cur.state = Cursors.wrap(source[i:], 0, 0);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
/// @notice Open the first homogeneous run in `source
|
|
35
|
+
/// @notice Open the first homogeneous run in `source`.
|
|
36
36
|
/// @param source Calldata block stream to open.
|
|
37
|
-
/// @param stride Number of blocks per group, or zero for an ungrouped stream.
|
|
38
37
|
/// @return cur Cursor spanning the first homogeneous run.
|
|
39
|
-
function open(
|
|
40
|
-
bytes calldata source,
|
|
41
|
-
uint stride
|
|
42
|
-
) internal pure returns (Cur memory cur) {
|
|
38
|
+
function open(bytes calldata source) internal pure returns (Cur memory cur) {
|
|
43
39
|
(uint abs, uint limit) = Cursors.bounds(source);
|
|
44
|
-
if (
|
|
40
|
+
if (abs == limit) revert Blocks.EmptyRun();
|
|
45
41
|
|
|
46
42
|
bytes4 key = bytes4(source);
|
|
47
|
-
(uint
|
|
48
|
-
|
|
43
|
+
(uint count, uint end) = Blocks.run(abs, limit, key);
|
|
44
|
+
if (count == 0) revert Blocks.EmptyRun();
|
|
45
|
+
cur.state = Cursors.create(abs, end - abs, count, 0, 0);
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
/// @notice Return whether `cur` has unread bytes.
|
|
@@ -163,6 +160,16 @@ library Decoders {
|
|
|
163
160
|
return Blocks.find(offset + i, offset + end, key) - offset;
|
|
164
161
|
}
|
|
165
162
|
|
|
163
|
+
/// @notice Count consecutive blocks with `key` from the current cursor position.
|
|
164
|
+
/// @dev Does not advance the cursor.
|
|
165
|
+
/// @param cur Cursor to inspect.
|
|
166
|
+
/// @param key Block key forming the run.
|
|
167
|
+
/// @return count Number of consecutive matching blocks.
|
|
168
|
+
function run(Cur memory cur, bytes4 key) internal pure returns (uint count) {
|
|
169
|
+
(uint i, uint offset, uint len) = cur.state.decode();
|
|
170
|
+
(count, ) = Blocks.run(offset + i, offset + len, key);
|
|
171
|
+
}
|
|
172
|
+
|
|
166
173
|
/// @notice Consume one LIST block and return a cursor over its items.
|
|
167
174
|
/// @param cur Cursor advanced past the list.
|
|
168
175
|
/// @return items Cursor spanning the list payload.
|
|
@@ -269,6 +276,16 @@ library Decoders {
|
|
|
269
276
|
(account, asset) = Blocks.unpackAccountAsset(abs);
|
|
270
277
|
}
|
|
271
278
|
|
|
279
|
+
/// @notice Decode and consume one HOST_ASSET block.
|
|
280
|
+
/// @param cur Cursor advanced past the block.
|
|
281
|
+
/// @return host Decoded host identifier.
|
|
282
|
+
/// @return asset Decoded asset identifier.
|
|
283
|
+
function unpackHostAsset(Cur memory cur) internal pure returns (uint host, bytes32 asset) {
|
|
284
|
+
uint abs;
|
|
285
|
+
(cur.state, abs) = cur.state.consume(Sizes.HostAsset);
|
|
286
|
+
(host, asset) = Blocks.unpackHostAsset(abs);
|
|
287
|
+
}
|
|
288
|
+
|
|
272
289
|
/// @notice Decode and consume one AMOUNT block.
|
|
273
290
|
/// @param cur Cursor advanced past the block.
|
|
274
291
|
/// @return asset Decoded asset identifier.
|
|
@@ -455,6 +472,13 @@ library Decoders {
|
|
|
455
472
|
(value.account, value.asset) = unpackAccountAsset(cur);
|
|
456
473
|
}
|
|
457
474
|
|
|
475
|
+
/// @notice Decode one HOST_ASSET block into its structured value.
|
|
476
|
+
/// @param cur Cursor advanced past the block.
|
|
477
|
+
/// @return value Structured host and asset.
|
|
478
|
+
function unpackHostAssetValue(Cur memory cur) internal pure returns (HostAsset memory value) {
|
|
479
|
+
(value.host, value.asset) = unpackHostAsset(cur);
|
|
480
|
+
}
|
|
481
|
+
|
|
458
482
|
/// @notice Decode one AMOUNT block into its structured value.
|
|
459
483
|
/// @param cur Cursor advanced past the block.
|
|
460
484
|
/// @return value Structured asset amount.
|
|
@@ -532,6 +556,20 @@ library Decoders {
|
|
|
532
556
|
(value.host, value.asset, value.amount) = unpackCustody(cur);
|
|
533
557
|
}
|
|
534
558
|
|
|
559
|
+
/// @notice Decode and consume one POSITION block.
|
|
560
|
+
function unpackPosition(
|
|
561
|
+
Cur memory cur
|
|
562
|
+
) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
|
|
563
|
+
uint abs;
|
|
564
|
+
(cur.state, abs) = cur.state.consume(Sizes.Position);
|
|
565
|
+
(asset, amount, liability, debt) = Blocks.unpackPosition(abs);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/// @notice Decode one POSITION block into its structured value.
|
|
569
|
+
function unpackPositionValue(Cur memory cur) internal pure returns (Position memory value) {
|
|
570
|
+
(value.asset, value.amount, value.liability, value.debt) = unpackPosition(cur);
|
|
571
|
+
}
|
|
572
|
+
|
|
535
573
|
/// @notice Decode one TRANSACTION block into its structured value.
|
|
536
574
|
/// @param cur Cursor advanced past the block.
|
|
537
575
|
/// @return value Structured transaction.
|
package/codec/Descriptors.sol
CHANGED
package/codec/Keys.sol
CHANGED
|
@@ -9,8 +9,6 @@ pragma solidity ^0.8.33;
|
|
|
9
9
|
library Keys {
|
|
10
10
|
/// @dev Empty / unset key.
|
|
11
11
|
bytes4 constant Empty = bytes4(0);
|
|
12
|
-
/// @dev Wildcard key used in discovery when any block stream is accepted.
|
|
13
|
-
bytes4 constant Any = 0xffffffff;
|
|
14
12
|
/// @dev Input amount - (bytes32 asset, uint amount)
|
|
15
13
|
bytes4 constant Amount = bytes4(keccak256("#amount"));
|
|
16
14
|
/// @dev Ledger balance - (bytes32 asset, uint amount)
|
|
@@ -21,6 +19,8 @@ library Keys {
|
|
|
21
19
|
bytes4 constant Allowance = bytes4(keccak256("#allowance"));
|
|
22
20
|
/// @dev Cross-host custody state - (uint host, bytes32 asset, uint amount)
|
|
23
21
|
bytes4 constant Custody = bytes4(keccak256("#custody"));
|
|
22
|
+
/// @dev Asset-liability position state - (bytes32 asset, uint amount, bytes32 liability, uint debt)
|
|
23
|
+
bytes4 constant Position = bytes4(keccak256("#position"));
|
|
24
24
|
/// @dev List wrapper; payload is an embedded repeated block stream
|
|
25
25
|
bytes4 constant List = bytes4(keccak256("#list"));
|
|
26
26
|
/// @dev EVM-encoded payload field; layout follows standard ABI tuple encoding
|
|
@@ -62,6 +62,8 @@ library Keys {
|
|
|
62
62
|
bytes4 constant Status = bytes4(keccak256("#status"));
|
|
63
63
|
/// @dev Structural account asset form - (bytes32 account, bytes32 asset)
|
|
64
64
|
bytes4 constant AccountAsset = bytes4(keccak256("#accountAsset"));
|
|
65
|
+
/// @dev Structural host asset form - (uint host, bytes32 asset)
|
|
66
|
+
bytes4 constant HostAsset = bytes4(keccak256("#hostAsset"));
|
|
65
67
|
/// @dev Structural account amount form - (bytes32 account, bytes32 asset, uint amount)
|
|
66
68
|
bytes4 constant AccountAmount = bytes4(keccak256("#accountAmount"));
|
|
67
69
|
/// @dev Structural host amount form - (uint host, bytes32 asset, uint amount)
|
package/codec/Readers.sol
CHANGED
|
@@ -94,6 +94,31 @@ library Readers {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/// @notice Consume a HOST_ASSET block and return its fields.
|
|
98
|
+
/// @param cur Reader; advanced past the block.
|
|
99
|
+
/// @return host Host identifier.
|
|
100
|
+
/// @return asset Asset identifier.
|
|
101
|
+
function unpackHostAsset(Reader memory cur) internal pure returns (uint host, bytes32 asset) {
|
|
102
|
+
uint abs = consume(cur, Keys.HostAsset, 64, 64);
|
|
103
|
+
assembly ("memory-safe") {
|
|
104
|
+
host := mload(abs)
|
|
105
|
+
asset := mload(add(abs, 0x20))
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/// @notice Consume a POSITION block and return its fields.
|
|
110
|
+
function unpackPosition(
|
|
111
|
+
Reader memory cur
|
|
112
|
+
) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
|
|
113
|
+
uint abs = consume(cur, Keys.Position, 128, 128);
|
|
114
|
+
assembly ("memory-safe") {
|
|
115
|
+
asset := mload(abs)
|
|
116
|
+
amount := mload(add(abs, 0x20))
|
|
117
|
+
liability := mload(add(abs, 0x40))
|
|
118
|
+
debt := mload(add(abs, 0x60))
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
97
122
|
/// @notice Consume a TRANSACTION block and return its fields.
|
|
98
123
|
/// @param cur Reader; advanced past the block.
|
|
99
124
|
/// @return from Source account identifier.
|
package/codec/Schema.sol
CHANGED
|
@@ -43,10 +43,13 @@ pragma solidity ^0.8.33;
|
|
|
43
43
|
// - command input and state streams are each a single run of blocks under the
|
|
44
44
|
// current protocol convention; the block format may support other shapes in
|
|
45
45
|
// future protocol surfaces
|
|
46
|
-
// - `balance(...)` and `
|
|
46
|
+
// - `balance(...)`, `custody(...)`, and `position(...)` are live, linear state in the active command pipeline
|
|
47
47
|
// - pipeline state belongs to the active account while the pipeline is executing
|
|
48
48
|
// - while a balance or custody is in-flight as pipeline state, it is not simultaneously persisted
|
|
49
49
|
// in another ledger/store by this protocol
|
|
50
|
+
// - a position pairs live asset and liability sides; commands may transform either side
|
|
51
|
+
// - position state is transient and does not itself create or erase an externally persisted obligation
|
|
52
|
+
// - positions support backward composition, but pipeline steps always execute in encoded order
|
|
50
53
|
// - commands must preserve, transform, settle, or intentionally consume pipeline state
|
|
51
54
|
// - input blocks such as `amount(...)`, `allocation(...)`, and `allowance(...)`
|
|
52
55
|
// express intent, constraints, or references
|
|
@@ -78,6 +81,7 @@ library Schemas {
|
|
|
78
81
|
string constant Amount = "{ bytes32 asset, uint amount }";
|
|
79
82
|
string constant Balance = "{ bytes32 asset, uint amount }";
|
|
80
83
|
string constant AccountAsset = "{ bytes32 account, bytes32 asset }";
|
|
84
|
+
string constant HostAsset = "{ uint host, bytes32 asset }";
|
|
81
85
|
|
|
82
86
|
// Three-word payloads
|
|
83
87
|
|
|
@@ -90,6 +94,7 @@ library Schemas {
|
|
|
90
94
|
|
|
91
95
|
// Four-word payloads
|
|
92
96
|
|
|
97
|
+
string constant Position = "{ bytes32 asset, uint amount, bytes32 liability, uint debt }";
|
|
93
98
|
string constant Transaction = "{ bytes32 from, bytes32 to, bytes32 asset, uint amount }";
|
|
94
99
|
string constant HostAccountAmount = "{ uint host, bytes32 account, bytes32 asset, uint amount }";
|
|
95
100
|
|
package/codec/Specs.sol
CHANGED
|
@@ -27,10 +27,14 @@ library Sizes {
|
|
|
27
27
|
uint constant Amount = B64;
|
|
28
28
|
/// @dev BALANCE block: 8 header + 32 asset + 32 amount = 72 bytes
|
|
29
29
|
uint constant Balance = B64;
|
|
30
|
+
/// @dev HOST_ASSET block: 8 header + 32 host + 32 asset = 72 bytes
|
|
31
|
+
uint constant HostAsset = B64;
|
|
30
32
|
/// @dev ALLOCATION/CUSTODY block: 8 header + 32 host + 32 asset + 32 amount = 104 bytes
|
|
31
33
|
uint constant HostAmount = B96;
|
|
32
34
|
/// @dev TRANSACTION block: 8 header + 32 from + 32 to + 32 asset + 32 amount = 136 bytes
|
|
33
35
|
uint constant Transaction = B128;
|
|
36
|
+
/// @dev POSITION block: 8 header + four-word asset-liability pair = 136 bytes
|
|
37
|
+
uint constant Position = B128;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
/// @title Specs
|
|
@@ -44,7 +48,6 @@ library Specs {
|
|
|
44
48
|
error InvalidSpec();
|
|
45
49
|
/// @dev A direct specification cannot contain a wrapper block.
|
|
46
50
|
error InvalidContainer();
|
|
47
|
-
|
|
48
51
|
uint private constant SizeFields = (uint(1) << 192) | (uint(1) << 160) | (uint(1) << 136);
|
|
49
52
|
|
|
50
53
|
// Reusable field shapes keep public specs readable while remaining valid
|
|
@@ -60,12 +63,12 @@ library Specs {
|
|
|
60
63
|
uint private constant UnboundedMin104Hint256 = (uint(104) << 192) | (uint(256) << 136);
|
|
61
64
|
|
|
62
65
|
uint constant Empty = uint(bytes32(Keys.Empty));
|
|
63
|
-
uint constant Any = uint(bytes32(Keys.Any)) | UnboundedHint128;
|
|
64
66
|
uint constant Amount = uint(bytes32(Keys.Amount)) | Exact64;
|
|
65
67
|
uint constant Balance = uint(bytes32(Keys.Balance)) | Exact64;
|
|
66
68
|
uint constant Allocation = uint(bytes32(Keys.Allocation)) | Exact96;
|
|
67
69
|
uint constant Allowance = uint(bytes32(Keys.Allowance)) | Exact96;
|
|
68
70
|
uint constant Custody = uint(bytes32(Keys.Custody)) | Exact96;
|
|
71
|
+
uint constant Position = uint(bytes32(Keys.Position)) | Exact128;
|
|
69
72
|
uint constant List = uint(bytes32(Keys.List)) | UnboundedHint128;
|
|
70
73
|
uint constant Evm = uint(bytes32(Keys.Evm)) | UnboundedHint128;
|
|
71
74
|
uint constant Bytes = uint(bytes32(Keys.Bytes)) | UnboundedHint128;
|
|
@@ -87,6 +90,7 @@ library Specs {
|
|
|
87
90
|
|
|
88
91
|
uint constant Status = uint(bytes32(Keys.Status)) | Exact32;
|
|
89
92
|
uint constant AccountAsset = uint(bytes32(Keys.AccountAsset)) | Exact64;
|
|
93
|
+
uint constant HostAsset = uint(bytes32(Keys.HostAsset)) | Exact64;
|
|
90
94
|
uint constant AccountAmount = uint(bytes32(Keys.AccountAmount)) | Exact96;
|
|
91
95
|
uint constant HostAmount = uint(bytes32(Keys.HostAmount)) | Exact96;
|
|
92
96
|
uint constant HostAccountAsset = uint(bytes32(Keys.HostAccountAsset)) | Exact96;
|
|
@@ -237,4 +241,5 @@ library Specs {
|
|
|
237
241
|
function group(uint spec, uint8 n) internal pure returns (uint) {
|
|
238
242
|
return replace8(spec, 128, n);
|
|
239
243
|
}
|
|
244
|
+
|
|
240
245
|
}
|
package/codec/Writers.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 {AssetAmount, AccountAmount, HostAmount, Tx} from "../core/Types.sol";
|
|
4
|
+
import {AssetAmount, AccountAmount, HostAmount, Position, Tx} from "../core/Types.sol";
|
|
5
5
|
import {Blocks} from "./Blocks.sol";
|
|
6
6
|
import {Buffers} from "./Buffers.sol";
|
|
7
7
|
import {Sizes, Specs} from "./Specs.sol";
|
|
@@ -44,7 +44,7 @@ library Writers {
|
|
|
44
44
|
(uint capacity, bool growable) = Specs.allocation(spec, groups);
|
|
45
45
|
if (capacity == 0) return writer;
|
|
46
46
|
|
|
47
|
-
writer.cur = Buffers.cursor(capacity, groups, growable, 0);
|
|
47
|
+
writer.cur = Buffers.cursor(capacity, Specs.count(spec, groups), growable, 0);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// -------------------------------------------------------------------------
|
|
@@ -204,6 +204,15 @@ library Writers {
|
|
|
204
204
|
Blocks.writeAccountAsset(writer.dst, i, account, asset);
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
/// @notice Append a HOST_ASSET block.
|
|
208
|
+
/// @param writer Destination writer.
|
|
209
|
+
/// @param host Host identifier to encode.
|
|
210
|
+
/// @param asset Asset identifier to encode.
|
|
211
|
+
function appendHostAsset(Writer memory writer, uint host, bytes32 asset) internal pure {
|
|
212
|
+
uint i = reserve(writer, Sizes.HostAsset);
|
|
213
|
+
Blocks.writeHostAsset(writer.dst, i, host, asset);
|
|
214
|
+
}
|
|
215
|
+
|
|
207
216
|
/// @notice Append an ALLOCATION block.
|
|
208
217
|
/// @param writer Destination writer.
|
|
209
218
|
/// @param host Host identifier to encode.
|
|
@@ -291,6 +300,23 @@ library Writers {
|
|
|
291
300
|
Blocks.writeHostAccountAsset(writer.dst, i, host, account, asset);
|
|
292
301
|
}
|
|
293
302
|
|
|
303
|
+
/// @notice Append a POSITION block.
|
|
304
|
+
function appendPosition(
|
|
305
|
+
Writer memory writer,
|
|
306
|
+
bytes32 asset,
|
|
307
|
+
uint amount,
|
|
308
|
+
bytes32 liability,
|
|
309
|
+
uint debt
|
|
310
|
+
) internal pure {
|
|
311
|
+
uint i = reserve(writer, Sizes.Position);
|
|
312
|
+
Blocks.writePosition(writer.dst, i, asset, amount, liability, debt);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/// @notice Append a structured POSITION value.
|
|
316
|
+
function appendPosition(Writer memory writer, Position memory value) internal pure {
|
|
317
|
+
appendPosition(writer, value.asset, value.amount, value.liability, value.debt);
|
|
318
|
+
}
|
|
319
|
+
|
|
294
320
|
/// @notice Append a TRANSACTION block.
|
|
295
321
|
/// @param writer Destination writer.
|
|
296
322
|
/// @param from Debit account identifier.
|
package/commands/Base.sol
CHANGED
|
@@ -5,7 +5,7 @@ import {CallerAccess} from "../core/Access.sol";
|
|
|
5
5
|
import {EndpointBase} from "../core/Endpoint.sol";
|
|
6
6
|
import {Blocks} from "../codec/Blocks.sol";
|
|
7
7
|
import {Specs} from "../codec/Specs.sol";
|
|
8
|
-
import {HostAmount} from "../core/Types.sol";
|
|
8
|
+
import {HostAmount, Position} from "../core/Types.sol";
|
|
9
9
|
import {Execution, Executions, Lanes} from "../execution/Execution.sol";
|
|
10
10
|
import {ReceivedEvent} from "../events/Received.sol";
|
|
11
11
|
import {Actions} from "../utils/Actions.sol";
|
|
@@ -22,6 +22,8 @@ using Executions for Execution;
|
|
|
22
22
|
abstract contract CommandBase is CallerAccess, EndpointBase, ReceivedEvent {
|
|
23
23
|
/// @dev Thrown when `onlyActive` finds that `deadline` has already passed.
|
|
24
24
|
error Expired();
|
|
25
|
+
/// @dev Thrown when a non-funded internal command receives native value.
|
|
26
|
+
error ValueNotAllowed();
|
|
25
27
|
|
|
26
28
|
/// @dev Restrict execution to trusted callers.
|
|
27
29
|
modifier onlyCommand() {
|
|
@@ -74,20 +76,11 @@ abstract contract CommandBase is CallerAccess, EndpointBase, ReceivedEvent {
|
|
|
74
76
|
published = endpoint(id, name, descriptor);
|
|
75
77
|
}
|
|
76
78
|
|
|
77
|
-
/// @notice Open
|
|
78
|
-
///
|
|
79
|
-
///
|
|
80
|
-
///
|
|
81
|
-
///
|
|
82
|
-
function openState(
|
|
83
|
-
bytes calldata source,
|
|
84
|
-
uint descriptor,
|
|
85
|
-
uint batches
|
|
86
|
-
) internal view returns (Execution memory exec) {
|
|
87
|
-
return Executions.openState(source, descriptor, batches);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/// @notice Open a command execution with batches derived from its input and state lanes.
|
|
79
|
+
/// @notice Open and validate both command lanes, including lanes declared EMPTY.
|
|
80
|
+
/// Batches are derived from the input and state lanes. A non-empty stream for
|
|
81
|
+
/// a lane whose descriptor has zero stride reverts instead of being ignored.
|
|
82
|
+
/// Commands must account for the complete validated state by consuming it,
|
|
83
|
+
/// transforming and returning it, forwarding it intact, or reverting.
|
|
91
84
|
/// @param state Current command state block stream.
|
|
92
85
|
/// @param input Command input block stream.
|
|
93
86
|
/// @param descriptor Packed command endpoint descriptor.
|
package/commands/Burn.sol
CHANGED
|
@@ -36,9 +36,9 @@ abstract contract Burn is CommandBase, BurnHook, Action {
|
|
|
36
36
|
function burn(
|
|
37
37
|
bytes32 account,
|
|
38
38
|
bytes calldata state,
|
|
39
|
-
bytes calldata
|
|
39
|
+
bytes calldata input
|
|
40
40
|
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
41
|
-
Execution memory exec =
|
|
41
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
42
42
|
|
|
43
43
|
while (exec.more()) {
|
|
44
44
|
(bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
|
package/commands/Credit.sol
CHANGED
|
@@ -3,12 +3,15 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
|
|
5
5
|
import {CreditAccountHook} from "../core/Settlement.sol";
|
|
6
|
+
import {Blocks} from "../codec/Blocks.sol";
|
|
7
|
+
import {Reader, Readers} from "../codec/Readers.sol";
|
|
6
8
|
|
|
7
9
|
using Executions for Execution;
|
|
10
|
+
using Readers for Reader;
|
|
8
11
|
|
|
9
12
|
/// @title CreditAccount
|
|
10
13
|
/// @notice Command that delivers BALANCE state blocks to an account via a virtual hook.
|
|
11
|
-
/// Use for internally recording credits that have already been
|
|
14
|
+
/// Use for internally recording credits that have already been posted externally.
|
|
12
15
|
abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
13
16
|
uint private immutable descriptor;
|
|
14
17
|
uint private immutable id;
|
|
@@ -29,9 +32,9 @@ abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
|
29
32
|
function creditAccount(
|
|
30
33
|
bytes32 account,
|
|
31
34
|
bytes calldata state,
|
|
32
|
-
bytes calldata
|
|
35
|
+
bytes calldata input
|
|
33
36
|
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
34
|
-
Execution memory exec =
|
|
37
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
35
38
|
|
|
36
39
|
while (exec.more()) {
|
|
37
40
|
(bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
|
|
@@ -41,3 +44,35 @@ abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
|
41
44
|
return close(exec, account);
|
|
42
45
|
}
|
|
43
46
|
}
|
|
47
|
+
|
|
48
|
+
/// @title InternalCreditAccount
|
|
49
|
+
/// @notice Extends the advertised credit-account command with memory-state pipeline dispatch.
|
|
50
|
+
/// @dev This adapter is not a separate command. It uses the command ID and account hook
|
|
51
|
+
/// inherited from `CreditAccount` while accepting the state location used by `Pipeline`.
|
|
52
|
+
abstract contract InternalCreditAccount is CreditAccount {
|
|
53
|
+
/// @notice Execute the inherited credit-account command from an internal pipeline.
|
|
54
|
+
/// @param account Account credited by each balance.
|
|
55
|
+
/// @param state BALANCE block stream held in pipeline memory.
|
|
56
|
+
/// @param input Empty input required by the command schema.
|
|
57
|
+
/// @param value Native value assigned to the command; must be zero.
|
|
58
|
+
/// @return output Empty output state.
|
|
59
|
+
/// @return transactions Empty transaction stream.
|
|
60
|
+
function executeCreditAccount(
|
|
61
|
+
bytes32 account,
|
|
62
|
+
bytes memory state,
|
|
63
|
+
bytes calldata input,
|
|
64
|
+
uint128 value
|
|
65
|
+
) internal returns (bytes memory, bytes memory) {
|
|
66
|
+
if (value != 0) revert ValueNotAllowed();
|
|
67
|
+
if (input.length != 0) revert Executions.ZeroStride();
|
|
68
|
+
if (state.length == 0) revert Blocks.EmptyRun();
|
|
69
|
+
|
|
70
|
+
Reader memory reader = Readers.open(state);
|
|
71
|
+
while (reader.more()) {
|
|
72
|
+
(bytes32 asset, uint amount) = reader.unpackBalance();
|
|
73
|
+
creditAccount(account, asset, amount);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return ("", "");
|
|
77
|
+
}
|
|
78
|
+
}
|
package/commands/Debit.sol
CHANGED
|
@@ -3,13 +3,18 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
|
|
5
5
|
import {DebitAccountHook} from "../core/Settlement.sol";
|
|
6
|
+
import {Blocks} from "../codec/Blocks.sol";
|
|
7
|
+
import {Sizes} from "../codec/Specs.sol";
|
|
8
|
+
import {Decoders} from "../codec/Decoders.sol";
|
|
9
|
+
import {Cur} from "../utils/Cursors.sol";
|
|
6
10
|
|
|
7
11
|
using Executions for Execution;
|
|
12
|
+
using Decoders for Cur;
|
|
8
13
|
|
|
9
14
|
/// @title DebitAccount
|
|
10
15
|
/// @notice Command that deducts AMOUNT blocks from an account and emits matching BALANCE state.
|
|
11
16
|
/// Use for internally recording debits. The virtual `debitAccount` hook is called once per
|
|
12
|
-
/// AMOUNT block
|
|
17
|
+
/// AMOUNT block.
|
|
13
18
|
abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
14
19
|
uint private immutable descriptor;
|
|
15
20
|
uint private immutable id;
|
|
@@ -23,11 +28,16 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
23
28
|
return id;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
|
-
/// @notice
|
|
27
|
-
///
|
|
28
|
-
///
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
/// @notice Debit AMOUNT input blocks from the command account and output matching BALANCE blocks.
|
|
32
|
+
/// @param input AMOUNT block stream.
|
|
33
|
+
/// @return BALANCE block stream matching the debited amounts.
|
|
34
|
+
/// @return Empty transaction stream.
|
|
35
|
+
function debitAccount(
|
|
36
|
+
bytes32 account,
|
|
37
|
+
bytes calldata state,
|
|
38
|
+
bytes calldata input
|
|
39
|
+
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
40
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
31
41
|
|
|
32
42
|
while (exec.more()) {
|
|
33
43
|
(bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
|
|
@@ -37,16 +47,42 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
37
47
|
|
|
38
48
|
return close(exec, account);
|
|
39
49
|
}
|
|
50
|
+
}
|
|
40
51
|
|
|
41
|
-
|
|
52
|
+
/// @title InternalDebitAccount
|
|
53
|
+
/// @notice Extends the advertised debit-account command with memory-state pipeline dispatch.
|
|
54
|
+
/// @dev This adapter is not a separate command. It uses the command ID and account hook
|
|
55
|
+
/// inherited from `DebitAccount` while accepting the state location used by `Pipeline`.
|
|
56
|
+
abstract contract InternalDebitAccount is DebitAccount {
|
|
57
|
+
/// @notice Execute the inherited debit-account command from an internal pipeline.
|
|
58
|
+
/// @param account Account whose funds are debited.
|
|
59
|
+
/// @param state Empty pipeline state required by the command schema.
|
|
42
60
|
/// @param input AMOUNT block stream.
|
|
43
|
-
/// @
|
|
44
|
-
/// @return
|
|
45
|
-
|
|
61
|
+
/// @param value Native value assigned to the command; must be zero.
|
|
62
|
+
/// @return output BALANCE block stream matching the debited amounts.
|
|
63
|
+
/// @return transactions Empty transaction stream.
|
|
64
|
+
function executeDebitAccount(
|
|
46
65
|
bytes32 account,
|
|
47
|
-
bytes
|
|
48
|
-
bytes calldata input
|
|
49
|
-
|
|
50
|
-
|
|
66
|
+
bytes memory state,
|
|
67
|
+
bytes calldata input,
|
|
68
|
+
uint128 value
|
|
69
|
+
) internal returns (bytes memory, bytes memory) {
|
|
70
|
+
if (value != 0) revert ValueNotAllowed();
|
|
71
|
+
if (state.length != 0) revert Executions.ZeroStride();
|
|
72
|
+
if (input.length == 0) revert Blocks.EmptyRun();
|
|
73
|
+
|
|
74
|
+
Cur memory cur = Decoders.wrap(input);
|
|
75
|
+
uint count = input.length / Sizes.Amount;
|
|
76
|
+
bytes memory output = new bytes(count * Sizes.Balance);
|
|
77
|
+
uint i;
|
|
78
|
+
|
|
79
|
+
while (cur.more()) {
|
|
80
|
+
(bytes32 asset, uint amount) = cur.unpackAmount();
|
|
81
|
+
debitAccount(account, asset, amount);
|
|
82
|
+
Blocks.writeBalance(output, i, asset, amount);
|
|
83
|
+
i += Sizes.Balance;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return (output, "");
|
|
51
87
|
}
|
|
52
88
|
}
|
package/commands/Deposit.sol
CHANGED
|
@@ -49,10 +49,10 @@ abstract contract Deposit is CommandBase, DepositHook, Action {
|
|
|
49
49
|
/// @return Empty transaction stream.
|
|
50
50
|
function deposit(
|
|
51
51
|
bytes32 account,
|
|
52
|
-
bytes calldata,
|
|
52
|
+
bytes calldata state,
|
|
53
53
|
bytes calldata input
|
|
54
54
|
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
55
|
-
Execution memory exec =
|
|
55
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
56
56
|
|
|
57
57
|
while (exec.more()) {
|
|
58
58
|
(bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
|
|
@@ -82,10 +82,10 @@ abstract contract DepositPayable is CommandBase, DepositPayableHook, Action {
|
|
|
82
82
|
/// @return Remaining native value as a refund transaction stream.
|
|
83
83
|
function depositPayable(
|
|
84
84
|
bytes32 account,
|
|
85
|
-
bytes calldata,
|
|
85
|
+
bytes calldata state,
|
|
86
86
|
bytes calldata input
|
|
87
87
|
) external payable onlyCommand returns (bytes memory, bytes memory) {
|
|
88
|
-
Execution memory exec =
|
|
88
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
89
89
|
|
|
90
90
|
while (exec.more()) {
|
|
91
91
|
(bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
|
package/commands/Provision.sol
CHANGED
|
@@ -41,10 +41,10 @@ abstract contract Provision is CommandBase, ProvisionHook {
|
|
|
41
41
|
/// @return Empty transaction stream.
|
|
42
42
|
function provision(
|
|
43
43
|
bytes32 account,
|
|
44
|
-
bytes calldata,
|
|
44
|
+
bytes calldata state,
|
|
45
45
|
bytes calldata input
|
|
46
46
|
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
47
|
-
Execution memory exec =
|
|
47
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
48
48
|
|
|
49
49
|
while (exec.more()) {
|
|
50
50
|
HostAmount memory allocation = exec.unpackAllocationValue(Lanes.Input);
|
|
@@ -73,10 +73,10 @@ abstract contract ProvisionPayable is CommandBase, ProvisionPayableHook {
|
|
|
73
73
|
/// @return Remaining native value as a refund transaction stream.
|
|
74
74
|
function provisionPayable(
|
|
75
75
|
bytes32 account,
|
|
76
|
-
bytes calldata,
|
|
76
|
+
bytes calldata state,
|
|
77
77
|
bytes calldata input
|
|
78
78
|
) external payable onlyCommand returns (bytes memory, bytes memory) {
|
|
79
|
-
Execution memory exec =
|
|
79
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
80
80
|
|
|
81
81
|
while (exec.more()) {
|
|
82
82
|
HostAmount memory allocation = exec.unpackAllocationValue(Lanes.Input);
|
package/commands/Recover.sol
CHANGED
|
@@ -6,21 +6,28 @@ import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
|
|
|
6
6
|
using Executions for Execution;
|
|
7
7
|
|
|
8
8
|
/// @notice Hook implemented by hosts that recover previously undelivered payloads.
|
|
9
|
-
abstract contract
|
|
9
|
+
abstract contract RecoverPayableHook {
|
|
10
10
|
/// @notice Override to recover a witness through `handler`.
|
|
11
11
|
/// @param handler Port that should attempt recovery.
|
|
12
|
+
/// @param resources Chain-specific resources assigned to the recovery attempt.
|
|
12
13
|
/// @param key Recovery lookup key.
|
|
13
14
|
/// @param witness Witness payload used to prove and replay recovery.
|
|
14
|
-
/// @param
|
|
15
|
-
function recover(
|
|
15
|
+
/// @param funds Shared execution containing the source value budget.
|
|
16
|
+
function recover(
|
|
17
|
+
uint handler,
|
|
18
|
+
uint resources,
|
|
19
|
+
bytes32 key,
|
|
20
|
+
bytes calldata witness,
|
|
21
|
+
Execution memory funds
|
|
22
|
+
) internal virtual;
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
/// @title RecoverPayable
|
|
19
26
|
/// @notice Command that forwards recover input blocks to a virtual hook.
|
|
20
27
|
/// Recovery is witness-driven: the command account pays and receives leftover
|
|
21
|
-
/// value
|
|
28
|
+
/// value posting, but the recovered subject is defined by each witness.
|
|
22
29
|
/// Produces no output state.
|
|
23
|
-
abstract contract RecoverPayable is CommandBase,
|
|
30
|
+
abstract contract RecoverPayable is CommandBase, RecoverPayableHook {
|
|
24
31
|
uint private immutable descriptor;
|
|
25
32
|
|
|
26
33
|
constructor() {
|
|
@@ -33,14 +40,14 @@ abstract contract RecoverPayable is CommandBase, RecoverHook {
|
|
|
33
40
|
/// @return Remaining native value as a refund transaction stream.
|
|
34
41
|
function recoverPayable(
|
|
35
42
|
bytes32 account,
|
|
36
|
-
bytes calldata,
|
|
43
|
+
bytes calldata state,
|
|
37
44
|
bytes calldata input
|
|
38
45
|
) external payable onlyCommand returns (bytes memory, bytes memory) {
|
|
39
|
-
Execution memory exec =
|
|
46
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
40
47
|
|
|
41
48
|
while (exec.more()) {
|
|
42
49
|
(uint handler, uint resources, bytes32 key, bytes calldata witness) = exec.unpackRecover(Lanes.Input);
|
|
43
|
-
recover(handler, key, witness, exec
|
|
50
|
+
recover(handler, resources, key, witness, exec);
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
return close(exec, account);
|