@rootzero/contracts 1.14.0 → 1.16.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 +100 -0
- package/Codec.sol +1 -1
- package/Commands.sol +1 -1
- package/Core.sol +8 -5
- package/Endpoints.sol +6 -6
- package/Events.sol +1 -3
- package/README.md +118 -35
- package/annotations/Action.sol +17 -0
- package/annotations/Label.sol +23 -0
- package/annotations/Schema.sol +53 -0
- package/codec/Blocks.sol +127 -32
- package/codec/Buffers.sol +3 -3
- package/codec/Decoders.sol +46 -13
- package/codec/Descriptors.sol +0 -1
- package/codec/Keys.sol +8 -4
- package/codec/Readers.sol +13 -0
- package/codec/Schema.sol +12 -3
- package/codec/Specs.sol +28 -4
- package/codec/Writers.sol +21 -6
- package/commands/Base.sol +39 -44
- package/commands/Burn.sol +8 -4
- package/commands/Credit.sol +35 -3
- package/commands/Debit.sol +46 -13
- package/commands/Deposit.sol +14 -8
- package/commands/Payout.sol +6 -2
- package/commands/Provision.sol +4 -4
- package/commands/Recover.sol +15 -8
- package/commands/Relay.sol +37 -12
- package/commands/Settle.sol +77 -0
- package/commands/Withdraw.sol +8 -4
- package/commands/admin/AllowAssets.sol +2 -2
- package/commands/admin/Allowance.sol +2 -2
- package/commands/admin/Annotate.sol +36 -0
- package/commands/admin/Appoint.sol +6 -5
- package/commands/admin/Authorize.sol +2 -2
- package/commands/admin/Base.sol +8 -1
- package/commands/admin/DenyAssets.sol +2 -2
- package/commands/admin/Dismiss.sol +6 -5
- package/commands/admin/Execute.sol +5 -4
- package/commands/admin/Unauthorize.sol +2 -2
- package/core/Access.sol +91 -49
- package/core/Calls.sol +27 -22
- package/core/Endpoint.sol +36 -46
- package/core/Host.sol +63 -21
- package/core/Pipeline.sol +6 -6
- package/core/Settlement.sol +37 -8
- package/core/Types.sol +13 -1
- package/docs/Schema.md +68 -7
- package/events/Annotation.sol +24 -0
- package/events/Guardian.sol +2 -2
- package/events/Introduction.sol +3 -2
- package/execution/Budget.sol +12 -4
- package/execution/Execution.sol +113 -18
- package/guards/Base.sol +4 -4
- package/package.json +1 -1
- package/ports/Base.sol +19 -7
- package/ports/Dispatch.sol +6 -6
- package/ports/{Settle.sol → Post.sol} +13 -9
- package/queries/Base.sol +18 -3
- package/utils/Accounts.sol +0 -23
- package/utils/Actions.sol +1 -0
- package/utils/Cursors.sol +79 -34
- package/utils/Layout.sol +0 -2
- package/commands/admin/Label.sol +0 -36
- package/commands/admin/Schemas.sol +0 -36
- package/events/Labeled.sol +0 -21
- package/events/Position.sol +0 -22
- package/events/Schema.sol +0 -23
package/codec/Blocks.sol
CHANGED
|
@@ -35,10 +35,6 @@ library Blocks {
|
|
|
35
35
|
error UnexpectedValue();
|
|
36
36
|
/// @dev A scoped block run contained no blocks.
|
|
37
37
|
error EmptyRun();
|
|
38
|
-
/// @dev A block run was scoped with a zero stride.
|
|
39
|
-
error ZeroStride();
|
|
40
|
-
/// @dev A block count is not divisible by its declared stride.
|
|
41
|
-
error BadRatio();
|
|
42
38
|
|
|
43
39
|
// -------------------------------------------------------------------------
|
|
44
40
|
// Calldata inspection and navigation
|
|
@@ -147,25 +143,16 @@ library Blocks {
|
|
|
147
143
|
}
|
|
148
144
|
}
|
|
149
145
|
|
|
150
|
-
/// @notice
|
|
146
|
+
/// @notice Count a run that must consume the complete region.
|
|
147
|
+
/// @dev Reverts when any well-formed trailing block has a different key.
|
|
151
148
|
/// @param abs Absolute start position.
|
|
152
149
|
/// @param limit Absolute region boundary.
|
|
153
|
-
/// @param key
|
|
154
|
-
/// @
|
|
155
|
-
/// @return
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
uint limit,
|
|
160
|
-
bytes4 key,
|
|
161
|
-
uint stride
|
|
162
|
-
) internal pure returns (uint groups, uint end) {
|
|
163
|
-
if (stride == 0) revert ZeroStride();
|
|
164
|
-
uint count;
|
|
165
|
-
(count, end) = run(abs, limit, key);
|
|
166
|
-
if (count == 0) revert EmptyRun();
|
|
167
|
-
if (count % stride != 0) revert BadRatio();
|
|
168
|
-
groups = count / stride;
|
|
150
|
+
/// @param key Required block key for the complete region.
|
|
151
|
+
/// @return total Number of matching blocks.
|
|
152
|
+
/// @return end Absolute position equal to `limit`.
|
|
153
|
+
function runExact(uint abs, uint limit, bytes4 key) internal pure returns (uint total, uint end) {
|
|
154
|
+
(total, end) = run(abs, limit, key);
|
|
155
|
+
if (end != limit) revert InvalidBlock();
|
|
169
156
|
}
|
|
170
157
|
|
|
171
158
|
// Generic block writes
|
|
@@ -460,6 +447,33 @@ library Blocks {
|
|
|
460
447
|
|
|
461
448
|
// Four-word payloads
|
|
462
449
|
|
|
450
|
+
/// @notice Write a POSITION block at `i`.
|
|
451
|
+
/// @dev DANGER: Unchecked memory write. Reserve `Sizes.B128` bytes first.
|
|
452
|
+
/// @param dst Destination buffer.
|
|
453
|
+
/// @param i Relative write position.
|
|
454
|
+
/// @param asset Identifier for the asset side.
|
|
455
|
+
/// @param amount Quantity on the asset side.
|
|
456
|
+
/// @param liability Identifier for the liability side.
|
|
457
|
+
/// @param debt Quantity owed on the liability side.
|
|
458
|
+
function writePosition(
|
|
459
|
+
bytes memory dst,
|
|
460
|
+
uint i,
|
|
461
|
+
bytes32 asset,
|
|
462
|
+
uint amount,
|
|
463
|
+
bytes32 liability,
|
|
464
|
+
uint debt
|
|
465
|
+
) internal pure {
|
|
466
|
+
uint spec = Specs.Position;
|
|
467
|
+
assembly ("memory-safe") {
|
|
468
|
+
let p := add(add(dst, 0x20), i)
|
|
469
|
+
mstore(p, spec)
|
|
470
|
+
mstore(add(p, 0x08), asset)
|
|
471
|
+
mstore(add(p, 0x28), amount)
|
|
472
|
+
mstore(add(p, 0x48), liability)
|
|
473
|
+
mstore(add(p, 0x68), debt)
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
463
477
|
/// @notice Write a TRANSACTION block at `i`.
|
|
464
478
|
/// @dev DANGER: Unchecked memory write. Reserve `Sizes.B128` bytes first.
|
|
465
479
|
/// @param dst Destination buffer.
|
|
@@ -754,20 +768,18 @@ library Blocks {
|
|
|
754
768
|
/// block size and ensure the encoded payload length fits in uint32.
|
|
755
769
|
/// @param dst Destination buffer.
|
|
756
770
|
/// @param i Relative write position.
|
|
757
|
-
/// @param id Node identifier.
|
|
758
771
|
/// @param namespace Label namespace.
|
|
759
772
|
/// @param name Label text.
|
|
760
|
-
function writeLabel(bytes memory dst, uint i,
|
|
761
|
-
uint len =
|
|
773
|
+
function writeLabel(bytes memory dst, uint i, bytes32 namespace, string memory name) internal pure {
|
|
774
|
+
uint len = 32 + Sizes.Header + bytes(name).length;
|
|
762
775
|
uint key = uint32(Keys.Label);
|
|
763
776
|
uint stringkey = uint32(Keys.String);
|
|
764
777
|
assembly ("memory-safe") {
|
|
765
778
|
let p := add(add(dst, 0x20), i)
|
|
766
779
|
mstore(p, or(shl(224, key), shl(192, len)))
|
|
767
|
-
mstore(add(p, 0x08),
|
|
768
|
-
mstore(add(p, 0x28), namespace)
|
|
780
|
+
mstore(add(p, 0x08), namespace)
|
|
769
781
|
|
|
770
|
-
let q := add(p,
|
|
782
|
+
let q := add(p, 0x28)
|
|
771
783
|
let namelen := mload(name)
|
|
772
784
|
mstore(q, or(shl(224, stringkey), shl(192, namelen)))
|
|
773
785
|
mcopy(add(q, 0x08), add(name, 0x20), namelen)
|
|
@@ -1251,6 +1263,28 @@ library Blocks {
|
|
|
1251
1263
|
|
|
1252
1264
|
// Four-word payloads
|
|
1253
1265
|
|
|
1266
|
+
/// @notice Decode a low-level fixed-width POSITION block at `abs`.
|
|
1267
|
+
/// @param abs Absolute block position.
|
|
1268
|
+
/// @return asset Decoded asset-side identifier.
|
|
1269
|
+
/// @return amount Decoded asset-side quantity.
|
|
1270
|
+
/// @return liability Decoded liability-side identifier.
|
|
1271
|
+
/// @return debt Decoded liability-side debt.
|
|
1272
|
+
function unpackPosition(
|
|
1273
|
+
uint abs
|
|
1274
|
+
) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
|
|
1275
|
+
uint head;
|
|
1276
|
+
assembly ("memory-safe") {
|
|
1277
|
+
head := calldataload(abs)
|
|
1278
|
+
}
|
|
1279
|
+
if (head >> 192 != Specs.Position >> 192) revert InvalidBlock();
|
|
1280
|
+
assembly ("memory-safe") {
|
|
1281
|
+
asset := calldataload(add(abs, 0x08))
|
|
1282
|
+
amount := calldataload(add(abs, 0x28))
|
|
1283
|
+
liability := calldataload(add(abs, 0x48))
|
|
1284
|
+
debt := calldataload(add(abs, 0x68))
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1254
1288
|
/// @notice Decode a low-level fixed-width TRANSACTION block at `abs`.
|
|
1255
1289
|
/// @param abs Absolute block position.
|
|
1256
1290
|
/// @return from Decoded debit account.
|
|
@@ -1345,6 +1379,23 @@ library Blocks {
|
|
|
1345
1379
|
|
|
1346
1380
|
// One fixed word
|
|
1347
1381
|
|
|
1382
|
+
/// @notice Decode one ANNOTATION block and its nested block stream.
|
|
1383
|
+
/// @param abs Absolute block position.
|
|
1384
|
+
/// @return entity Decoded entity identifier.
|
|
1385
|
+
/// @return stream Decoded annotation block stream.
|
|
1386
|
+
/// @return end Absolute position after the block.
|
|
1387
|
+
function unpackAnnotation(
|
|
1388
|
+
uint abs
|
|
1389
|
+
) internal pure returns (uint entity, bytes calldata stream, uint end) {
|
|
1390
|
+
uint limit;
|
|
1391
|
+
(abs, limit) = expect(abs, Specs.Annotation);
|
|
1392
|
+
assembly ("memory-safe") {
|
|
1393
|
+
entity := calldataload(abs)
|
|
1394
|
+
}
|
|
1395
|
+
(stream, end) = unpackBytes(abs + 32);
|
|
1396
|
+
if (end != limit) revert InvalidBlock();
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1348
1399
|
/// @notice Decode one CONTEXT block and all nested byte blocks.
|
|
1349
1400
|
/// @param abs Absolute block position.
|
|
1350
1401
|
/// @return account Decoded account identifier.
|
|
@@ -1444,19 +1495,17 @@ library Blocks {
|
|
|
1444
1495
|
|
|
1445
1496
|
/// @notice Decode one LABEL block and its nested name.
|
|
1446
1497
|
/// @param abs Absolute block position.
|
|
1447
|
-
/// @return id Decoded node identifier.
|
|
1448
1498
|
/// @return namespace Decoded label namespace.
|
|
1449
1499
|
/// @return name Decoded label text.
|
|
1450
1500
|
/// @return end Absolute position after the block.
|
|
1451
|
-
function unpackLabel(uint abs) internal pure returns (
|
|
1501
|
+
function unpackLabel(uint abs) internal pure returns (bytes32 namespace, string memory name, uint end) {
|
|
1452
1502
|
uint limit;
|
|
1453
1503
|
(abs, limit) = expect(abs, Specs.Label);
|
|
1454
1504
|
assembly ("memory-safe") {
|
|
1455
|
-
|
|
1456
|
-
namespace := calldataload(add(abs, 0x20))
|
|
1505
|
+
namespace := calldataload(abs)
|
|
1457
1506
|
}
|
|
1458
1507
|
bytes calldata value;
|
|
1459
|
-
(value, end) = unpackString(abs +
|
|
1508
|
+
(value, end) = unpackString(abs + 32);
|
|
1460
1509
|
if (end != limit) revert InvalidBlock();
|
|
1461
1510
|
name = string(value);
|
|
1462
1511
|
}
|
|
@@ -1532,6 +1581,30 @@ library Blocks {
|
|
|
1532
1581
|
return create(Keys.String, bytes(value));
|
|
1533
1582
|
}
|
|
1534
1583
|
|
|
1584
|
+
/// @notice Encode a LABEL block.
|
|
1585
|
+
/// @param namespace Label namespace.
|
|
1586
|
+
/// @param name Label text.
|
|
1587
|
+
/// @return Encoded LABEL block bytes.
|
|
1588
|
+
function label(bytes32 namespace, string memory name) internal pure returns (bytes memory) {
|
|
1589
|
+
return create(Keys.Label, bytes.concat(namespace, text(name)));
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
/// @notice Encode an ACTION annotation block.
|
|
1593
|
+
/// @param value Canonical semantic action identifier.
|
|
1594
|
+
/// @return Encoded ACTION block bytes.
|
|
1595
|
+
function action(uint value) internal pure returns (bytes memory) {
|
|
1596
|
+
return create(Keys.Action, bytes.concat(bytes32(value)));
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
/// @notice Encode a SCHEMA block.
|
|
1600
|
+
/// @param spec Block specification.
|
|
1601
|
+
/// @param body Schema body.
|
|
1602
|
+
/// @param name Schema name.
|
|
1603
|
+
/// @return Encoded SCHEMA block bytes.
|
|
1604
|
+
function schema(uint spec, string memory body, bytes32 name) internal pure returns (bytes memory) {
|
|
1605
|
+
return create(Keys.Schema, bytes.concat(bytes32(spec), text(body), name));
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1535
1608
|
/// @notice Encode a BALANCE block.
|
|
1536
1609
|
/// @param asset Asset identifier.
|
|
1537
1610
|
/// @param amount Token amount.
|
|
@@ -1540,6 +1613,28 @@ library Blocks {
|
|
|
1540
1613
|
return bytes.concat(Keys.Balance, bytes4(uint32(64)), asset, bytes32(amount));
|
|
1541
1614
|
}
|
|
1542
1615
|
|
|
1616
|
+
/// @notice Encode a POSITION block.
|
|
1617
|
+
/// @param asset Identifier for the asset side.
|
|
1618
|
+
/// @param amount Quantity on the asset side.
|
|
1619
|
+
/// @param liability Identifier for the liability side.
|
|
1620
|
+
/// @param debt Quantity owed on the liability side.
|
|
1621
|
+
/// @return Encoded POSITION block bytes.
|
|
1622
|
+
function position(
|
|
1623
|
+
bytes32 asset,
|
|
1624
|
+
uint amount,
|
|
1625
|
+
bytes32 liability,
|
|
1626
|
+
uint debt
|
|
1627
|
+
) internal pure returns (bytes memory) {
|
|
1628
|
+
return bytes.concat(
|
|
1629
|
+
Keys.Position,
|
|
1630
|
+
bytes4(uint32(128)),
|
|
1631
|
+
asset,
|
|
1632
|
+
bytes32(amount),
|
|
1633
|
+
liability,
|
|
1634
|
+
bytes32(debt)
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1543
1638
|
/// @notice Encode a CUSTODY block.
|
|
1544
1639
|
/// @param host Host node ID holding the custody.
|
|
1545
1640
|
/// @param asset Asset identifier.
|
package/codec/Buffers.sol
CHANGED
|
@@ -18,12 +18,12 @@ library Buffers {
|
|
|
18
18
|
|
|
19
19
|
/// @notice Create a packed buffer cursor at write position zero.
|
|
20
20
|
/// @param len Initial logical byte capacity.
|
|
21
|
-
/// @param
|
|
21
|
+
/// @param count Number of logical items represented by the buffer.
|
|
22
22
|
/// @param growable Whether writes may expand the logical capacity.
|
|
23
23
|
/// @param tag Cursor identity tag.
|
|
24
24
|
/// @return cur Packed buffer cursor.
|
|
25
|
-
function cursor(uint len, uint
|
|
26
|
-
cur = Cursors.create(0, len,
|
|
25
|
+
function cursor(uint len, uint count, bool growable, uint8 tag) internal pure returns (uint cur) {
|
|
26
|
+
cur = Cursors.create(0, len, count, growable ? Growable : 0, tag);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/// @notice Reserve relative write space and return the updated packed buffer cursor.
|
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, 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.
|
|
@@ -365,6 +372,19 @@ library Decoders {
|
|
|
365
372
|
cur.state = cur.state.seekAbs(end);
|
|
366
373
|
}
|
|
367
374
|
|
|
375
|
+
/// @notice Decode and consume one ANNOTATION block.
|
|
376
|
+
/// @param cur Cursor advanced past the block.
|
|
377
|
+
/// @return entity Decoded entity identifier.
|
|
378
|
+
/// @return data Decoded annotation block stream.
|
|
379
|
+
function unpackAnnotation(
|
|
380
|
+
Cur memory cur
|
|
381
|
+
) internal pure returns (uint entity, bytes calldata data) {
|
|
382
|
+
uint abs = cur.state.absolute();
|
|
383
|
+
uint end;
|
|
384
|
+
(entity, data, end) = Blocks.unpackAnnotation(abs);
|
|
385
|
+
cur.state = cur.state.seekAbs(end);
|
|
386
|
+
}
|
|
387
|
+
|
|
368
388
|
/// @notice Decode and consume one CONTEXT block.
|
|
369
389
|
/// @param cur Cursor advanced past the block.
|
|
370
390
|
/// @return account Decoded account identifier.
|
|
@@ -395,13 +415,12 @@ library Decoders {
|
|
|
395
415
|
|
|
396
416
|
/// @notice Decode and consume one LABEL block.
|
|
397
417
|
/// @param cur Cursor advanced past the block.
|
|
398
|
-
/// @return id Decoded node identifier.
|
|
399
418
|
/// @return namespace Decoded label namespace.
|
|
400
419
|
/// @return name Decoded label text.
|
|
401
|
-
function unpackLabel(Cur memory cur) internal pure returns (
|
|
420
|
+
function unpackLabel(Cur memory cur) internal pure returns (bytes32 namespace, string memory name) {
|
|
402
421
|
uint abs = cur.state.absolute();
|
|
403
422
|
uint end;
|
|
404
|
-
(
|
|
423
|
+
(namespace, name, end) = Blocks.unpackLabel(abs);
|
|
405
424
|
cur.state = cur.state.seekAbs(end);
|
|
406
425
|
}
|
|
407
426
|
|
|
@@ -520,6 +539,20 @@ library Decoders {
|
|
|
520
539
|
(value.host, value.asset, value.amount) = unpackCustody(cur);
|
|
521
540
|
}
|
|
522
541
|
|
|
542
|
+
/// @notice Decode and consume one POSITION block.
|
|
543
|
+
function unpackPosition(
|
|
544
|
+
Cur memory cur
|
|
545
|
+
) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
|
|
546
|
+
uint abs;
|
|
547
|
+
(cur.state, abs) = cur.state.consume(Sizes.Position);
|
|
548
|
+
(asset, amount, liability, debt) = Blocks.unpackPosition(abs);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/// @notice Decode one POSITION block into its structured value.
|
|
552
|
+
function unpackPositionValue(Cur memory cur) internal pure returns (Position memory value) {
|
|
553
|
+
(value.asset, value.amount, value.liability, value.debt) = unpackPosition(cur);
|
|
554
|
+
}
|
|
555
|
+
|
|
523
556
|
/// @notice Decode one TRANSACTION block into its structured value.
|
|
524
557
|
/// @param cur Cursor advanced past the block.
|
|
525
558
|
/// @return value Structured transaction.
|
package/codec/Descriptors.sol
CHANGED
package/codec/Keys.sol
CHANGED
|
@@ -5,12 +5,10 @@ pragma solidity ^0.8.33;
|
|
|
5
5
|
/// @notice Standard block type selectors for the rootzero block stream protocol.
|
|
6
6
|
/// Standard keys use the first 4 bytes of `keccak256("#name")` by convention.
|
|
7
7
|
/// Custom block keys only need to be unique in the context where they are used;
|
|
8
|
-
/// hosts may publish custom key meanings with
|
|
8
|
+
/// hosts may publish custom key meanings with `#schema` annotations.
|
|
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
|
|
@@ -49,8 +49,12 @@ library Keys {
|
|
|
49
49
|
bytes4 constant Asset = bytes4(keccak256("#asset"));
|
|
50
50
|
/// @dev Node identifier - (uint id)
|
|
51
51
|
bytes4 constant Node = bytes4(keccak256("#node"));
|
|
52
|
-
/// @dev
|
|
52
|
+
/// @dev Entity label annotation - (bytes32 namespace, #string as name)
|
|
53
53
|
bytes4 constant Label = bytes4(keccak256("#label"));
|
|
54
|
+
/// @dev Entity annotations - (uint entity, #bytes as data)
|
|
55
|
+
bytes4 constant Annotation = bytes4(keccak256("#annotation"));
|
|
56
|
+
/// @dev Primary semantic action annotation - (uint action)
|
|
57
|
+
bytes4 constant Action = bytes4(keccak256("#action"));
|
|
54
58
|
/// @dev Block schema publication - (bytes4 key, #string as body, bytes32 name)
|
|
55
59
|
bytes4 constant Schema = bytes4(keccak256("#schema"));
|
|
56
60
|
|
package/codec/Readers.sol
CHANGED
|
@@ -94,6 +94,19 @@ library Readers {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/// @notice Consume a POSITION block and return its fields.
|
|
98
|
+
function unpackPosition(
|
|
99
|
+
Reader memory cur
|
|
100
|
+
) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
|
|
101
|
+
uint abs = consume(cur, Keys.Position, 128, 128);
|
|
102
|
+
assembly ("memory-safe") {
|
|
103
|
+
asset := mload(abs)
|
|
104
|
+
amount := mload(add(abs, 0x20))
|
|
105
|
+
liability := mload(add(abs, 0x40))
|
|
106
|
+
debt := mload(add(abs, 0x60))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
97
110
|
/// @notice Consume a TRANSACTION block and return its fields.
|
|
98
111
|
/// @param cur Reader; advanced past the block.
|
|
99
112
|
/// @return from Source account identifier.
|
package/codec/Schema.sol
CHANGED
|
@@ -36,17 +36,20 @@ pragma solidity ^0.8.33;
|
|
|
36
36
|
// - generic lists use the stable key derived from `#list`
|
|
37
37
|
// - standard keys are derived from block aliases, e.g. bytes4(keccak256("#amount"))
|
|
38
38
|
// - custom keys are opaque bytes4 tags and only need to be unique in their
|
|
39
|
-
// active context; use
|
|
39
|
+
// active context; use a `#schema` annotation to publish their meaning
|
|
40
40
|
// - see `docs/Schema.md` for the full working spec
|
|
41
41
|
//
|
|
42
42
|
// Pipeline state:
|
|
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
|
|
@@ -90,6 +93,7 @@ library Schemas {
|
|
|
90
93
|
|
|
91
94
|
// Four-word payloads
|
|
92
95
|
|
|
96
|
+
string constant Position = "{ bytes32 asset, uint amount, bytes32 liability, uint debt }";
|
|
93
97
|
string constant Transaction = "{ bytes32 from, bytes32 to, bytes32 asset, uint amount }";
|
|
94
98
|
string constant HostAccountAmount = "{ uint host, bytes32 account, bytes32 asset, uint amount }";
|
|
95
99
|
|
|
@@ -101,7 +105,12 @@ library Schemas {
|
|
|
101
105
|
string constant Dispatch = "{ uint portal, uint resources, #bytes as payload }";
|
|
102
106
|
string constant Context = "{ bytes32 account, #bytes as state, #bytes as input }";
|
|
103
107
|
string constant Recover = "{ uint handler, uint resources, bytes32 key, #bytes as witness }";
|
|
104
|
-
string constant
|
|
108
|
+
string constant Annotation = "{ uint entity, #bytes as data }";
|
|
109
|
+
|
|
110
|
+
// Annotation payloads
|
|
111
|
+
|
|
112
|
+
string constant Action = "{ uint action }";
|
|
113
|
+
string constant Label = "{ bytes32 namespace, #string as name }";
|
|
105
114
|
string constant Schema = "{ uint spec, #string as body, bytes32 name }";
|
|
106
115
|
}
|
|
107
116
|
|
package/codec/Specs.sol
CHANGED
|
@@ -31,6 +31,8 @@ library Sizes {
|
|
|
31
31
|
uint constant HostAmount = B96;
|
|
32
32
|
/// @dev TRANSACTION block: 8 header + 32 from + 32 to + 32 asset + 32 amount = 136 bytes
|
|
33
33
|
uint constant Transaction = B128;
|
|
34
|
+
/// @dev POSITION block: 8 header + four-word asset-liability pair = 136 bytes
|
|
35
|
+
uint constant Position = B128;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/// @title Specs
|
|
@@ -44,7 +46,6 @@ library Specs {
|
|
|
44
46
|
error InvalidSpec();
|
|
45
47
|
/// @dev A direct specification cannot contain a wrapper block.
|
|
46
48
|
error InvalidContainer();
|
|
47
|
-
|
|
48
49
|
uint private constant SizeFields = (uint(1) << 192) | (uint(1) << 160) | (uint(1) << 136);
|
|
49
50
|
|
|
50
51
|
// Reusable field shapes keep public specs readable while remaining valid
|
|
@@ -54,17 +55,18 @@ library Specs {
|
|
|
54
55
|
uint private constant Exact96 = 96 * SizeFields;
|
|
55
56
|
uint private constant Exact128 = 128 * SizeFields;
|
|
56
57
|
uint private constant UnboundedHint128 = uint(128) << 136;
|
|
58
|
+
uint private constant UnboundedMin40Hint256 = (uint(40) << 192) | (uint(256) << 136);
|
|
57
59
|
uint private constant UnboundedMin72Hint256 = (uint(72) << 192) | (uint(256) << 136);
|
|
58
60
|
uint private constant UnboundedMin48Hint512 = (uint(48) << 192) | (uint(512) << 136);
|
|
59
61
|
uint private constant UnboundedMin104Hint256 = (uint(104) << 192) | (uint(256) << 136);
|
|
60
62
|
|
|
61
63
|
uint constant Empty = uint(bytes32(Keys.Empty));
|
|
62
|
-
uint constant Any = uint(bytes32(Keys.Any)) | UnboundedHint128;
|
|
63
64
|
uint constant Amount = uint(bytes32(Keys.Amount)) | Exact64;
|
|
64
65
|
uint constant Balance = uint(bytes32(Keys.Balance)) | Exact64;
|
|
65
66
|
uint constant Allocation = uint(bytes32(Keys.Allocation)) | Exact96;
|
|
66
67
|
uint constant Allowance = uint(bytes32(Keys.Allowance)) | Exact96;
|
|
67
68
|
uint constant Custody = uint(bytes32(Keys.Custody)) | Exact96;
|
|
69
|
+
uint constant Position = uint(bytes32(Keys.Position)) | Exact128;
|
|
68
70
|
uint constant List = uint(bytes32(Keys.List)) | UnboundedHint128;
|
|
69
71
|
uint constant Evm = uint(bytes32(Keys.Evm)) | UnboundedHint128;
|
|
70
72
|
uint constant Bytes = uint(bytes32(Keys.Bytes)) | UnboundedHint128;
|
|
@@ -79,7 +81,9 @@ library Specs {
|
|
|
79
81
|
uint constant Call = uint(bytes32(Keys.Call)) | UnboundedMin72Hint256;
|
|
80
82
|
uint constant Asset = uint(bytes32(Keys.Asset)) | Exact32;
|
|
81
83
|
uint constant Node = uint(bytes32(Keys.Node)) | Exact32;
|
|
82
|
-
uint constant Label = uint(bytes32(Keys.Label)) |
|
|
84
|
+
uint constant Label = uint(bytes32(Keys.Label)) | UnboundedMin40Hint256;
|
|
85
|
+
uint constant Annotation = uint(bytes32(Keys.Annotation)) | UnboundedMin40Hint256;
|
|
86
|
+
uint constant Action = uint(bytes32(Keys.Action)) | Exact32;
|
|
83
87
|
uint constant Schema = uint(bytes32(Keys.Schema)) | UnboundedMin72Hint256;
|
|
84
88
|
|
|
85
89
|
uint constant Status = uint(bytes32(Keys.Status)) | Exact32;
|
|
@@ -96,12 +100,31 @@ library Specs {
|
|
|
96
100
|
/// @param hint Initial per-block payload capacity.
|
|
97
101
|
/// @return spec Packed block specification.
|
|
98
102
|
function create(bytes4 blockkey, uint32 min, uint32 max, uint32 hint) internal pure returns (uint spec) {
|
|
99
|
-
|
|
103
|
+
return create(uint32(blockkey), min, max, hint);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// @notice Construct a block specification from its numeric key and encoded fields.
|
|
107
|
+
/// @param blockkey Numeric block key.
|
|
108
|
+
/// @param min Minimum accepted payload length.
|
|
109
|
+
/// @param max Maximum accepted payload length; zero means unbounded.
|
|
110
|
+
/// @param hint Initial per-block payload capacity.
|
|
111
|
+
/// @return spec Packed block specification.
|
|
112
|
+
function create(uint32 blockkey, uint32 min, uint32 max, uint32 hint) internal pure returns (uint spec) {
|
|
113
|
+
spec |= uint(blockkey) << 224;
|
|
100
114
|
spec |= uint(min) << 192;
|
|
101
115
|
spec |= uint(max) << 160;
|
|
102
116
|
spec |= uint(max24(hint)) << 136;
|
|
103
117
|
}
|
|
104
118
|
|
|
119
|
+
/// @notice Construct an exact-size block specification from a numeric key.
|
|
120
|
+
/// @dev Sets the minimum, maximum, and allocation hint to `size`.
|
|
121
|
+
/// @param blockkey Numeric block key.
|
|
122
|
+
/// @param size Exact payload length and initial per-block payload capacity.
|
|
123
|
+
/// @return spec Packed exact-size block specification.
|
|
124
|
+
function create(uint32 blockkey, uint32 size) internal pure returns (uint spec) {
|
|
125
|
+
return create(blockkey, size, size, size);
|
|
126
|
+
}
|
|
127
|
+
|
|
105
128
|
/// @notice Decode the block key and accepted payload range from `spec`.
|
|
106
129
|
/// @param spec Packed block specification.
|
|
107
130
|
/// @return blockkey Encoded block key.
|
|
@@ -215,4 +238,5 @@ library Specs {
|
|
|
215
238
|
function group(uint spec, uint8 n) internal pure returns (uint) {
|
|
216
239
|
return replace8(spec, 128, n);
|
|
217
240
|
}
|
|
241
|
+
|
|
218
242
|
}
|
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
|
// -------------------------------------------------------------------------
|
|
@@ -291,6 +291,23 @@ library Writers {
|
|
|
291
291
|
Blocks.writeHostAccountAsset(writer.dst, i, host, account, asset);
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
/// @notice Append a POSITION block.
|
|
295
|
+
function appendPosition(
|
|
296
|
+
Writer memory writer,
|
|
297
|
+
bytes32 asset,
|
|
298
|
+
uint amount,
|
|
299
|
+
bytes32 liability,
|
|
300
|
+
uint debt
|
|
301
|
+
) internal pure {
|
|
302
|
+
uint i = reserve(writer, Sizes.Position);
|
|
303
|
+
Blocks.writePosition(writer.dst, i, asset, amount, liability, debt);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/// @notice Append a structured POSITION value.
|
|
307
|
+
function appendPosition(Writer memory writer, Position memory value) internal pure {
|
|
308
|
+
appendPosition(writer, value.asset, value.amount, value.liability, value.debt);
|
|
309
|
+
}
|
|
310
|
+
|
|
294
311
|
/// @notice Append a TRANSACTION block.
|
|
295
312
|
/// @param writer Destination writer.
|
|
296
313
|
/// @param from Debit account identifier.
|
|
@@ -448,18 +465,16 @@ library Writers {
|
|
|
448
465
|
|
|
449
466
|
/// @notice Append a LABEL block.
|
|
450
467
|
/// @param writer Destination writer.
|
|
451
|
-
/// @param id Node identifier to encode.
|
|
452
468
|
/// @param namespace Label namespace to encode.
|
|
453
469
|
/// @param name Label text to encode.
|
|
454
470
|
function appendLabel(
|
|
455
471
|
Writer memory writer,
|
|
456
|
-
uint id,
|
|
457
472
|
bytes32 namespace,
|
|
458
473
|
string memory name
|
|
459
474
|
) internal pure {
|
|
460
|
-
uint size = Sizes.
|
|
475
|
+
uint size = Sizes.B32 + Sizes.Header + bytes(name).length;
|
|
461
476
|
uint i = reserve(writer, size);
|
|
462
|
-
Blocks.writeLabel(writer.dst, i,
|
|
477
|
+
Blocks.writeLabel(writer.dst, i, namespace, name);
|
|
463
478
|
}
|
|
464
479
|
|
|
465
480
|
/// @notice Append a SCHEMA block.
|