@rootzero/contracts 0.9.9 → 1.0.1
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/Endpoints.sol +2 -0
- package/Events.sol +1 -0
- package/README.md +19 -18
- package/blocks/Cursors.sol +104 -52
- package/blocks/Keys.sol +6 -0
- package/blocks/Schema.sol +4 -2
- package/blocks/Writers.sol +4 -4
- package/commands/Burn.sol +4 -1
- package/commands/Credit.sol +4 -1
- package/commands/Debit.sol +4 -1
- package/commands/Deposit.sol +8 -2
- package/commands/Payout.sol +7 -3
- package/commands/Provision.sol +8 -2
- package/commands/Relay.sol +57 -0
- package/commands/Withdraw.sol +4 -1
- package/commands/admin/AllowAssets.sol +6 -1
- package/commands/admin/Allowance.sol +4 -1
- package/commands/admin/Appoint.sol +4 -1
- package/commands/admin/Authorize.sol +4 -1
- package/commands/admin/DenyAssets.sol +6 -1
- package/commands/admin/Destroy.sol +4 -2
- package/commands/admin/Dismiss.sol +4 -1
- package/commands/admin/Execute.sol +5 -2
- package/commands/admin/Init.sol +4 -2
- package/commands/admin/Unauthorize.sol +4 -1
- package/core/Host.sol +10 -1
- package/core/Pipeline.sol +2 -1
- package/core/Runtime.sol +3 -3
- package/events/Admin.sol +5 -5
- package/events/Chain.sol +20 -0
- package/events/Command.sol +5 -5
- package/guards/Revoke.sol +1 -1
- package/package.json +1 -1
- package/peer/AllowAssets.sol +3 -1
- package/peer/Allowance.sol +3 -1
- package/peer/BalancePull.sol +3 -1
- package/peer/DenyAssets.sol +3 -1
- package/peer/Dispatch.sol +50 -0
- package/peer/Pipe.sol +5 -3
- package/peer/Settle.sol +3 -1
- package/queries/Assets.sol +1 -1
- package/queries/Balances.sol +1 -1
- package/queries/Positions.sol +1 -1
- package/utils/Accounts.sol +1 -34
- package/utils/Assets.sol +21 -21
- package/utils/Ids.sol +12 -2
- package/utils/Layout.sol +21 -17
- package/utils/Utils.sol +2 -2
package/Endpoints.sol
CHANGED
|
@@ -16,6 +16,7 @@ import { DebitAccount, DebitAccountHook } from "./commands/Debit.sol";
|
|
|
16
16
|
import { Deposit, DepositHook, DepositPayable, DepositPayableHook } from "./commands/Deposit.sol";
|
|
17
17
|
import { Payout, PayoutHook } from "./commands/Payout.sol";
|
|
18
18
|
import { Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook } from "./commands/Provision.sol";
|
|
19
|
+
import { RelayPayable, RelayPayableHook } from "./commands/Relay.sol";
|
|
19
20
|
import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
|
|
20
21
|
|
|
21
22
|
// Admin commands
|
|
@@ -37,6 +38,7 @@ import { PeerAllowance } from "./peer/Allowance.sol";
|
|
|
37
38
|
import { PeerBalancePull, BalancePullHook } from "./peer/BalancePull.sol";
|
|
38
39
|
import { PeerDenyAssets } from "./peer/DenyAssets.sol";
|
|
39
40
|
import { PeerPipePayable } from "./peer/Pipe.sol";
|
|
41
|
+
import { PeerDispatchPayable } from "./peer/Dispatch.sol";
|
|
40
42
|
import { PeerSettle } from "./peer/Settle.sol";
|
|
41
43
|
|
|
42
44
|
// Guard endpoints
|
package/Events.sol
CHANGED
|
@@ -8,6 +8,7 @@ import { AdminEvent } from "./events/Admin.sol";
|
|
|
8
8
|
import { AssetStatusEvent } from "./events/Asset.sol";
|
|
9
9
|
import { Actions } from "./utils/Actions.sol";
|
|
10
10
|
import { BalanceEvent } from "./events/Balance.sol";
|
|
11
|
+
import { ChainEvent } from "./events/Chain.sol";
|
|
11
12
|
import { CommandEvent } from "./events/Command.sol";
|
|
12
13
|
import { PositionEvent } from "./events/Position.sol";
|
|
13
14
|
import { ReceivedEvent } from "./events/Received.sol";
|
package/README.md
CHANGED
|
@@ -8,11 +8,11 @@ It contains the reusable contracts, utilities, cursor parsers, and encoding help
|
|
|
8
8
|
|
|
9
9
|
Most consumers should start from the package root entry points:
|
|
10
10
|
|
|
11
|
-
- `@rootzero/contracts/Core.sol`
|
|
12
|
-
- `@rootzero/contracts/Endpoints.sol`
|
|
13
|
-
- `@rootzero/contracts/Cursors.sol`
|
|
14
|
-
- `@rootzero/contracts/Utils.sol`
|
|
15
|
-
- `@rootzero/contracts/Events.sol`
|
|
11
|
+
- `@rootzero/contracts/Core.sol` - host, access control, balances, and validator building blocks
|
|
12
|
+
- `@rootzero/contracts/Endpoints.sol` - command, peer, guard, and query base contracts plus standard endpoint mixins
|
|
13
|
+
- `@rootzero/contracts/Cursors.sol` - cursor reader (`Cur`), block schemas, key constants, typed block helpers, and writers
|
|
14
|
+
- `@rootzero/contracts/Utils.sol` - IDs, assets, accounts, layout, and value helpers
|
|
15
|
+
- `@rootzero/contracts/Events.sol` - reusable event emitters and event contracts
|
|
16
16
|
|
|
17
17
|
## Block Wire Format
|
|
18
18
|
|
|
@@ -28,7 +28,7 @@ All request and response data is encoded as a binary block stream. Each block is
|
|
|
28
28
|
|
|
29
29
|
Protocol blocks use schema strings and four-byte keys:
|
|
30
30
|
|
|
31
|
-
- `Schemas` describes semantic protocol blocks such as `#amount`, `#balance`, `#custody`, and `#
|
|
31
|
+
- `Schemas` describes semantic protocol blocks such as `#amount`, `#balance`, `#custody`, and `#relay`.
|
|
32
32
|
- `Forms` describes reusable structural blocks such as `#accountAsset` and `#accountAmount`, mostly used by queries.
|
|
33
33
|
- `Keys` contains the runtime `bytes4` keys derived from block names.
|
|
34
34
|
|
|
@@ -77,21 +77,21 @@ abstract contract ExampleCommand is CommandBase {
|
|
|
77
77
|
uint internal immutable myCommandId = commandId(NAME);
|
|
78
78
|
|
|
79
79
|
constructor() {
|
|
80
|
-
emit Command(host, myCommandId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false);
|
|
80
|
+
emit Command(host, myCommandId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, false);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
function myCommand(
|
|
84
84
|
CommandContext calldata c
|
|
85
85
|
) external onlyCommand returns (bytes memory) {
|
|
86
|
-
(Cur memory request, uint groups) =
|
|
86
|
+
(Cur memory request, uint groups, ) = Cursors.init(c.request, 0, 1);
|
|
87
87
|
Writer memory writer = Writers.allocBalances(groups);
|
|
88
88
|
|
|
89
|
-
while (request.i < request.
|
|
89
|
+
while (request.i < request.len) {
|
|
90
90
|
(bytes32 asset, bytes32 meta, uint amount) = request.unpackAmount();
|
|
91
91
|
writer.appendBalance(asset, meta, amount);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
request.
|
|
94
|
+
request.complete();
|
|
95
95
|
return writer.finish();
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -99,14 +99,15 @@ abstract contract ExampleCommand is CommandBase {
|
|
|
99
99
|
|
|
100
100
|
## Repo Layout
|
|
101
101
|
|
|
102
|
-
- `contracts/core`
|
|
103
|
-
- `contracts/commands`
|
|
104
|
-
- `contracts/peer`
|
|
105
|
-
- `contracts/
|
|
106
|
-
- `contracts/
|
|
107
|
-
- `contracts/
|
|
108
|
-
- `contracts/
|
|
109
|
-
- `
|
|
102
|
+
- `contracts/core` - host, access control, balances, operation base, and signature validation
|
|
103
|
+
- `contracts/commands` - standard command building blocks and admin commands
|
|
104
|
+
- `contracts/peer` - peer protocol surfaces for inter-host asset flows and asset allow/deny
|
|
105
|
+
- `contracts/guards` - guard action surfaces for delegated protection flows
|
|
106
|
+
- `contracts/queries` - read-only query endpoints for protocol state
|
|
107
|
+
- `contracts/blocks` - block stream schema (`Schema`), cursor parsing (`Cursors`), and writers (`Writers`)
|
|
108
|
+
- `contracts/utils` - shared encoding helpers: IDs, assets, accounts, layout, ECDSA
|
|
109
|
+
- `contracts/events` - protocol event contracts and emitters
|
|
110
|
+
- `docs` - introductory documentation
|
|
110
111
|
|
|
111
112
|
## Install and Compile
|
|
112
113
|
|
package/blocks/Cursors.sol
CHANGED
|
@@ -108,26 +108,6 @@ library Cursors {
|
|
|
108
108
|
if (groups != expectedGroups) revert BadRatio();
|
|
109
109
|
}
|
|
110
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.
|
|
123
|
-
/// @param source Calldata slice that forms the block stream.
|
|
124
|
-
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
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);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
111
|
/// @notice Move the cursor to an absolute position within the source region.
|
|
132
112
|
/// @param cur Cursor to update.
|
|
133
113
|
/// @param i New read position (byte offset relative to source start).
|
|
@@ -571,16 +551,34 @@ library Cursors {
|
|
|
571
551
|
/// @param value Native value assigned to the pipe.
|
|
572
552
|
/// @param account Command account identifier.
|
|
573
553
|
/// @param state Embedded state block stream.
|
|
574
|
-
/// @param
|
|
554
|
+
/// @param steps Embedded step block stream.
|
|
575
555
|
/// @return Encoded PIPE block bytes.
|
|
576
556
|
function toPipeBlock(
|
|
577
557
|
uint value,
|
|
578
558
|
bytes32 account,
|
|
579
559
|
bytes memory state,
|
|
580
|
-
bytes memory
|
|
560
|
+
bytes memory steps
|
|
581
561
|
) internal pure returns (bytes memory) {
|
|
582
|
-
return createBlock(Keys.Pipe, bytes.concat(bytes32(value), toContextBlock(account, state,
|
|
583
|
-
}
|
|
562
|
+
return createBlock(Keys.Pipe, bytes.concat(bytes32(value), toContextBlock(account, state, steps)));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/// @notice Encode a RELAY block.
|
|
566
|
+
/// @param chain Destination chain node ID.
|
|
567
|
+
/// @param resources Chain-adapter-specific resources for the destination pipe.
|
|
568
|
+
/// @param steps Nested step block stream.
|
|
569
|
+
/// @return Encoded RELAY block bytes.
|
|
570
|
+
function toRelayBlock(uint chain, uint resources, bytes memory steps) internal pure returns (bytes memory) {
|
|
571
|
+
return createBlock(Keys.Relay, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(steps)));
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/// @notice Encode a DISPATCH block.
|
|
575
|
+
/// @param chain Destination chain node ID.
|
|
576
|
+
/// @param resources Chain-adapter-specific resources for the destination dispatch.
|
|
577
|
+
/// @param payload Encoded cross-chain payload.
|
|
578
|
+
/// @return Encoded DISPATCH block bytes.
|
|
579
|
+
function toDispatchBlock(uint chain, uint resources, bytes memory payload) internal pure returns (bytes memory) {
|
|
580
|
+
return createBlock(Keys.Dispatch, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(payload)));
|
|
581
|
+
}
|
|
584
582
|
|
|
585
583
|
// -------------------------------------------------------------------------
|
|
586
584
|
// Raw calldata loaders
|
|
@@ -592,19 +590,31 @@ library Cursors {
|
|
|
592
590
|
/// @param cur Cursor whose current position is advanced by `n` bytes.
|
|
593
591
|
/// @param n Number of bytes to advance.
|
|
594
592
|
/// @return value Loaded word.
|
|
595
|
-
function read(Cur memory cur, uint n) internal pure returns (bytes32 value) {
|
|
596
|
-
uint abs = cur.offset + cur.i;
|
|
597
|
-
assembly ("memory-safe") {
|
|
598
|
-
value := calldataload(abs)
|
|
599
|
-
}
|
|
600
|
-
cur.i += n;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
/// @notice Read the next
|
|
604
|
-
/// @dev Performs no bounds, key, length, or cursor checks.
|
|
605
|
-
/// @param cur Cursor whose current position is advanced by
|
|
606
|
-
/// @return value Loaded
|
|
607
|
-
function
|
|
593
|
+
function read(Cur memory cur, uint n) internal pure returns (bytes32 value) {
|
|
594
|
+
uint abs = cur.offset + cur.i;
|
|
595
|
+
assembly ("memory-safe") {
|
|
596
|
+
value := calldataload(abs)
|
|
597
|
+
}
|
|
598
|
+
cur.i += n;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/// @notice Read the next 4 bytes from the cursor and advance by 4 bytes.
|
|
602
|
+
/// @dev Performs no bounds, key, length, or cursor checks.
|
|
603
|
+
/// @param cur Cursor whose current position is advanced by 4 bytes.
|
|
604
|
+
/// @return value Loaded bytes4 value.
|
|
605
|
+
function read4(Cur memory cur) internal pure returns (bytes4 value) {
|
|
606
|
+
uint abs = cur.offset + cur.i;
|
|
607
|
+
assembly ("memory-safe") {
|
|
608
|
+
value := calldataload(abs)
|
|
609
|
+
}
|
|
610
|
+
cur.i += 4;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/// @notice Read the next 16 bytes from the cursor and advance by 16 bytes.
|
|
614
|
+
/// @dev Performs no bounds, key, length, or cursor checks.
|
|
615
|
+
/// @param cur Cursor whose current position is advanced by 16 bytes.
|
|
616
|
+
/// @return value Loaded bytes16 value.
|
|
617
|
+
function read16(Cur memory cur) internal pure returns (bytes16 value) {
|
|
608
618
|
uint abs = cur.offset + cur.i;
|
|
609
619
|
assembly ("memory-safe") {
|
|
610
620
|
value := calldataload(abs)
|
|
@@ -616,18 +626,30 @@ library Cursors {
|
|
|
616
626
|
/// @dev Performs no bounds, key, length, or cursor checks.
|
|
617
627
|
/// @param cur Cursor whose current position is advanced by 32 bytes.
|
|
618
628
|
/// @return value Loaded word.
|
|
619
|
-
function read32(Cur memory cur) internal pure returns (bytes32 value) {
|
|
620
|
-
uint abs = cur.offset + cur.i;
|
|
621
|
-
assembly ("memory-safe") {
|
|
622
|
-
value := calldataload(abs)
|
|
623
|
-
}
|
|
624
|
-
cur.i += 32;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/// @notice Read the next
|
|
628
|
-
/// @dev Performs no bounds, key, length, or cursor checks.
|
|
629
|
-
/// @param cur Cursor whose current position is advanced by
|
|
630
|
-
/// @return
|
|
629
|
+
function read32(Cur memory cur) internal pure returns (bytes32 value) {
|
|
630
|
+
uint abs = cur.offset + cur.i;
|
|
631
|
+
assembly ("memory-safe") {
|
|
632
|
+
value := calldataload(abs)
|
|
633
|
+
}
|
|
634
|
+
cur.i += 32;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/// @notice Read the next uint from the cursor and advance by one word.
|
|
638
|
+
/// @dev Performs no bounds, key, length, or cursor checks.
|
|
639
|
+
/// @param cur Cursor whose current position is advanced by 32 bytes.
|
|
640
|
+
/// @return value Loaded uint value.
|
|
641
|
+
function readUint(Cur memory cur) internal pure returns (uint value) {
|
|
642
|
+
uint abs = cur.offset + cur.i;
|
|
643
|
+
assembly ("memory-safe") {
|
|
644
|
+
value := calldataload(abs)
|
|
645
|
+
}
|
|
646
|
+
cur.i += 32;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/// @notice Read the next two 32-byte words from the cursor and advance by 64 bytes.
|
|
650
|
+
/// @dev Performs no bounds, key, length, or cursor checks.
|
|
651
|
+
/// @param cur Cursor whose current position is advanced by 64 bytes.
|
|
652
|
+
/// @return a First loaded word.
|
|
631
653
|
/// @return b Second loaded word.
|
|
632
654
|
function read64(Cur memory cur) internal pure returns (bytes32 a, bytes32 b) {
|
|
633
655
|
uint abs = cur.offset + cur.i;
|
|
@@ -1102,16 +1124,46 @@ library Cursors {
|
|
|
1102
1124
|
/// @return value Native value assigned to the pipe.
|
|
1103
1125
|
/// @return account Command account identifier.
|
|
1104
1126
|
/// @return state Embedded state block stream.
|
|
1105
|
-
/// @return
|
|
1127
|
+
/// @return steps Embedded step block stream.
|
|
1106
1128
|
function unpackPipe(
|
|
1107
1129
|
Cur memory cur
|
|
1108
|
-
) internal pure returns (uint value, bytes32 account, bytes calldata state, bytes calldata
|
|
1130
|
+
) internal pure returns (uint value, bytes32 account, bytes calldata state, bytes calldata steps) {
|
|
1109
1131
|
uint end = cur.enter(Keys.Pipe, 32 + Sizes.Header + 32 + 2 * Sizes.Header, 0);
|
|
1110
1132
|
value = uint(cur.read32());
|
|
1111
|
-
(account, state,
|
|
1133
|
+
(account, state, steps) = cur.unpackContext();
|
|
1112
1134
|
cur.exit(end);
|
|
1113
1135
|
}
|
|
1114
1136
|
|
|
1137
|
+
/// @notice Consume a RELAY block and return its destination chain, resources, and step stream.
|
|
1138
|
+
/// @param cur Cursor; advanced past the block.
|
|
1139
|
+
/// @return chain Destination chain node ID.
|
|
1140
|
+
/// @return resources Chain-adapter-specific resources for the destination pipe.
|
|
1141
|
+
/// @return steps Embedded step block stream.
|
|
1142
|
+
function unpackRelay(
|
|
1143
|
+
Cur memory cur
|
|
1144
|
+
) internal pure returns (uint chain, uint resources, bytes calldata steps) {
|
|
1145
|
+
uint end = cur.enter(Keys.Relay, 64 + Sizes.Header, 0);
|
|
1146
|
+
chain = cur.readUint();
|
|
1147
|
+
resources = cur.readUint();
|
|
1148
|
+
steps = cur.unpackBytes();
|
|
1149
|
+
cur.exit(end);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/// @notice Consume a DISPATCH block and return its destination chain, resources, and payload.
|
|
1153
|
+
/// @param cur Cursor; advanced past the block.
|
|
1154
|
+
/// @return chain Destination chain node ID.
|
|
1155
|
+
/// @return resources Chain-adapter-specific resources for the destination dispatch.
|
|
1156
|
+
/// @return payload Encoded cross-chain payload.
|
|
1157
|
+
function unpackDispatch(
|
|
1158
|
+
Cur memory cur
|
|
1159
|
+
) internal pure returns (uint chain, uint resources, bytes calldata payload) {
|
|
1160
|
+
uint end = cur.enter(Keys.Dispatch, 64 + Sizes.Header, 0);
|
|
1161
|
+
chain = cur.readUint();
|
|
1162
|
+
resources = cur.readUint();
|
|
1163
|
+
payload = cur.unpackBytes();
|
|
1164
|
+
cur.exit(end);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1115
1167
|
// Type-specific validators
|
|
1116
1168
|
|
|
1117
1169
|
/// @notice Validate an AUTH block at position `i` and extract deadline and proof.
|
package/blocks/Keys.sol
CHANGED
|
@@ -7,6 +7,8 @@ pragma solidity ^0.8.33;
|
|
|
7
7
|
library Keys {
|
|
8
8
|
/// @dev Empty / unset key.
|
|
9
9
|
bytes4 constant Empty = bytes4(0);
|
|
10
|
+
/// @dev Wildcard key used in discovery when any block stream is accepted.
|
|
11
|
+
bytes4 constant Any = 0xffffffff;
|
|
10
12
|
/// @dev Input amount - (bytes32 asset, bytes32 meta, uint amount)
|
|
11
13
|
bytes4 constant Amount = bytes4(keccak256("#amount"));
|
|
12
14
|
/// @dev Ledger balance - (bytes32 asset, bytes32 meta, uint amount)
|
|
@@ -37,6 +39,10 @@ library Keys {
|
|
|
37
39
|
bytes4 constant Transaction = bytes4(keccak256("#transaction"));
|
|
38
40
|
/// @dev Sub-command invocation - (uint target, uint value, #bytes as request)
|
|
39
41
|
bytes4 constant Step = bytes4(keccak256("#step"));
|
|
42
|
+
/// @dev Cross-chain pipe relay - (uint chain, uint resources, #bytes as steps)
|
|
43
|
+
bytes4 constant Relay = bytes4(keccak256("#relay"));
|
|
44
|
+
/// @dev Cross-chain encoded payload dispatch - (uint chain, uint resources, #bytes as payload)
|
|
45
|
+
bytes4 constant Dispatch = bytes4(keccak256("#dispatch"));
|
|
40
46
|
/// @dev Raw external call - (uint target, uint value, #bytes as payload)
|
|
41
47
|
bytes4 constant Call = bytes4(keccak256("#call"));
|
|
42
48
|
/// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
|
package/blocks/Schema.sol
CHANGED
|
@@ -12,7 +12,7 @@ pragma solidity ^0.8.33;
|
|
|
12
12
|
// - commas separate siblings at every level
|
|
13
13
|
// - braces define parent-child boundaries
|
|
14
14
|
// - command requests start with the input run when the request schema is non-empty
|
|
15
|
-
// -
|
|
15
|
+
// - postcheck command requests include a constraint run after the input run; if the
|
|
16
16
|
// request schema is empty, the constraint run starts the request
|
|
17
17
|
// - command state starts with the active state run; trailing state globals may follow
|
|
18
18
|
// - run items may repeat at top level for batching
|
|
@@ -62,9 +62,11 @@ library Schemas {
|
|
|
62
62
|
string constant Allowance = "#allowance { uint host, bytes32 asset, bytes32 meta, uint amount }";
|
|
63
63
|
string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount }";
|
|
64
64
|
string constant Context = "#context { bytes32 account, #bytes as state, #bytes as request }";
|
|
65
|
-
string constant Pipe = "#pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as
|
|
65
|
+
string constant Pipe = "#pipe { uint value, #context { bytes32 account, #bytes as state, #bytes as steps } }";
|
|
66
66
|
string constant Call = "#call { uint target, uint value, #bytes as payload }";
|
|
67
67
|
string constant Step = "#step { uint target, uint value, #bytes as request }";
|
|
68
|
+
string constant Relay = "#relay { uint chain, uint resources, #bytes as steps }";
|
|
69
|
+
string constant Dispatch = "#dispatch { uint chain, uint resources, #bytes as payload }";
|
|
68
70
|
string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
|
|
69
71
|
string constant Fee = "#fee { uint amount }";
|
|
70
72
|
string constant Auth = "#auth { uint cid, uint deadline, #bytes as proof }";
|
package/blocks/Writers.sol
CHANGED
|
@@ -894,16 +894,16 @@ library Writers {
|
|
|
894
894
|
/// @param value Native value assigned to the pipe.
|
|
895
895
|
/// @param account Command account identifier.
|
|
896
896
|
/// @param state Raw nested state payload.
|
|
897
|
-
/// @param
|
|
897
|
+
/// @param steps Raw nested step payload.
|
|
898
898
|
function appendPipe(
|
|
899
899
|
Writer memory writer,
|
|
900
900
|
uint value,
|
|
901
901
|
bytes32 account,
|
|
902
902
|
bytes memory state,
|
|
903
|
-
bytes memory
|
|
903
|
+
bytes memory steps
|
|
904
904
|
) internal pure {
|
|
905
905
|
uint i = writer.i;
|
|
906
|
-
uint len = 64 + 3 * Sizes.Header + state.length +
|
|
906
|
+
uint len = 64 + 3 * Sizes.Header + state.length + steps.length;
|
|
907
907
|
uint next = i + Sizes.Header + len;
|
|
908
908
|
i = reserve(writer, next, next);
|
|
909
909
|
|
|
@@ -912,7 +912,7 @@ library Writers {
|
|
|
912
912
|
mstore(add(p, 0x08), value)
|
|
913
913
|
}
|
|
914
914
|
|
|
915
|
-
writeBlock32BytesBytes(writer.dst, i + Sizes.Header + 32, Keys.Context, account, state,
|
|
915
|
+
writeBlock32BytesBytes(writer.dst, i + Sizes.Header + 32, Keys.Context, account, state, steps);
|
|
916
916
|
}
|
|
917
917
|
|
|
918
918
|
/// @notice Append a STATUS form block.
|
package/commands/Burn.sol
CHANGED
|
@@ -28,8 +28,11 @@ abstract contract Burn is CommandBase, BurnHook {
|
|
|
28
28
|
emit Command(host, burnId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/// @notice Burn each BALANCE block from the command state.
|
|
32
|
+
/// @param c Command context; `c.state` must contain BALANCE blocks.
|
|
33
|
+
/// @return Empty output state.
|
|
31
34
|
function burn(CommandContext calldata c) external onlyCommand returns (bytes memory) {
|
|
32
|
-
(Cur memory state, ) = Cursors.
|
|
35
|
+
(Cur memory state, , ) = Cursors.init(c.state, 0, 1);
|
|
33
36
|
|
|
34
37
|
while (state.i < state.len) {
|
|
35
38
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
package/commands/Credit.sol
CHANGED
|
@@ -28,10 +28,13 @@ abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
|
28
28
|
emit Command(host, creditAccountId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/// @notice Credit each BALANCE block from the command state to the command account.
|
|
32
|
+
/// @param c Command context; `c.state` must contain BALANCE blocks.
|
|
33
|
+
/// @return Empty output state.
|
|
31
34
|
function creditAccount(
|
|
32
35
|
CommandContext calldata c
|
|
33
36
|
) external onlyCommand returns (bytes memory) {
|
|
34
|
-
(Cur memory state, ) = Cursors.
|
|
37
|
+
(Cur memory state, , ) = Cursors.init(c.state, 0, 1);
|
|
35
38
|
|
|
36
39
|
while (state.i < state.len) {
|
|
37
40
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
package/commands/Debit.sol
CHANGED
|
@@ -34,7 +34,7 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
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) = Cursors.
|
|
37
|
+
(Cur memory input, uint groups, ) = Cursors.init(request, 0, 1);
|
|
38
38
|
Writer memory writer = Writers.allocBalances(groups);
|
|
39
39
|
|
|
40
40
|
while (input.i < input.len) {
|
|
@@ -47,6 +47,9 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
47
47
|
return writer.finish();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/// @notice Debit AMOUNT request blocks from the command account and output matching BALANCE blocks.
|
|
51
|
+
/// @param c Command context; `c.request` must contain AMOUNT blocks.
|
|
52
|
+
/// @return BALANCE block stream matching the debited amounts.
|
|
50
53
|
function debitAccount(
|
|
51
54
|
CommandContext calldata c
|
|
52
55
|
) external onlyCommand returns (bytes memory) {
|
package/commands/Deposit.sol
CHANGED
|
@@ -45,10 +45,13 @@ abstract contract Deposit is CommandBase, DepositHook {
|
|
|
45
45
|
emit Command(host, depositId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, false);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/// @notice Deposit AMOUNT request blocks into the command account and output matching BALANCE blocks.
|
|
49
|
+
/// @param c Command context; `c.request` must contain AMOUNT blocks.
|
|
50
|
+
/// @return BALANCE block stream matching the deposited amounts.
|
|
48
51
|
function deposit(
|
|
49
52
|
CommandContext calldata c
|
|
50
53
|
) external onlyCommand returns (bytes memory) {
|
|
51
|
-
(Cur memory request, uint groups) = Cursors.
|
|
54
|
+
(Cur memory request, uint groups, ) = Cursors.init(c.request, 0, 1);
|
|
52
55
|
Writer memory writer = Writers.allocBalances(groups);
|
|
53
56
|
|
|
54
57
|
while (request.i < request.len) {
|
|
@@ -74,10 +77,13 @@ abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
|
|
|
74
77
|
emit Command(host, depositPayableId, NAME, "1:0:1", Schemas.Amount, Keys.Empty, Keys.Balance, false, true);
|
|
75
78
|
}
|
|
76
79
|
|
|
80
|
+
/// @notice Deposit AMOUNT request blocks with access to a mutable native-value budget.
|
|
81
|
+
/// @param c Command context; `c.request` must contain AMOUNT blocks.
|
|
82
|
+
/// @return BALANCE block stream matching the deposited amounts.
|
|
77
83
|
function depositPayable(
|
|
78
84
|
CommandContext calldata c
|
|
79
85
|
) external payable onlyCommand returns (bytes memory) {
|
|
80
|
-
(Cur memory request, uint groups) = Cursors.
|
|
86
|
+
(Cur memory request, uint groups, ) = Cursors.init(c.request, 0, 1);
|
|
81
87
|
Writer memory writer = Writers.allocBalances(groups);
|
|
82
88
|
Budget memory budget = valueBudget();
|
|
83
89
|
|
package/commands/Payout.sol
CHANGED
|
@@ -3,6 +3,7 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {CommandContext, CommandBase, Keys} from "./Base.sol";
|
|
5
5
|
import {Cursors, Cur, Schemas} from "../Cursors.sol";
|
|
6
|
+
import {Accounts} from "../utils/Accounts.sol";
|
|
6
7
|
|
|
7
8
|
using Cursors for Cur;
|
|
8
9
|
|
|
@@ -29,13 +30,16 @@ abstract contract Payout is CommandBase, PayoutHook {
|
|
|
29
30
|
emit Command(host, payoutId, NAME, "1:1:0", Schemas.Account, Keys.Balance, Keys.Empty, false, false);
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
/// @notice Pay out BALANCE state blocks to matching ACCOUNT request blocks.
|
|
34
|
+
/// @param c Command context; `c.state` must contain BALANCE blocks and `c.request` matching ACCOUNT blocks.
|
|
35
|
+
/// @return Empty output state.
|
|
32
36
|
function payout(CommandContext calldata c) external onlyCommand returns (bytes memory) {
|
|
33
|
-
(Cur memory state, uint groups) = Cursors.
|
|
34
|
-
Cur memory request = Cursors.
|
|
37
|
+
(Cur memory state, uint groups, ) = Cursors.init(c.state, 0, 1);
|
|
38
|
+
(Cur memory request, ) = Cursors.init(c.request, 0, 1, groups);
|
|
35
39
|
|
|
36
40
|
while (state.i < state.len) {
|
|
37
41
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
|
38
|
-
bytes32 to = request.unpackAccount();
|
|
42
|
+
bytes32 to = Accounts.ensure(request.unpackAccount());
|
|
39
43
|
payout(c.account, to, asset, meta, amount);
|
|
40
44
|
}
|
|
41
45
|
|
package/commands/Provision.sol
CHANGED
|
@@ -41,8 +41,11 @@ abstract contract Provision is CommandBase, ProvisionHook {
|
|
|
41
41
|
emit Command(host, provisionId, NAME, "1:0:1", Schemas.Allocation, Keys.Empty, Keys.Custody, false, false);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/// @notice Provision ALLOCATION request blocks and output matching CUSTODY state blocks.
|
|
45
|
+
/// @param c Command context; `c.request` must contain ALLOCATION blocks.
|
|
46
|
+
/// @return CUSTODY block stream matching the provisioned allocations.
|
|
44
47
|
function provision(CommandContext calldata c) external onlyCommand returns (bytes memory) {
|
|
45
|
-
(Cur memory request, uint groups) = Cursors.
|
|
48
|
+
(Cur memory request, uint groups, ) = Cursors.init(c.request, 0, 1);
|
|
46
49
|
Writer memory writer = Writers.allocCustodies(groups);
|
|
47
50
|
|
|
48
51
|
while (request.i < request.len) {
|
|
@@ -69,10 +72,13 @@ abstract contract ProvisionPayable is CommandBase, Payable, ProvisionPayableHook
|
|
|
69
72
|
emit Command(host, provisionPayableId, NAME, "1:0:1", Schemas.Allocation, Keys.Empty, Keys.Custody, false, true);
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
/// @notice Provision ALLOCATION request blocks with access to a mutable native-value budget.
|
|
76
|
+
/// @param c Command context; `c.request` must contain ALLOCATION blocks.
|
|
77
|
+
/// @return CUSTODY block stream matching the provisioned allocations.
|
|
72
78
|
function provisionPayable(
|
|
73
79
|
CommandContext calldata c
|
|
74
80
|
) external payable onlyCommand returns (bytes memory) {
|
|
75
|
-
(Cur memory request, uint groups) = Cursors.
|
|
81
|
+
(Cur memory request, uint groups, ) = Cursors.init(c.request, 0, 1);
|
|
76
82
|
Writer memory writer = Writers.allocCustodies(groups);
|
|
77
83
|
Budget memory budget = valueBudget();
|
|
78
84
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {CommandBase, CommandContext, Keys} from "./Base.sol";
|
|
5
|
+
import {Payable} from "../core/Payable.sol";
|
|
6
|
+
import {Cursors, Cur, Schemas} from "../Cursors.sol";
|
|
7
|
+
import {Budget} from "../utils/Value.sol";
|
|
8
|
+
|
|
9
|
+
using Cursors for Cur;
|
|
10
|
+
|
|
11
|
+
abstract contract RelayPayableHook {
|
|
12
|
+
/// @notice Override to relay `steps` to `chain` with the current account and state.
|
|
13
|
+
/// @param chain Destination chain node ID.
|
|
14
|
+
/// @param resources Chain-adapter-specific destination resources. EVM adapters
|
|
15
|
+
/// may interpret this as packed execution gas and destination value.
|
|
16
|
+
/// @param account Command account identifier.
|
|
17
|
+
/// @param state Current command state block stream.
|
|
18
|
+
/// @param steps Embedded destination step block stream.
|
|
19
|
+
/// @param budget Source-chain native-value budget available for transport
|
|
20
|
+
/// fees and destination resource funding.
|
|
21
|
+
function relay(
|
|
22
|
+
uint chain,
|
|
23
|
+
uint resources,
|
|
24
|
+
bytes32 account,
|
|
25
|
+
bytes calldata state,
|
|
26
|
+
bytes calldata steps,
|
|
27
|
+
Budget memory budget
|
|
28
|
+
) internal virtual;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// @title RelayPayable
|
|
32
|
+
/// @notice Command that forwards one RELAY block to a host-defined relay hook.
|
|
33
|
+
/// Reverts unless the request contains exactly one RELAY block, preventing
|
|
34
|
+
/// the same state from being duplicated across multiple relays.
|
|
35
|
+
/// Produces no output state.
|
|
36
|
+
abstract contract RelayPayable is CommandBase, Payable, RelayPayableHook {
|
|
37
|
+
string private constant NAME = "relayPayable";
|
|
38
|
+
|
|
39
|
+
uint internal immutable relayPayableId = commandId(NAME);
|
|
40
|
+
|
|
41
|
+
constructor() {
|
|
42
|
+
emit Command(host, relayPayableId, NAME, "1:0:0", Schemas.Relay, Keys.Any, Keys.Empty, false, true);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// @notice Relay one RELAY request block with the command account and current state.
|
|
46
|
+
/// @param c Command context; `c.request` must contain exactly one RELAY block.
|
|
47
|
+
/// @return output Empty output state.
|
|
48
|
+
function relayPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory output) {
|
|
49
|
+
(Cur memory request, ) = Cursors.init(c.request, 0, 1, 1);
|
|
50
|
+
Budget memory budget = valueBudget();
|
|
51
|
+
|
|
52
|
+
(uint chain, uint resources, bytes calldata steps) = request.unpackRelay();
|
|
53
|
+
relay(chain, resources, c.account, c.state, steps, budget);
|
|
54
|
+
request.complete();
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
}
|
package/commands/Withdraw.sol
CHANGED
|
@@ -28,10 +28,13 @@ abstract contract Withdraw is CommandBase, WithdrawHook {
|
|
|
28
28
|
emit Command(host, withdrawId, NAME, "0:1:0", "", Keys.Balance, Keys.Empty, false, false);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/// @notice Withdraw each BALANCE block from the command state to the command account.
|
|
32
|
+
/// @param c Command context; `c.state` must contain BALANCE blocks.
|
|
33
|
+
/// @return Empty output state.
|
|
31
34
|
function withdraw(
|
|
32
35
|
CommandContext calldata c
|
|
33
36
|
) external onlyCommand returns (bytes memory) {
|
|
34
|
-
(Cur memory state, ) = Cursors.
|
|
37
|
+
(Cur memory state, , ) = Cursors.init(c.state, 0, 1);
|
|
35
38
|
|
|
36
39
|
while (state.i < state.len) {
|
|
37
40
|
(bytes32 asset, bytes32 meta, uint amount) = state.unpackBalance();
|
|
@@ -9,6 +9,8 @@ using Cursors for Cur;
|
|
|
9
9
|
abstract contract AllowAssetsHook {
|
|
10
10
|
/// @dev Override to allow a single asset/meta pair.
|
|
11
11
|
/// Called once per ASSET block in the request.
|
|
12
|
+
/// @param asset Asset identifier.
|
|
13
|
+
/// @param meta Asset metadata slot.
|
|
12
14
|
function allowAsset(bytes32 asset, bytes32 meta) internal virtual;
|
|
13
15
|
}
|
|
14
16
|
|
|
@@ -24,10 +26,13 @@ abstract contract AllowAssets is CommandBase, AdminEvent, AllowAssetsHook {
|
|
|
24
26
|
emit Admin(host, allowAssetsId, NAME, "1:0:0", Schemas.Asset, Keys.Empty, Keys.Empty, false, false);
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
/// @notice Allow each ASSET block in the admin request.
|
|
30
|
+
/// @param c Admin command context; `c.request` must contain ASSET blocks.
|
|
31
|
+
/// @return Empty output state.
|
|
27
32
|
function allowAssets(
|
|
28
33
|
CommandContext calldata c
|
|
29
34
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
30
|
-
(Cur memory request, ) = Cursors.
|
|
35
|
+
(Cur memory request, , ) = Cursors.init(c.request, 0, 1);
|
|
31
36
|
|
|
32
37
|
while (request.i < request.len) {
|
|
33
38
|
(bytes32 asset, bytes32 meta) = request.unpackAsset();
|
|
@@ -29,8 +29,11 @@ abstract contract Allowance is CommandBase, AdminEvent, AllowanceHook {
|
|
|
29
29
|
emit Admin(host, allowanceId, NAME, "1:0:0", Schemas.Allowance, Keys.Empty, Keys.Empty, false, false);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/// @notice Apply each ALLOWANCE block in the admin request.
|
|
33
|
+
/// @param c Admin command context; `c.request` must contain ALLOWANCE blocks.
|
|
34
|
+
/// @return Empty output state.
|
|
32
35
|
function allowance(CommandContext calldata c) external onlyAdmin(c.account) returns (bytes memory) {
|
|
33
|
-
(Cur memory request, ) = Cursors.
|
|
36
|
+
(Cur memory request, , ) = Cursors.init(c.request, 0, 1);
|
|
34
37
|
|
|
35
38
|
while (request.i < request.len) {
|
|
36
39
|
(uint peer, bytes32 asset, bytes32 meta, uint amount) = request.unpackAllowance();
|
|
@@ -19,10 +19,13 @@ abstract contract Appoint is CommandBase, AdminEvent {
|
|
|
19
19
|
emit Admin(host, appointId, NAME, "1:0:0", Schemas.Account, Keys.Empty, Keys.Empty, false, false);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/// @notice Appoint each ACCOUNT block in the admin request as a guardian.
|
|
23
|
+
/// @param c Admin command context; `c.request` must contain ACCOUNT blocks.
|
|
24
|
+
/// @return Empty output state.
|
|
22
25
|
function appoint(
|
|
23
26
|
CommandContext calldata c
|
|
24
27
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
25
|
-
(Cur memory request, ) = Cursors.
|
|
28
|
+
(Cur memory request, , ) = Cursors.init(c.request, 0, 1);
|
|
26
29
|
|
|
27
30
|
while (request.i < request.len) {
|
|
28
31
|
bytes32 account = request.unpackAccount();
|