@rootzero/contracts 0.9.7 → 0.9.9
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/Core.sol +3 -3
- package/Endpoints.sol +1 -1
- package/Events.sol +4 -3
- package/Utils.sol +2 -1
- package/blocks/Cursors.sol +117 -155
- package/blocks/Keys.sol +4 -6
- package/blocks/Schema.sol +14 -8
- package/commands/Burn.sol +4 -4
- package/commands/Credit.sol +6 -9
- package/commands/Debit.sol +4 -4
- package/commands/Deposit.sol +8 -8
- package/commands/Payout.sol +45 -0
- package/commands/Provision.sol +8 -8
- package/commands/Withdraw.sol +7 -9
- package/commands/admin/AllowAssets.sol +4 -4
- package/commands/admin/Allowance.sol +4 -4
- package/commands/admin/Appoint.sol +4 -4
- package/commands/admin/Authorize.sol +4 -4
- package/commands/admin/DenyAssets.sol +4 -4
- package/commands/admin/Destroy.sol +2 -2
- package/commands/admin/Dismiss.sol +4 -4
- package/commands/admin/Execute.sol +4 -4
- package/commands/admin/Init.sol +2 -2
- package/commands/admin/Unauthorize.sol +4 -4
- package/core/Access.sol +2 -2
- package/core/Host.sol +4 -2
- package/core/Pipeline.sol +3 -3
- package/core/Runtime.sol +14 -0
- package/core/Types.sol +1 -1
- package/docs/Schema.md +0 -1
- package/events/Admin.sol +10 -7
- package/events/Command.sol +10 -7
- package/events/Locked.sol +21 -0
- package/events/Peer.sol +5 -5
- package/events/Position.sol +4 -2
- package/events/Query.sol +2 -4
- package/events/Received.sol +4 -3
- package/events/Spent.sol +4 -3
- package/events/Transfer.sol +22 -0
- package/events/Unlocked.sol +21 -0
- package/guards/Revoke.sol +3 -3
- package/package.json +1 -1
- package/peer/AllowAssets.sol +3 -3
- package/peer/Allowance.sol +3 -3
- package/peer/BalancePull.sol +3 -3
- package/peer/DenyAssets.sol +3 -3
- package/peer/Pipe.sol +3 -3
- package/peer/Settle.sol +11 -8
- package/queries/Assets.sol +3 -3
- package/queries/Balances.sol +3 -3
- package/queries/Base.sol +2 -2
- package/queries/Positions.sol +3 -3
- package/utils/Accounts.sol +8 -0
- package/utils/Actions.sol +18 -0
- package/commands/Transfer.sol +0 -54
- package/core/Context.sol +0 -47
- package/events/Collateral.sol +0 -24
- package/events/Contexts.sol +0 -12
- package/events/Debt.sol +0 -25
package/Core.sol
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
// Aggregator: re-exports the core host,
|
|
4
|
+
// Aggregator: re-exports the core host, runtime, access, node-call, and validation layer.
|
|
5
5
|
// Import this file to bring the full rootzero host base layer into scope.
|
|
6
6
|
|
|
7
7
|
import { AccessControl } from "./core/Access.sol";
|
|
8
|
-
import { Balances } from "./core/Balances.sol";
|
|
9
|
-
import {
|
|
8
|
+
import { Balances, InsufficientFunds } from "./core/Balances.sol";
|
|
9
|
+
import { Runtime } from "./core/Runtime.sol";
|
|
10
10
|
import { Host, IHostIntroduction } from "./core/Host.sol";
|
|
11
11
|
import { FailedCall, NodeCalls } from "./core/Calls.sol";
|
|
12
12
|
import { Payable } from "./core/Payable.sol";
|
package/Endpoints.sol
CHANGED
|
@@ -14,8 +14,8 @@ import { Burn, BurnHook } from "./commands/Burn.sol";
|
|
|
14
14
|
import { CreditAccount, CreditAccountHook } from "./commands/Credit.sol";
|
|
15
15
|
import { DebitAccount, DebitAccountHook } from "./commands/Debit.sol";
|
|
16
16
|
import { Deposit, DepositHook, DepositPayable, DepositPayableHook } from "./commands/Deposit.sol";
|
|
17
|
+
import { Payout, PayoutHook } from "./commands/Payout.sol";
|
|
17
18
|
import { Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook } from "./commands/Provision.sol";
|
|
18
|
-
import { Transfer, TransferHook } from "./commands/Transfer.sol";
|
|
19
19
|
import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
|
|
20
20
|
|
|
21
21
|
// Admin commands
|
package/Events.sol
CHANGED
|
@@ -6,22 +6,23 @@ pragma solidity ^0.8.33;
|
|
|
6
6
|
|
|
7
7
|
import { AdminEvent } from "./events/Admin.sol";
|
|
8
8
|
import { AssetStatusEvent } from "./events/Asset.sol";
|
|
9
|
+
import { Actions } from "./utils/Actions.sol";
|
|
9
10
|
import { BalanceEvent } from "./events/Balance.sol";
|
|
10
|
-
import { CollateralEvent } from "./events/Collateral.sol";
|
|
11
11
|
import { CommandEvent } from "./events/Command.sol";
|
|
12
|
-
import { Contexts } from "./events/Contexts.sol";
|
|
13
|
-
import { DebtEvent } from "./events/Debt.sol";
|
|
14
12
|
import { PositionEvent } from "./events/Position.sol";
|
|
15
13
|
import { ReceivedEvent } from "./events/Received.sol";
|
|
16
14
|
import { EventEmitter } from "./events/Emitter.sol";
|
|
17
15
|
import { GuardEvent } from "./events/Guard.sol";
|
|
18
16
|
import { GuardianEvent } from "./events/Guardian.sol";
|
|
19
17
|
import { IntroductionEvent } from "./events/Introduction.sol";
|
|
18
|
+
import { LockedEvent } from "./events/Locked.sol";
|
|
20
19
|
import { NodeEvent } from "./events/Node.sol";
|
|
21
20
|
import { PeerEvent } from "./events/Peer.sol";
|
|
22
21
|
import { QueryEvent } from "./events/Query.sol";
|
|
23
22
|
import { RootedEvent } from "./events/Rooted.sol";
|
|
24
23
|
import { SpentEvent } from "./events/Spent.sol";
|
|
24
|
+
import { TransferEvent } from "./events/Transfer.sol";
|
|
25
|
+
import { UnlockedEvent } from "./events/Unlocked.sol";
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
|
package/Utils.sol
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
// Aggregator: re-exports all utility libraries (Keys, Accounts, Assets, ECDSA, Ids, Layout, Utils, Value).
|
|
4
|
+
// Aggregator: re-exports all utility libraries (Keys, Accounts, Actions, Assets, ECDSA, Ids, Layout, Utils, Value).
|
|
5
5
|
// Import this file to access the full utility surface without managing individual paths.
|
|
6
6
|
|
|
7
7
|
import { Keys } from "./blocks/Keys.sol";
|
|
8
8
|
import { Accounts } from "./utils/Accounts.sol";
|
|
9
|
+
import { Actions } from "./utils/Actions.sol";
|
|
9
10
|
import { Amounts, Assets } from "./utils/Assets.sol";
|
|
10
11
|
import { ECDSA } from "./utils/ECDSA.sol";
|
|
11
12
|
import { Ids, Selectors } from "./utils/Ids.sol";
|
package/blocks/Cursors.sol
CHANGED
|
@@ -6,7 +6,7 @@ import {Sizes} from "./Schema.sol";
|
|
|
6
6
|
import {Keys} from "./Keys.sol";
|
|
7
7
|
|
|
8
8
|
/// @notice Zero-copy view into a calldata block stream.
|
|
9
|
-
/// All positions (`i
|
|
9
|
+
/// All positions (`i`) are byte offsets relative to the start of the source region.
|
|
10
10
|
/// The absolute calldata location of byte `i` is `offset + i`.
|
|
11
11
|
struct Cur {
|
|
12
12
|
/// @dev Absolute calldata byte offset of the source region start.
|
|
@@ -15,9 +15,6 @@ struct Cur {
|
|
|
15
15
|
uint i;
|
|
16
16
|
/// @dev Total byte length of the source region.
|
|
17
17
|
uint len;
|
|
18
|
-
/// @dev Exclusive upper bound for the current iteration group, set by `primeRun`.
|
|
19
|
-
/// Zero until `primeRun` is called.
|
|
20
|
-
uint bound;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
20
|
using Cursors for Cur;
|
|
@@ -32,11 +29,11 @@ library Cursors {
|
|
|
32
29
|
error MalformedBlocks();
|
|
33
30
|
/// @dev Current block key does not match the expected key, or payload size is out of range.
|
|
34
31
|
error InvalidBlock();
|
|
35
|
-
/// @dev `complete` called but the cursor has not consumed exactly
|
|
32
|
+
/// @dev `complete` called but the cursor has not consumed exactly to `len`.
|
|
36
33
|
error IncompleteCursor();
|
|
37
|
-
/// @dev `
|
|
34
|
+
/// @dev `run` found zero blocks of the expected key; the cursor region is empty.
|
|
38
35
|
error ZeroCursor();
|
|
39
|
-
/// @dev `
|
|
36
|
+
/// @dev `run` was called with a zero group size.
|
|
40
37
|
error ZeroGroup();
|
|
41
38
|
/// @dev An account field was required but the block or fallback was zero.
|
|
42
39
|
error ZeroAccount();
|
|
@@ -65,15 +62,70 @@ library Cursors {
|
|
|
65
62
|
cur.len = source.length;
|
|
66
63
|
}
|
|
67
64
|
|
|
68
|
-
/// @notice Create a cursor
|
|
69
|
-
///
|
|
65
|
+
/// @notice Create a cursor backed by `source[i:]`.
|
|
66
|
+
/// @param source Calldata slice that forms the parent block stream.
|
|
67
|
+
/// @param i Start byte offset within `source`.
|
|
68
|
+
/// @return cur Cursor positioned at the beginning of `source[i:]`.
|
|
69
|
+
function open(bytes calldata source, uint i) internal pure returns (Cur memory cur) {
|
|
70
|
+
return open(source[i:]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// @notice Create a cursor over `source[i:]` and restrict it to its first grouped run.
|
|
74
|
+
/// Equivalent to `open(source, i)`, reading the current key, then `run(key, group)`.
|
|
75
|
+
/// @param source Calldata slice that forms the parent block stream.
|
|
76
|
+
/// @param i Start byte offset within `source`.
|
|
77
|
+
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
78
|
+
/// @return cur Cursor with `len` truncated to the end of the first run in `source[i:]`.
|
|
79
|
+
/// @return groups Number of block groups in the run (`block count / group`).
|
|
80
|
+
/// @return next Byte offset immediately after the run, relative to `source`.
|
|
81
|
+
function init(
|
|
82
|
+
bytes calldata source,
|
|
83
|
+
uint i,
|
|
84
|
+
uint group
|
|
85
|
+
) internal pure returns (Cur memory cur, uint groups, uint next) {
|
|
86
|
+
cur = open(source, i);
|
|
87
|
+
if (cur.i == cur.len) revert ZeroCursor();
|
|
88
|
+
(bytes4 key, ) = cur.peek(cur.i);
|
|
89
|
+
groups = cur.run(key, group);
|
|
90
|
+
next = i + cur.len;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// @notice Create a cursor over `source[i:]`, restrict it to its first grouped run, and require an exact group count.
|
|
94
|
+
/// @param source Calldata slice that forms the parent block stream.
|
|
95
|
+
/// @param i Start byte offset within `source`.
|
|
96
|
+
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
97
|
+
/// @param expectedGroups Required number of groups in the run.
|
|
98
|
+
/// @return cur Cursor with `len` truncated to the end of the first run in `source[i:]`.
|
|
99
|
+
/// @return next Byte offset immediately after the run, relative to `source`.
|
|
100
|
+
function init(
|
|
101
|
+
bytes calldata source,
|
|
102
|
+
uint i,
|
|
103
|
+
uint group,
|
|
104
|
+
uint expectedGroups
|
|
105
|
+
) internal pure returns (Cur memory cur, uint next) {
|
|
106
|
+
uint groups;
|
|
107
|
+
(cur, groups, next) = init(source, i, group);
|
|
108
|
+
if (groups != expectedGroups) revert BadRatio();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// @notice Create a cursor over the first grouped run in `source`.
|
|
112
|
+
/// Equivalent to `init(source, 0, group)` without returning the next offset.
|
|
113
|
+
/// @param source Calldata slice that forms the block stream.
|
|
114
|
+
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
115
|
+
/// @return cur Cursor with `len` truncated to the end of the first run.
|
|
116
|
+
/// @return groups Number of block groups in the run (`block count / group`).
|
|
117
|
+
function first(bytes calldata source, uint group) internal pure returns (Cur memory cur, uint groups) {
|
|
118
|
+
(cur, groups, ) = init(source, 0, group);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/// @notice Create a cursor over the first grouped run in `source` and require an exact group count.
|
|
122
|
+
/// Equivalent to `init(source, 0, group, expectedGroups)` without returning the next offset.
|
|
70
123
|
/// @param source Calldata slice that forms the block stream.
|
|
71
124
|
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
72
|
-
/// @
|
|
73
|
-
/// @return
|
|
74
|
-
function
|
|
75
|
-
cur =
|
|
76
|
-
(, groups) = cur.primeRun(group);
|
|
125
|
+
/// @param expectedGroups Required number of groups in the run.
|
|
126
|
+
/// @return cur Cursor with `len` truncated to the end of the first run.
|
|
127
|
+
function first(bytes calldata source, uint group, uint expectedGroups) internal pure returns (Cur memory cur) {
|
|
128
|
+
(cur, ) = init(source, 0, group, expectedGroups);
|
|
77
129
|
}
|
|
78
130
|
|
|
79
131
|
/// @notice Move the cursor to an absolute position within the source region.
|
|
@@ -119,7 +171,7 @@ library Cursors {
|
|
|
119
171
|
}
|
|
120
172
|
|
|
121
173
|
/// @notice Return the full cursor region as a calldata slice.
|
|
122
|
-
/// Does not advance the cursor; `cur.i`
|
|
174
|
+
/// Does not advance the cursor; `cur.i` is ignored.
|
|
123
175
|
/// @param cur Cursor whose backing region should be returned.
|
|
124
176
|
/// @return data Calldata view over `[cur.offset, cur.offset + cur.len)`.
|
|
125
177
|
function raw(Cur memory cur) internal pure returns (bytes calldata data) {
|
|
@@ -128,7 +180,7 @@ library Cursors {
|
|
|
128
180
|
}
|
|
129
181
|
|
|
130
182
|
/// @notice Return a sub-range of the cursor region as a calldata slice.
|
|
131
|
-
/// Does not advance the cursor; `cur.i`
|
|
183
|
+
/// Does not advance the cursor; `cur.i` is ignored.
|
|
132
184
|
/// @param cur Source cursor.
|
|
133
185
|
/// @param from Start byte offset within the source region (inclusive).
|
|
134
186
|
/// @param to End byte offset within the source region (exclusive).
|
|
@@ -267,21 +319,19 @@ library Cursors {
|
|
|
267
319
|
}
|
|
268
320
|
}
|
|
269
321
|
|
|
270
|
-
/// @notice
|
|
271
|
-
///
|
|
272
|
-
///
|
|
273
|
-
///
|
|
274
|
-
/// @param
|
|
322
|
+
/// @notice Restrict the cursor to the consecutive run of `key` at its current position.
|
|
323
|
+
/// Counts the run, truncates `cur.len` to the run end, and validates that the
|
|
324
|
+
/// count is a multiple of `group`.
|
|
325
|
+
/// @param cur Cursor to restrict; `cur.len` is updated in place.
|
|
326
|
+
/// @param key Expected block type identifier of the run.
|
|
275
327
|
/// @param group Expected group size (e.g. 1 for single-asset, 2 for paired input/output).
|
|
276
|
-
/// @return key Block type identifier of the run.
|
|
277
328
|
/// @return groups Number of groups represented by the run (`block count / group`).
|
|
278
|
-
function
|
|
329
|
+
function run(Cur memory cur, bytes4 key, uint group) internal pure returns (uint groups) {
|
|
279
330
|
if (group == 0) revert ZeroGroup();
|
|
280
|
-
|
|
281
|
-
uint count;
|
|
282
|
-
(count, cur.bound) = countRun(cur, cur.i, key);
|
|
331
|
+
(uint count, uint next) = countRun(cur, cur.i, key);
|
|
283
332
|
if (count == 0) revert ZeroCursor();
|
|
284
333
|
if (count % group != 0) revert BadRatio();
|
|
334
|
+
cur.len = next;
|
|
285
335
|
groups = count / group;
|
|
286
336
|
}
|
|
287
337
|
|
|
@@ -361,17 +411,6 @@ library Cursors {
|
|
|
361
411
|
return maybeTake(cur, Keys.Data);
|
|
362
412
|
}
|
|
363
413
|
|
|
364
|
-
/// @notice Enter a List block, prime its member run, and return the group count.
|
|
365
|
-
/// @param cur Cursor positioned at a list block; advanced past the 8-byte header.
|
|
366
|
-
/// @param group Expected block group size for the list item stream.
|
|
367
|
-
/// @return groups Number of block groups in the list payload.
|
|
368
|
-
/// @return next Byte offset immediately after the list payload.
|
|
369
|
-
function list(Cur memory cur, uint group) internal pure returns (uint groups, uint next) {
|
|
370
|
-
next = list(cur);
|
|
371
|
-
(, groups) = cur.primeRun(group);
|
|
372
|
-
if (cur.bound != next) revert IncompleteCursor();
|
|
373
|
-
}
|
|
374
|
-
|
|
375
414
|
/// @notice Exit a nested region at an exact boundary.
|
|
376
415
|
/// Reverts with `IncompleteCursor` if `end` exceeds the cursor region length
|
|
377
416
|
/// or `cur.i != end`.
|
|
@@ -381,13 +420,6 @@ library Cursors {
|
|
|
381
420
|
if (end > cur.len || cur.i != end) revert IncompleteCursor();
|
|
382
421
|
}
|
|
383
422
|
|
|
384
|
-
/// @notice Assert that the cursor has consumed exactly up to `bound`.
|
|
385
|
-
/// Reverts with `IncompleteCursor` if `bound` is zero or `cur.i != cur.bound`.
|
|
386
|
-
/// @param cur Cursor to check.
|
|
387
|
-
function close(Cur memory cur) internal pure {
|
|
388
|
-
if (cur.bound == 0 || cur.i != cur.bound) revert IncompleteCursor();
|
|
389
|
-
}
|
|
390
|
-
|
|
391
423
|
/// @notice Assert that the cursor has consumed its entire source region.
|
|
392
424
|
/// Reverts with `IncompleteCursor` when `cur.i != cur.len`.
|
|
393
425
|
/// @param cur Cursor to check.
|
|
@@ -527,7 +559,11 @@ library Cursors {
|
|
|
527
559
|
/// @param state Embedded state block stream.
|
|
528
560
|
/// @param request Embedded request block stream.
|
|
529
561
|
/// @return Encoded CONTEXT block bytes.
|
|
530
|
-
function toContextBlock(
|
|
562
|
+
function toContextBlock(
|
|
563
|
+
bytes32 account,
|
|
564
|
+
bytes memory state,
|
|
565
|
+
bytes memory request
|
|
566
|
+
) internal pure returns (bytes memory) {
|
|
531
567
|
return createBlock(Keys.Context, bytes.concat(account, toBytesBlock(state), toBytesBlock(request)));
|
|
532
568
|
}
|
|
533
569
|
|
|
@@ -902,38 +938,6 @@ library Cursors {
|
|
|
902
938
|
(value.asset, value.meta, value.amount) = unpackAssetAmount(cur, Keys.Balance);
|
|
903
939
|
}
|
|
904
940
|
|
|
905
|
-
/// @notice Consume a MINIMUM block and return its fields as separate values.
|
|
906
|
-
/// @param cur Cursor; advanced past the block.
|
|
907
|
-
/// @return asset Asset identifier.
|
|
908
|
-
/// @return meta Asset metadata slot.
|
|
909
|
-
/// @return amount Minimum acceptable amount.
|
|
910
|
-
function unpackMinimum(Cur memory cur) internal pure returns (bytes32 asset, bytes32 meta, uint amount) {
|
|
911
|
-
return unpackAssetAmount(cur, Keys.Minimum);
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
/// @notice Consume a MINIMUM block and return its fields as a struct.
|
|
915
|
-
/// @param cur Cursor; advanced past the block.
|
|
916
|
-
/// @return value Decoded asset, meta, and minimum amount.
|
|
917
|
-
function unpackMinimumValue(Cur memory cur) internal pure returns (AssetAmount memory value) {
|
|
918
|
-
(value.asset, value.meta, value.amount) = unpackAssetAmount(cur, Keys.Minimum);
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
/// @notice Consume a MAXIMUM block and return its fields as separate values.
|
|
922
|
-
/// @param cur Cursor; advanced past the block.
|
|
923
|
-
/// @return asset Asset identifier.
|
|
924
|
-
/// @return meta Asset metadata slot.
|
|
925
|
-
/// @return amount Maximum allowable spend.
|
|
926
|
-
function unpackMaximum(Cur memory cur) internal pure returns (bytes32 asset, bytes32 meta, uint amount) {
|
|
927
|
-
return unpackAssetAmount(cur, Keys.Maximum);
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
/// @notice Consume a MAXIMUM block and return its fields as a struct.
|
|
931
|
-
/// @param cur Cursor; advanced past the block.
|
|
932
|
-
/// @return value Decoded asset, meta, and maximum amount.
|
|
933
|
-
function unpackMaximumValue(Cur memory cur) internal pure returns (AssetAmount memory value) {
|
|
934
|
-
(value.asset, value.meta, value.amount) = unpackAssetAmount(cur, Keys.Maximum);
|
|
935
|
-
}
|
|
936
|
-
|
|
937
941
|
/// @notice Consume a HOST_ACCOUNT_ASSET form block and return its fields as separate values.
|
|
938
942
|
/// @param cur Cursor; advanced past the block.
|
|
939
943
|
/// @return host Host node ID.
|
|
@@ -953,25 +957,6 @@ library Cursors {
|
|
|
953
957
|
(value.host, value.account, value.asset, value.meta) = unpackHostAccountAsset(cur, Keys.HostAccountAsset);
|
|
954
958
|
}
|
|
955
959
|
|
|
956
|
-
/// @notice Consume a PAYOUT block and return its fields as separate values.
|
|
957
|
-
/// @param cur Cursor; advanced past the block.
|
|
958
|
-
/// @return account Account identifier.
|
|
959
|
-
/// @return asset Asset identifier.
|
|
960
|
-
/// @return meta Asset metadata slot.
|
|
961
|
-
/// @return amount Token amount.
|
|
962
|
-
function unpackPayout(
|
|
963
|
-
Cur memory cur
|
|
964
|
-
) internal pure returns (bytes32 account, bytes32 asset, bytes32 meta, uint amount) {
|
|
965
|
-
return unpackAccountAmount(cur, Keys.Payout);
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
/// @notice Consume a PAYOUT block and return its fields as a struct.
|
|
969
|
-
/// @param cur Cursor; advanced past the block.
|
|
970
|
-
/// @return value Decoded account, asset, meta, and amount.
|
|
971
|
-
function unpackPayoutValue(Cur memory cur) internal pure returns (AccountAmount memory value) {
|
|
972
|
-
(value.account, value.asset, value.meta, value.amount) = unpackAccountAmount(cur, Keys.Payout);
|
|
973
|
-
}
|
|
974
|
-
|
|
975
960
|
/// @notice Consume an ACCOUNT_AMOUNT form block and return its fields as separate values.
|
|
976
961
|
/// @param cur Cursor; advanced past the block.
|
|
977
962
|
/// @return account Account identifier.
|
|
@@ -1102,7 +1087,9 @@ library Cursors {
|
|
|
1102
1087
|
/// @return account Command account identifier.
|
|
1103
1088
|
/// @return state Embedded state block stream.
|
|
1104
1089
|
/// @return request Embedded request block stream.
|
|
1105
|
-
function unpackContext(
|
|
1090
|
+
function unpackContext(
|
|
1091
|
+
Cur memory cur
|
|
1092
|
+
) internal pure returns (bytes32 account, bytes calldata state, bytes calldata request) {
|
|
1106
1093
|
uint end = cur.enter(Keys.Context, 32 + 2 * Sizes.Header, 0);
|
|
1107
1094
|
account = cur.read32();
|
|
1108
1095
|
state = cur.unpackBytes();
|
|
@@ -1194,15 +1181,6 @@ library Cursors {
|
|
|
1194
1181
|
if (uint(bytes32(msg.data[abs + 64:abs + 96])) != 1) revert UnexpectedValue();
|
|
1195
1182
|
}
|
|
1196
1183
|
|
|
1197
|
-
/// @notice Consume a MINIMUM block and assert it matches the expected asset and meta.
|
|
1198
|
-
/// @param cur Cursor; advanced past the block.
|
|
1199
|
-
/// @param asset Expected asset identifier.
|
|
1200
|
-
/// @param meta Expected metadata slot.
|
|
1201
|
-
/// @return amount Minimum amount from the block.
|
|
1202
|
-
function requireMinimum(Cur memory cur, bytes32 asset, bytes32 meta) internal pure returns (uint amount) {
|
|
1203
|
-
return requireAssetAmount(cur, Keys.Minimum, asset, meta);
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
1184
|
/// @notice Consume a host amount block and assert it matches the expected host.
|
|
1207
1185
|
/// @param cur Cursor; advanced past the block.
|
|
1208
1186
|
/// @param key Expected block type key.
|
|
@@ -1324,7 +1302,39 @@ library Cursors {
|
|
|
1324
1302
|
}
|
|
1325
1303
|
|
|
1326
1304
|
// -------------------------------------------------------------------------
|
|
1327
|
-
//
|
|
1305
|
+
// ensure* - validate constraint blocks against provided values
|
|
1306
|
+
// -------------------------------------------------------------------------
|
|
1307
|
+
|
|
1308
|
+
/// @notice Consume a BALANCE_LIMIT block and assert all constraint fields match the provided balance.
|
|
1309
|
+
/// @param cur Cursor; advanced past the block.
|
|
1310
|
+
/// @param asset Expected asset identifier.
|
|
1311
|
+
/// @param meta Expected metadata slot.
|
|
1312
|
+
/// @param amount Amount that must fall within the encoded min/max range.
|
|
1313
|
+
function ensureBalanceLimit(Cur memory cur, bytes32 asset, bytes32 meta, uint amount) internal pure {
|
|
1314
|
+
uint abs = consume(cur, 0, Keys.BalanceLimit, 128, 128);
|
|
1315
|
+
if (bytes32(msg.data[abs:abs + 32]) != asset) revert UnexpectedValue();
|
|
1316
|
+
if (bytes32(msg.data[abs + 32:abs + 64]) != meta) revert UnexpectedValue();
|
|
1317
|
+
if (uint(bytes32(msg.data[abs + 64:abs + 96])) > amount) revert UnexpectedValue();
|
|
1318
|
+
if (uint(bytes32(msg.data[abs + 96:abs + 128])) < amount) revert UnexpectedValue();
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
/// @notice Consume a CUSTODY_LIMIT block and assert all constraint fields match the provided custody.
|
|
1322
|
+
/// @param cur Cursor; advanced past the block.
|
|
1323
|
+
/// @param host Expected host node ID.
|
|
1324
|
+
/// @param asset Expected asset identifier.
|
|
1325
|
+
/// @param meta Expected metadata slot.
|
|
1326
|
+
/// @param amount Amount that must fall within the encoded min/max range.
|
|
1327
|
+
function ensureCustodyLimit(Cur memory cur, uint host, bytes32 asset, bytes32 meta, uint amount) internal pure {
|
|
1328
|
+
uint abs = consume(cur, 0, Keys.CustodyLimit, 160, 160);
|
|
1329
|
+
if (uint(bytes32(msg.data[abs:abs + 32])) != host) revert UnexpectedValue();
|
|
1330
|
+
if (bytes32(msg.data[abs + 32:abs + 64]) != asset) revert UnexpectedValue();
|
|
1331
|
+
if (bytes32(msg.data[abs + 64:abs + 96]) != meta) revert UnexpectedValue();
|
|
1332
|
+
if (uint(bytes32(msg.data[abs + 96:abs + 128])) > amount) revert UnexpectedValue();
|
|
1333
|
+
if (uint(bytes32(msg.data[abs + 128:abs + 160])) < amount) revert UnexpectedValue();
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
// -------------------------------------------------------------------------
|
|
1337
|
+
// Search helpers
|
|
1328
1338
|
// -------------------------------------------------------------------------
|
|
1329
1339
|
|
|
1330
1340
|
/// @notice Look for a NODE block anywhere in a calldata source and return its value.
|
|
@@ -1364,52 +1374,4 @@ library Cursors {
|
|
|
1364
1374
|
(uint abs, ) = expect(cur, i, 0, Keys.Account, 32, 32);
|
|
1365
1375
|
return bytes32(msg.data[abs:abs + 32]);
|
|
1366
1376
|
}
|
|
1367
|
-
|
|
1368
|
-
/// @notice Look for a NODE block after the current run boundary and return its value.
|
|
1369
|
-
/// Searches from `cur.bound` to the end of the source region.
|
|
1370
|
-
/// @param cur Source cursor; `bound` marks the end of the primary run.
|
|
1371
|
-
/// @param backup Value to return if no NODE block is found.
|
|
1372
|
-
/// @return node Node ID from the NODE block, or `backup` if absent.
|
|
1373
|
-
function nodeAfter(Cur memory cur, uint backup) internal pure returns (uint node) {
|
|
1374
|
-
uint i = find(cur, cur.bound, Keys.Node);
|
|
1375
|
-
if (i == cur.len) return backup;
|
|
1376
|
-
|
|
1377
|
-
(uint abs, ) = expect(cur, i, 0, Keys.Node, 32, 32);
|
|
1378
|
-
return uint(bytes32(msg.data[abs:abs + 32]));
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
/// @notice Look for an ACCOUNT block after the current run boundary and return its value.
|
|
1382
|
-
/// Searches from `cur.bound` to the end of the source region.
|
|
1383
|
-
/// @param cur Source cursor; `bound` marks the end of the primary run.
|
|
1384
|
-
/// @param backup Account to return if no ACCOUNT block is found.
|
|
1385
|
-
/// @return account Account from the ACCOUNT block, or `backup` if absent.
|
|
1386
|
-
function accountAfter(Cur memory cur, bytes32 backup) internal pure returns (bytes32 account) {
|
|
1387
|
-
uint i = find(cur, cur.bound, Keys.Account);
|
|
1388
|
-
if (i == cur.len) return backup;
|
|
1389
|
-
|
|
1390
|
-
(uint abs, ) = expect(cur, i, 0, Keys.Account, 32, 32);
|
|
1391
|
-
return bytes32(msg.data[abs:abs + 32]);
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
/// @notice Parse the trailing AUTH block and compute the signed message hash.
|
|
1395
|
-
/// The AUTH block must occupy the final `Sizes.Auth` bytes of the source region
|
|
1396
|
-
/// and must begin after `cur.bound`.
|
|
1397
|
-
/// The signed slice covers from `cur.i` up to (but not including) the AUTH proof bytes.
|
|
1398
|
-
/// @param cur Source cursor; `bound` marks the end of the primary data region.
|
|
1399
|
-
/// @param cid Command ID that the signature must be bound to.
|
|
1400
|
-
/// @return digest keccak256 of the signed message slice.
|
|
1401
|
-
/// @return deadline Expiry timestamp from the AUTH block.
|
|
1402
|
-
/// @return proof Raw proof bytes (layout: `[bytes20 signer][bytes65 sig]`).
|
|
1403
|
-
function authLast(
|
|
1404
|
-
Cur memory cur,
|
|
1405
|
-
uint cid
|
|
1406
|
-
) internal pure returns (bytes32 digest, uint deadline, bytes calldata proof) {
|
|
1407
|
-
if (cur.len - cur.i < Sizes.Auth) revert MalformedBlocks();
|
|
1408
|
-
|
|
1409
|
-
uint i = cur.len - Sizes.Auth;
|
|
1410
|
-
if (i < cur.bound) revert MalformedBlocks();
|
|
1411
|
-
|
|
1412
|
-
(deadline, proof) = expectAuth(cur, i, cid);
|
|
1413
|
-
digest = cur.hash(cur.i, cur.len - Sizes.Proof);
|
|
1414
|
-
}
|
|
1415
1377
|
}
|
package/blocks/Keys.sol
CHANGED
|
@@ -11,16 +11,16 @@ library Keys {
|
|
|
11
11
|
bytes4 constant Amount = bytes4(keccak256("#amount"));
|
|
12
12
|
/// @dev Ledger balance - (bytes32 asset, bytes32 meta, uint amount)
|
|
13
13
|
bytes4 constant Balance = bytes4(keccak256("#balance"));
|
|
14
|
+
/// @dev Balance constraint - (bytes32 asset, bytes32 meta, uint min, uint max)
|
|
15
|
+
bytes4 constant BalanceLimit = bytes4(keccak256("#balanceLimit"));
|
|
14
16
|
/// @dev Host-scoped request amount - (uint host, bytes32 asset, bytes32 meta, uint amount)
|
|
15
17
|
bytes4 constant Allocation = bytes4(keccak256("#allocation"));
|
|
16
18
|
/// @dev Host-scoped allowance cap - (uint host, bytes32 asset, bytes32 meta, uint amount)
|
|
17
19
|
bytes4 constant Allowance = bytes4(keccak256("#allowance"));
|
|
18
20
|
/// @dev Cross-host custody state - (uint host, bytes32 asset, bytes32 meta, uint amount)
|
|
19
21
|
bytes4 constant Custody = bytes4(keccak256("#custody"));
|
|
20
|
-
/// @dev
|
|
21
|
-
bytes4 constant
|
|
22
|
-
/// @dev Maximum allowable spend - (bytes32 asset, bytes32 meta, uint amount)
|
|
23
|
-
bytes4 constant Maximum = bytes4(keccak256("#maximum"));
|
|
22
|
+
/// @dev Cross-host custody constraint - (uint host, bytes32 asset, bytes32 meta, uint min, uint max)
|
|
23
|
+
bytes4 constant CustodyLimit = bytes4(keccak256("#custodyLimit"));
|
|
24
24
|
/// @dev Fee amount - (uint amount)
|
|
25
25
|
bytes4 constant Fee = bytes4(keccak256("#fee"));
|
|
26
26
|
/// @dev List wrapper; payload is an embedded repeated block stream
|
|
@@ -33,8 +33,6 @@ library Keys {
|
|
|
33
33
|
bytes4 constant Bytes = bytes4(keccak256("#bytes"));
|
|
34
34
|
/// @dev Account identifier - (bytes32 account)
|
|
35
35
|
bytes4 constant Account = bytes4(keccak256("#account"));
|
|
36
|
-
/// @dev Transfer payout request - (bytes32 account, bytes32 asset, bytes32 meta, uint amount)
|
|
37
|
-
bytes4 constant Payout = bytes4(keccak256("#payout"));
|
|
38
36
|
/// @dev Transfer record passed through the pipeline - (bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount)
|
|
39
37
|
bytes4 constant Transaction = bytes4(keccak256("#transaction"));
|
|
40
38
|
/// @dev Sub-command invocation - (uint target, uint value, #bytes as request)
|
package/blocks/Schema.sol
CHANGED
|
@@ -11,8 +11,11 @@ pragma solidity ^0.8.33;
|
|
|
11
11
|
// - a block without braces has no payload, e.g. `#unit`
|
|
12
12
|
// - commas separate siblings at every level
|
|
13
13
|
// - braces define parent-child boundaries
|
|
14
|
-
// -
|
|
15
|
-
// -
|
|
14
|
+
// - command requests start with the input run when the request schema is non-empty
|
|
15
|
+
// - checked command requests include a constraint run after the input run; if the
|
|
16
|
+
// request schema is empty, the constraint run starts the request
|
|
17
|
+
// - command state starts with the active state run; trailing state globals may follow
|
|
18
|
+
// - run items may repeat at top level for batching
|
|
16
19
|
// - `maybe #x { ... }` marks an optional block item
|
|
17
20
|
// - `many #x { ... }` emits one generic list block containing repeated `#x` items
|
|
18
21
|
// - fixed fields are packed in declaration order
|
|
@@ -30,8 +33,8 @@ pragma solidity ^0.8.33;
|
|
|
30
33
|
// - while a balance or custody is in-flight as pipeline state, it is not simultaneously persisted
|
|
31
34
|
// in another ledger/store by this protocol
|
|
32
35
|
// - commands must preserve, transform, settle, or intentionally consume pipeline state
|
|
33
|
-
// - request blocks such as `amount(...)`, `allocation(...)`, `allowance(...)
|
|
34
|
-
//
|
|
36
|
+
// - request blocks such as `amount(...)`, `allocation(...)`, and `allowance(...)`
|
|
37
|
+
// express intent, constraints, or references
|
|
35
38
|
// - request and value/response blocks are not live state
|
|
36
39
|
//
|
|
37
40
|
// Signed blocks:
|
|
@@ -50,12 +53,11 @@ library Schemas {
|
|
|
50
53
|
string constant Node = "#node { uint id }";
|
|
51
54
|
string constant Account = "#account { bytes32 account }";
|
|
52
55
|
string constant Asset = "#asset { bytes32 asset, bytes32 meta }";
|
|
53
|
-
string constant Balance = "#balance { bytes32 asset, bytes32 meta, uint amount }";
|
|
54
56
|
string constant Amount = "#amount { bytes32 asset, bytes32 meta, uint amount }";
|
|
55
|
-
string constant
|
|
56
|
-
string constant
|
|
57
|
+
string constant Balance = "#balance { bytes32 asset, bytes32 meta, uint amount }";
|
|
58
|
+
string constant BalanceLimit = "#balanceLimit { bytes32 asset, bytes32 meta, uint min, uint max }";
|
|
57
59
|
string constant Custody = "#custody { uint host, bytes32 asset, bytes32 meta, uint amount }";
|
|
58
|
-
string constant
|
|
60
|
+
string constant CustodyLimit = "#custodyLimit { uint host, bytes32 asset, bytes32 meta, uint min, uint max }";
|
|
59
61
|
string constant Allocation = "#allocation { uint host, bytes32 asset, bytes32 meta, uint amount }";
|
|
60
62
|
string constant Allowance = "#allowance { uint host, bytes32 asset, bytes32 meta, uint amount }";
|
|
61
63
|
string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount }";
|
|
@@ -113,12 +115,16 @@ library Sizes {
|
|
|
113
115
|
uint constant Amount = B96;
|
|
114
116
|
/// @dev BALANCE block: 8 header + 32 asset + 32 meta + 32 amount = 104 bytes
|
|
115
117
|
uint constant Balance = B96;
|
|
118
|
+
/// @dev BALANCE_LIMIT block: 8 header + 32 asset + 32 meta + 32 min + 32 max = 136 bytes
|
|
119
|
+
uint constant BalanceLimit = B128;
|
|
116
120
|
/// @dev FEE block: 8 header + 32 amount = 40 bytes
|
|
117
121
|
uint constant Fee = B32;
|
|
118
122
|
/// @dev BOUNTY block: 8 header + 32 amount + 32 relayer = 72 bytes
|
|
119
123
|
uint constant Bounty = B64;
|
|
120
124
|
/// @dev ALLOCATION/CUSTODY block: 8 header + 32 host + 32 asset + 32 meta + 32 amount = 136 bytes
|
|
121
125
|
uint constant HostAmount = B128;
|
|
126
|
+
/// @dev CUSTODY_LIMIT block: 8 header + 32 host + 32 asset + 32 meta + 32 min + 32 max = 168 bytes
|
|
127
|
+
uint constant CustodyLimit = B160;
|
|
122
128
|
/// @dev TRANSACTION block: 8 header + 32 from + 32 to + 32 asset + 32 meta + 32 amount = 168 bytes
|
|
123
129
|
uint constant Transaction = B160;
|
|
124
130
|
}
|
package/commands/Burn.sol
CHANGED
|
@@ -25,18 +25,18 @@ abstract contract Burn is CommandBase, BurnHook {
|
|
|
25
25
|
uint internal immutable burnId = commandId(NAME);
|
|
26
26
|
|
|
27
27
|
constructor() {
|
|
28
|
-
emit Command(host, burnId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false);
|
|
28
|
+
emit Command(host, burnId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
function burn(CommandContext calldata c) external onlyCommand returns (bytes memory) {
|
|
32
|
-
(Cur memory state, ) =
|
|
32
|
+
(Cur memory state, ) = Cursors.first(c.state, 1);
|
|
33
33
|
|
|
34
|
-
while (state.i < state.
|
|
34
|
+
while (state.i < state.len) {
|
|
35
35
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
|
36
36
|
burn(c.account, asset, meta, amount);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
state.
|
|
39
|
+
state.complete();
|
|
40
40
|
return "";
|
|
41
41
|
}
|
|
42
42
|
}
|
package/commands/Credit.sol
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import { CommandBase, CommandContext, Keys } from "./Base.sol";
|
|
5
|
-
import { Cursors, Cur
|
|
5
|
+
import { Cursors, Cur } from "../Cursors.sol";
|
|
6
6
|
|
|
7
7
|
using Cursors for Cur;
|
|
8
8
|
|
|
@@ -19,29 +19,26 @@ abstract contract CreditAccountHook {
|
|
|
19
19
|
/// @title CreditAccount
|
|
20
20
|
/// @notice Command that delivers BALANCE state blocks to an account via a virtual hook.
|
|
21
21
|
/// Use for internally recording credits that have already been settled externally.
|
|
22
|
-
/// An optional ACCOUNT block in the request overrides the default `c.account` destination.
|
|
23
22
|
abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
24
23
|
string private constant NAME = "creditAccount";
|
|
25
|
-
string private constant REQUEST = string.concat(Schemas.Unit, ", maybe ", Schemas.Account);
|
|
26
24
|
|
|
27
25
|
uint internal immutable creditAccountId = commandId(NAME);
|
|
28
26
|
|
|
29
27
|
constructor() {
|
|
30
|
-
emit Command(host, creditAccountId, NAME, "0:1:0",
|
|
28
|
+
emit Command(host, creditAccountId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
function creditAccount(
|
|
34
32
|
CommandContext calldata c
|
|
35
33
|
) external onlyCommand returns (bytes memory) {
|
|
36
|
-
(Cur memory state, ) =
|
|
37
|
-
bytes32 to = Cursors.resolveAccount(c.request, c.account);
|
|
34
|
+
(Cur memory state, ) = Cursors.first(c.state, 1);
|
|
38
35
|
|
|
39
|
-
while (state.i < state.
|
|
36
|
+
while (state.i < state.len) {
|
|
40
37
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
|
41
|
-
creditAccount(
|
|
38
|
+
creditAccount(c.account, asset, meta, amount);
|
|
42
39
|
}
|
|
43
40
|
|
|
44
|
-
state.
|
|
41
|
+
state.complete();
|
|
45
42
|
return "";
|
|
46
43
|
}
|
|
47
44
|
}
|
package/commands/Debit.sol
CHANGED
|
@@ -27,23 +27,23 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
27
27
|
uint internal immutable debitAccountId = commandId(NAME);
|
|
28
28
|
|
|
29
29
|
constructor() {
|
|
30
|
-
emit Command(host, debitAccountId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
30
|
+
emit Command(host, debitAccountId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, false);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/// @notice Override to customize request parsing or batching for debits.
|
|
34
34
|
/// The default implementation iterates AMOUNT blocks, calls
|
|
35
35
|
/// `debitAccount`, and emits matching BALANCE blocks.
|
|
36
36
|
function debitAccount(bytes32 account, bytes calldata request) internal virtual returns (bytes memory) {
|
|
37
|
-
(Cur memory input, uint groups) =
|
|
37
|
+
(Cur memory input, uint groups) = Cursors.first(request, 1);
|
|
38
38
|
Writer memory writer = Writers.allocBalances(groups);
|
|
39
39
|
|
|
40
|
-
while (input.i < input.
|
|
40
|
+
while (input.i < input.len) {
|
|
41
41
|
(bytes32 asset, bytes32 meta, uint amount) = input.unpackAmount();
|
|
42
42
|
debitAccount(account, asset, meta, amount);
|
|
43
43
|
writer.appendBalance(asset, meta, amount);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
input.
|
|
46
|
+
input.complete();
|
|
47
47
|
return writer.finish();
|
|
48
48
|
}
|
|
49
49
|
|