@rootzero/contracts 1.6.0 → 1.7.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 +34 -1
- package/Endpoints.sol +13 -13
- package/Events.sol +2 -1
- package/README.md +9 -9
- package/blocks/Cursors.sol +36 -49
- package/blocks/Keys.sol +5 -5
- package/blocks/Schema.sol +4 -2
- package/blocks/Writers.sol +0 -35
- package/commands/Deposit.sol +2 -2
- package/commands/Provision.sol +2 -2
- package/commands/Recover.sol +48 -0
- package/commands/Relay.sol +4 -4
- package/commands/admin/Execute.sol +1 -1
- package/core/Commitments.sol +1 -1
- package/core/Payable.sol +15 -28
- package/core/Pipeline.sol +1 -1
- package/docs/Schema.md +13 -2
- package/events/Commitment.sol +4 -4
- package/events/Dispatch.sol +20 -0
- package/events/Port.sol +22 -0
- package/package.json +1 -1
- package/ports/AllowAssets.sol +44 -0
- package/ports/Allowance.sol +41 -0
- package/ports/Base.sol +41 -0
- package/ports/Credit.sol +39 -0
- package/ports/Debit.sol +39 -0
- package/ports/DenyAssets.sol +44 -0
- package/{peer → ports}/Dispatch.sol +13 -13
- package/ports/Pipe.sol +43 -0
- package/{peer → ports}/Redeem.sol +13 -13
- package/ports/Settle.sol +41 -0
- package/utils/Layout.sol +3 -3
- package/utils/Nodes.sol +21 -21
- package/utils/Value.sol +12 -5
- package/events/Peer.sol +0 -22
- package/peer/AllowAssets.sol +0 -44
- package/peer/Allowance.sol +0 -41
- package/peer/Base.sol +0 -41
- package/peer/Credit.sol +0 -39
- package/peer/Debit.sol +0 -39
- package/peer/DenyAssets.sol +0 -44
- package/peer/Pipe.sol +0 -44
- package/peer/Recover.sol +0 -51
- package/peer/Settle.sol +0 -41
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,39 @@
|
|
|
3
3
|
Until the protocol reaches integration-stable status, minor versions may include
|
|
4
4
|
breaking API changes. Breaking changes are called out explicitly.
|
|
5
5
|
|
|
6
|
+
## 1.7.0
|
|
7
|
+
|
|
8
|
+
### Breaking Changes
|
|
9
|
+
|
|
10
|
+
- Renamed peer callable surfaces to ports:
|
|
11
|
+
- `contracts/peer` moved to `contracts/ports`.
|
|
12
|
+
- `PeerEvent` / `event Peer` became `PortEvent` / `event Port`.
|
|
13
|
+
- `PeerBase`, `IPeer*`, and `Peer*` endpoint contracts became `PortBase`,
|
|
14
|
+
`IPort*`, and `Port*`.
|
|
15
|
+
- Peer endpoint functions and labels now use `port*` names, such as
|
|
16
|
+
`portPipePayable`, `portDispatchPayable`, and `portSettle`.
|
|
17
|
+
- Node helpers and layout tags now use `Port` terminology:
|
|
18
|
+
`Nodes.toPort`, `Nodes.isPort`, `Nodes.port`, and
|
|
19
|
+
`Nodes.portSelector`.
|
|
20
|
+
- Removed the generic `PortRecoverContextPayable`; recovery is now routed by
|
|
21
|
+
the command-level `recoverContextPayable` to concrete ports such as
|
|
22
|
+
`portPipePayable`.
|
|
23
|
+
- Renamed the `#contextRecovery` handler field from `target` to `port`.
|
|
24
|
+
- Changed port entrypoint calldata parameter naming to `data` to avoid
|
|
25
|
+
clashing with nested context `request` fields.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Added `RecoverContextPayable` and `#contextRecovery` for command-level
|
|
30
|
+
recovery routing with a commitment key, resources, handler port, and context
|
|
31
|
+
witness.
|
|
32
|
+
- Added `Dispatch(uint indexed host, uint chain, uint resources, bytes32 digest, bytes32 ref)`
|
|
33
|
+
as the discovery/event surface for dispatch tracking.
|
|
34
|
+
- Added `ContextRecovery` schema/cursor support and context schema aliases for
|
|
35
|
+
reusable nested block schemas.
|
|
36
|
+
- Added `Values.drain`, `Payable.openValue`, and `Payable.closeValue` to make
|
|
37
|
+
payable command budget lifecycles explicit.
|
|
38
|
+
|
|
6
39
|
## 1.6.0
|
|
7
40
|
|
|
8
41
|
### Added
|
|
@@ -15,7 +48,7 @@ breaking API changes. Breaking changes are called out explicitly.
|
|
|
15
48
|
asset ID without the full host runtime.
|
|
16
49
|
- Added `Escrows` as a keyed ledger for amounts reserved outside normal
|
|
17
50
|
balances.
|
|
18
|
-
- Added `Commitment(
|
|
51
|
+
- Added `Commitment(uint indexed host, bytes32 key, bytes32 digest, uint status)`
|
|
19
52
|
and the `Commitments` core mixin for digest commitments and witness/recovery
|
|
20
53
|
flows.
|
|
21
54
|
|
package/Endpoints.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
|
-
// Aggregator: re-exports command, admin,
|
|
4
|
+
// Aggregator: re-exports command, admin, port, guard, and query endpoint abstractions.
|
|
5
5
|
// Import this file to inherit from the full rootzero callable host surface without managing individual paths.
|
|
6
6
|
|
|
7
7
|
// Shared helpers
|
|
@@ -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 { RecoverContextPayable, RecoverContextPayableHook } from "./commands/Recover.sol";
|
|
19
20
|
import { RelayPayable, DispatchPayableHook } from "./commands/Relay.sol";
|
|
20
21
|
import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
|
|
21
22
|
|
|
@@ -33,18 +34,17 @@ import { Init, InitHook } from "./commands/admin/Init.sol";
|
|
|
33
34
|
import { Label } from "./commands/admin/Label.sol";
|
|
34
35
|
import { Unauthorize } from "./commands/admin/Unauthorize.sol";
|
|
35
36
|
|
|
36
|
-
//
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
47
|
-
import { PeerSettle, IPeerSettle } from "./peer/Settle.sol";
|
|
37
|
+
// Port endpoints
|
|
38
|
+
import { PortBase, encodePortCall } from "./ports/Base.sol";
|
|
39
|
+
import { PortAllowAssets, IPortAllowAssets } from "./ports/AllowAssets.sol";
|
|
40
|
+
import { PortAllowance, IPortAllowance } from "./ports/Allowance.sol";
|
|
41
|
+
import { PortRedeemBalance, RedeemBalanceHook, IPortRedeemBalance } from "./ports/Redeem.sol";
|
|
42
|
+
import { PortCreditAccount, IPortCreditAccount } from "./ports/Credit.sol";
|
|
43
|
+
import { PortDebitAccount, IPortDebitAccount } from "./ports/Debit.sol";
|
|
44
|
+
import { PortDenyAssets, IPortDenyAssets } from "./ports/DenyAssets.sol";
|
|
45
|
+
import { PortPipePayable, IPortPipePayable } from "./ports/Pipe.sol";
|
|
46
|
+
import { PortDispatchPayable, IPortDispatchPayable } from "./ports/Dispatch.sol";
|
|
47
|
+
import { PortSettle, IPortSettle } from "./ports/Settle.sol";
|
|
48
48
|
|
|
49
49
|
// Guard endpoints
|
|
50
50
|
import { GuardBase, encodeGuardCall } from "./guards/Base.sol";
|
package/Events.sol
CHANGED
|
@@ -11,6 +11,7 @@ import { BalanceEvent } from "./events/Balance.sol";
|
|
|
11
11
|
import { CommanderEvent } from "./events/Commander.sol";
|
|
12
12
|
import { CommandEvent } from "./events/Command.sol";
|
|
13
13
|
import { CommitmentEvent } from "./events/Commitment.sol";
|
|
14
|
+
import { DispatchEvent } from "./events/Dispatch.sol";
|
|
14
15
|
import { PositionEvent } from "./events/Position.sol";
|
|
15
16
|
import { ReceivedEvent } from "./events/Received.sol";
|
|
16
17
|
import { EventEmitter } from "./events/Emitter.sol";
|
|
@@ -20,7 +21,7 @@ import { IntroductionEvent } from "./events/Introduction.sol";
|
|
|
20
21
|
import { LabeledEvent } from "./events/Labeled.sol";
|
|
21
22
|
import { LockedEvent } from "./events/Locked.sol";
|
|
22
23
|
import { NodeEvent } from "./events/Node.sol";
|
|
23
|
-
import {
|
|
24
|
+
import { PortEvent } from "./events/Port.sol";
|
|
24
25
|
import { QueryEvent } from "./events/Query.sol";
|
|
25
26
|
import { RootedEvent } from "./events/Rooted.sol";
|
|
26
27
|
import { RouteEvent } from "./events/Route.sol";
|
package/README.md
CHANGED
|
@@ -271,8 +271,8 @@ blocks executed in order within one transaction:
|
|
|
271
271
|
|
|
272
272
|
Each step names a target command, the resources it may spend, and its request.
|
|
273
273
|
The state threads through: whatever one command returns becomes the input
|
|
274
|
-
state of the next, and the final state must be empty
|
|
275
|
-
|
|
274
|
+
state of the next, and the final state must be empty. This is the core of
|
|
275
|
+
`Pipeline.pipe`:
|
|
276
276
|
|
|
277
277
|
```solidity
|
|
278
278
|
while (input.i < input.len) {
|
|
@@ -304,19 +304,19 @@ response: #accountAmount { bytes32 account, bytes32 asset, uint amount }
|
|
|
304
304
|
Like commands, every query announces its request and response schemas at
|
|
305
305
|
deployment, so tooling knows how to call it without artifacts.
|
|
306
306
|
|
|
307
|
-
##
|
|
307
|
+
## Ports
|
|
308
308
|
|
|
309
|
-
|
|
309
|
+
Ports are the host-to-host surfaces, callable only by trusted peer hosts. The two
|
|
310
310
|
central ones are batches all the way down:
|
|
311
311
|
|
|
312
|
-
- `
|
|
312
|
+
- `portSettle` consumes `#transaction { bytes32 from, bytes32 to, bytes32 asset,
|
|
313
313
|
uint amount }` blocks, debiting `from` and crediting `to` per
|
|
314
314
|
block — how two hosts record settlement between their ledgers.
|
|
315
|
-
- `
|
|
315
|
+
- `portPipePayable` consumes `#context` blocks, each carrying an account, an
|
|
316
316
|
initial state, and a run of steps — a complete pipeline delivered by another
|
|
317
|
-
host, executed locally
|
|
317
|
+
host, executed locally against the peer call's shared value budget.
|
|
318
318
|
|
|
319
|
-
This is also the cross-chain mechanism. `relayPayable` (or `
|
|
319
|
+
This is also the cross-chain mechanism. `relayPayable` (or `portDispatchPayable`)
|
|
320
320
|
wraps a pipe and addresses it to a chain; a bridge adapter moves the **raw
|
|
321
321
|
bytes**; the destination host parses them with the same cursor rules and runs
|
|
322
322
|
the same pipeline loop. Nothing in the payload is EVM-specific — step targets
|
|
@@ -363,7 +363,7 @@ Repo layout:
|
|
|
363
363
|
|
|
364
364
|
- `contracts/core` — host, access control, balances, pipeline, validation
|
|
365
365
|
- `contracts/commands` — standard commands and admin commands
|
|
366
|
-
- `contracts/
|
|
366
|
+
- `contracts/ports` — peer surfaces for inter-host and cross-chain flows
|
|
367
367
|
- `contracts/guards` — guardian direct actions
|
|
368
368
|
- `contracts/queries` — read-only query endpoints
|
|
369
369
|
- `contracts/blocks` — block schema, cursor parsing, writers
|
package/blocks/Cursors.sol
CHANGED
|
@@ -548,28 +548,13 @@ library Cursors {
|
|
|
548
548
|
return createBlock(Keys.Context, bytes.concat(account, toBytesBlock(state), toBytesBlock(request)));
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
-
/// @notice Encode a PIPE block.
|
|
552
|
-
/// @param resources Chain resources assigned to the pipe.
|
|
553
|
-
/// @param account Command account identifier.
|
|
554
|
-
/// @param state Embedded state block stream.
|
|
555
|
-
/// @param steps Embedded step block stream.
|
|
556
|
-
/// @return Encoded PIPE block bytes.
|
|
557
|
-
function toPipeBlock(
|
|
558
|
-
uint resources,
|
|
559
|
-
bytes32 account,
|
|
560
|
-
bytes memory state,
|
|
561
|
-
bytes memory steps
|
|
562
|
-
) internal pure returns (bytes memory) {
|
|
563
|
-
return createBlock(Keys.Pipe, bytes.concat(bytes32(resources), toContextBlock(account, state, steps)));
|
|
564
|
-
}
|
|
565
|
-
|
|
566
551
|
/// @notice Encode a RELAY block.
|
|
567
552
|
/// @param chain Destination chain node ID.
|
|
568
|
-
/// @param resources Chain-adapter-specific resources for the destination
|
|
569
|
-
/// @param
|
|
553
|
+
/// @param resources Chain-adapter-specific resources for the destination context.
|
|
554
|
+
/// @param request Nested request block stream.
|
|
570
555
|
/// @return Encoded RELAY block bytes.
|
|
571
|
-
function toRelayBlock(uint chain, uint resources, bytes memory
|
|
572
|
-
return createBlock(Keys.Relay, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(
|
|
556
|
+
function toRelayBlock(uint chain, uint resources, bytes memory request) internal pure returns (bytes memory) {
|
|
557
|
+
return createBlock(Keys.Relay, bytes.concat(bytes32(chain), bytes32(resources), toBytesBlock(request)));
|
|
573
558
|
}
|
|
574
559
|
|
|
575
560
|
/// @notice Encode a DISPATCH block.
|
|
@@ -1155,33 +1140,18 @@ library Cursors {
|
|
|
1155
1140
|
cur.exit(end);
|
|
1156
1141
|
}
|
|
1157
1142
|
|
|
1158
|
-
/// @notice Consume a
|
|
1159
|
-
/// @param cur Cursor; advanced past the block.
|
|
1160
|
-
/// @return resources Chain resources assigned to the pipe.
|
|
1161
|
-
/// @return account Command account identifier.
|
|
1162
|
-
/// @return state Embedded state block stream.
|
|
1163
|
-
/// @return steps Embedded step block stream.
|
|
1164
|
-
function unpackPipe(
|
|
1165
|
-
Cur memory cur
|
|
1166
|
-
) internal pure returns (uint resources, bytes32 account, bytes calldata state, bytes calldata steps) {
|
|
1167
|
-
uint end = cur.enter(Keys.Pipe, 32 + Sizes.Header + 32 + 2 * Sizes.Header, 0);
|
|
1168
|
-
resources = uint(cur.read32());
|
|
1169
|
-
(account, state, steps) = cur.unpackContext();
|
|
1170
|
-
cur.exit(end);
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
/// @notice Consume a RELAY block and return its destination chain, resources, and step stream.
|
|
1143
|
+
/// @notice Consume a RELAY block and return its destination chain, resources, and request stream.
|
|
1174
1144
|
/// @param cur Cursor; advanced past the block.
|
|
1175
1145
|
/// @return chain Destination chain node ID.
|
|
1176
|
-
/// @return resources Chain-adapter-specific resources for the destination
|
|
1177
|
-
/// @return
|
|
1146
|
+
/// @return resources Chain-adapter-specific resources for the destination context.
|
|
1147
|
+
/// @return request Embedded request block stream.
|
|
1178
1148
|
function unpackRelay(
|
|
1179
1149
|
Cur memory cur
|
|
1180
|
-
) internal pure returns (uint chain, uint resources, bytes calldata
|
|
1150
|
+
) internal pure returns (uint chain, uint resources, bytes calldata request) {
|
|
1181
1151
|
uint end = cur.enter(Keys.Relay, 64 + Sizes.Header, 0);
|
|
1182
1152
|
chain = cur.readUint();
|
|
1183
1153
|
resources = cur.readUint();
|
|
1184
|
-
|
|
1154
|
+
request = cur.unpackBytes();
|
|
1185
1155
|
cur.exit(end);
|
|
1186
1156
|
}
|
|
1187
1157
|
|
|
@@ -1200,6 +1170,23 @@ library Cursors {
|
|
|
1200
1170
|
cur.exit(end);
|
|
1201
1171
|
}
|
|
1202
1172
|
|
|
1173
|
+
/// @notice Consume a CONTEXT_RECOVERY block and return its port, key, resources, and embedded context cursor.
|
|
1174
|
+
/// @param cur Cursor; advanced past the block.
|
|
1175
|
+
/// @return port Recovery handler port node ID.
|
|
1176
|
+
/// @return key Commitment or recovery lookup key.
|
|
1177
|
+
/// @return resources Chain resources assigned to the recovery attempt.
|
|
1178
|
+
/// @return context Cursor scoped to the embedded CONTEXT witness block.
|
|
1179
|
+
function unpackContextRecovery(
|
|
1180
|
+
Cur memory cur
|
|
1181
|
+
) internal pure returns (uint port, bytes32 key, uint resources, Cur memory context) {
|
|
1182
|
+
uint end = cur.enter(Keys.ContextRecovery, 96 + Sizes.Header, 0);
|
|
1183
|
+
port = cur.readUint();
|
|
1184
|
+
key = cur.read32();
|
|
1185
|
+
resources = cur.readUint();
|
|
1186
|
+
context = cur.take(Keys.Context);
|
|
1187
|
+
cur.exit(end);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1203
1190
|
// Type-specific validators
|
|
1204
1191
|
|
|
1205
1192
|
/// @notice Validate an AUTH block at position `i` and extract deadline and proof.
|
|
@@ -1388,21 +1375,21 @@ library Cursors {
|
|
|
1388
1375
|
// Transform helpers
|
|
1389
1376
|
// -------------------------------------------------------------------------
|
|
1390
1377
|
|
|
1391
|
-
/// @notice Consume a RELAY block and encode its destination
|
|
1378
|
+
/// @notice Consume a RELAY block and encode its destination context payload.
|
|
1392
1379
|
/// @param cur Cursor; advanced past the RELAY block.
|
|
1393
|
-
/// @param account Account identifier to embed in the destination
|
|
1394
|
-
/// @param state State block stream to embed in the destination
|
|
1380
|
+
/// @param account Account identifier to embed in the destination context.
|
|
1381
|
+
/// @param state State block stream to embed in the destination context.
|
|
1395
1382
|
/// @return chain Destination chain node ID.
|
|
1396
|
-
/// @return resources Chain resources assigned to the destination
|
|
1397
|
-
/// @return
|
|
1398
|
-
function
|
|
1383
|
+
/// @return resources Chain resources assigned to the destination context.
|
|
1384
|
+
/// @return context Encoded CONTEXT block containing `account`, `state`, and relay request.
|
|
1385
|
+
function relayToContext(
|
|
1399
1386
|
Cur memory cur,
|
|
1400
1387
|
bytes32 account,
|
|
1401
1388
|
bytes calldata state
|
|
1402
|
-
) internal pure returns (uint chain, uint resources, bytes memory
|
|
1403
|
-
bytes calldata
|
|
1404
|
-
(chain, resources,
|
|
1405
|
-
|
|
1389
|
+
) internal pure returns (uint chain, uint resources, bytes memory context) {
|
|
1390
|
+
bytes calldata request;
|
|
1391
|
+
(chain, resources, request) = cur.unpackRelay();
|
|
1392
|
+
context = toContextBlock(account, bytes(state), bytes(request));
|
|
1406
1393
|
}
|
|
1407
1394
|
|
|
1408
1395
|
// -------------------------------------------------------------------------
|
package/blocks/Keys.sol
CHANGED
|
@@ -41,16 +41,16 @@ library Keys {
|
|
|
41
41
|
bytes4 constant Transaction = bytes4(keccak256("#transaction"));
|
|
42
42
|
/// @dev Sub-command invocation - (uint target, uint resources, #bytes as request)
|
|
43
43
|
bytes4 constant Step = bytes4(keccak256("#step"));
|
|
44
|
-
/// @dev Cross-chain
|
|
44
|
+
/// @dev Cross-chain relay request - (uint chain, uint resources, #bytes as request)
|
|
45
45
|
bytes4 constant Relay = bytes4(keccak256("#relay"));
|
|
46
|
+
/// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
|
|
47
|
+
bytes4 constant Context = bytes4(keccak256("#context"));
|
|
48
|
+
/// @dev Recoverable context witness - (uint port, bytes32 key, uint resources, #context)
|
|
49
|
+
bytes4 constant ContextRecovery = bytes4(keccak256("#contextRecovery"));
|
|
46
50
|
/// @dev Cross-chain encoded payload dispatch - (uint chain, uint resources, #bytes as payload)
|
|
47
51
|
bytes4 constant Dispatch = bytes4(keccak256("#dispatch"));
|
|
48
52
|
/// @dev Raw external call - (uint target, uint resources, #bytes as payload)
|
|
49
53
|
bytes4 constant Call = bytes4(keccak256("#call"));
|
|
50
|
-
/// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
|
|
51
|
-
bytes4 constant Context = bytes4(keccak256("#context"));
|
|
52
|
-
/// @dev Pipeline invocation - (uint resources, #context)
|
|
53
|
-
bytes4 constant Pipe = bytes4(keccak256("#pipe"));
|
|
54
54
|
/// @dev Authentication proof - (uint cid, uint deadline, #bytes as proof); must appear last in its segment
|
|
55
55
|
bytes4 constant Auth = bytes4(keccak256("#auth"));
|
|
56
56
|
/// @dev Asset descriptor without amount - (bytes32 asset)
|
package/blocks/Schema.sol
CHANGED
|
@@ -21,6 +21,8 @@ pragma solidity ^0.8.33;
|
|
|
21
21
|
// stable format everywhere. EVM resources use the low 128 bits as native value.
|
|
22
22
|
// - dotted field names and aliases, e.g. `dst.chain` or `#bytes as dst.payload`,
|
|
23
23
|
// are offchain projection metadata only and do not change runtime encoding
|
|
24
|
+
// - a child block without an inline body, e.g. `#context as witness`, may resolve
|
|
25
|
+
// to a known schema in the active schema context; unresolved aliases are invalid
|
|
24
26
|
// - fixed fields are packed in declaration order
|
|
25
27
|
// - blocks have fixed fields followed by a dynamic child-block tail
|
|
26
28
|
// - child block tails are embedded directly, without an extra stream wrapper
|
|
@@ -69,10 +71,10 @@ library Schemas {
|
|
|
69
71
|
string constant Allowance = "#allowance { uint host, bytes32 asset, uint amount }";
|
|
70
72
|
string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, uint amount }";
|
|
71
73
|
string constant Context = "#context { bytes32 account, #bytes as state, #bytes as request }";
|
|
72
|
-
string constant
|
|
74
|
+
string constant ContextRecovery = "#contextRecovery { uint port, bytes32 key, uint resources, #context as witness }";
|
|
73
75
|
string constant Call = "#call { uint target, uint resources, #bytes as payload }";
|
|
74
76
|
string constant Step = "#step { uint target, uint resources, #bytes as request }";
|
|
75
|
-
string constant Relay = "#relay { uint chain, uint resources, #bytes as
|
|
77
|
+
string constant Relay = "#relay { uint chain, uint resources, #bytes as request }";
|
|
76
78
|
string constant Dispatch = "#dispatch { uint chain, uint resources, #bytes as payload }";
|
|
77
79
|
string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
|
|
78
80
|
string constant Fee = "#fee { uint amount }";
|
package/blocks/Writers.sol
CHANGED
|
@@ -28,7 +28,6 @@ library Hints {
|
|
|
28
28
|
uint constant Step = 256;
|
|
29
29
|
uint constant Call = 256;
|
|
30
30
|
uint constant Context = 512;
|
|
31
|
-
uint constant Pipe = 608;
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
/// @title Writers
|
|
@@ -233,14 +232,6 @@ library Writers {
|
|
|
233
232
|
return allocFromHint(count, Hints.Context);
|
|
234
233
|
}
|
|
235
234
|
|
|
236
|
-
/// @notice Allocate a writer for `count` PIPE blocks using a per-block capacity hint.
|
|
237
|
-
/// @dev The backing buffer expands automatically if encoded pipes exceed the initial hint.
|
|
238
|
-
/// @param count Number of pipe blocks to allocate space for.
|
|
239
|
-
/// @return writer Allocated growable writer.
|
|
240
|
-
function allocPipes(uint count) internal pure returns (Writer memory writer) {
|
|
241
|
-
return allocFromHint(count, Hints.Pipe);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
235
|
// -------------------------------------------------------------------------
|
|
245
236
|
// Fixed-width write helpers
|
|
246
237
|
// -------------------------------------------------------------------------
|
|
@@ -905,32 +896,6 @@ library Writers {
|
|
|
905
896
|
appendBlock32BytesBytes(writer, Keys.Context, account, state, request);
|
|
906
897
|
}
|
|
907
898
|
|
|
908
|
-
/// @notice Append a PIPE block with a nested CONTEXT block.
|
|
909
|
-
/// @param writer Destination writer; `i` is advanced by the encoded PIPE block length.
|
|
910
|
-
/// @param resources Chain resources assigned to the pipe.
|
|
911
|
-
/// @param account Command account identifier.
|
|
912
|
-
/// @param state Raw nested state payload.
|
|
913
|
-
/// @param steps Raw nested step payload.
|
|
914
|
-
function appendPipe(
|
|
915
|
-
Writer memory writer,
|
|
916
|
-
uint resources,
|
|
917
|
-
bytes32 account,
|
|
918
|
-
bytes memory state,
|
|
919
|
-
bytes memory steps
|
|
920
|
-
) internal pure {
|
|
921
|
-
uint i = writer.i;
|
|
922
|
-
uint len = 64 + 3 * Sizes.Header + state.length + steps.length;
|
|
923
|
-
uint next = i + Sizes.Header + len;
|
|
924
|
-
i = reserve(writer, next, next);
|
|
925
|
-
|
|
926
|
-
uint p = writeHeader(writer.dst, i, Keys.Pipe, uint32(max32(len)));
|
|
927
|
-
assembly ("memory-safe") {
|
|
928
|
-
mstore(add(p, 0x08), resources)
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
writeBlock32BytesBytes(writer.dst, i + Sizes.Header + 32, Keys.Context, account, state, steps);
|
|
932
|
-
}
|
|
933
|
-
|
|
934
899
|
/// @notice Append a STATUS form block.
|
|
935
900
|
/// @param writer Destination writer; `i` is advanced by `Sizes.Status`.
|
|
936
901
|
/// @param code Status code to encode.
|
package/commands/Deposit.sol
CHANGED
|
@@ -81,7 +81,7 @@ abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
|
|
|
81
81
|
) external payable onlyCommand returns (bytes memory) {
|
|
82
82
|
(Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
|
|
83
83
|
Writer memory writer = Writers.allocBalances(groups);
|
|
84
|
-
Budget memory budget =
|
|
84
|
+
Budget memory budget = openValue();
|
|
85
85
|
|
|
86
86
|
while (request.i < request.len) {
|
|
87
87
|
(bytes32 asset, uint amount) = request.unpackAmount();
|
|
@@ -89,7 +89,7 @@ abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
|
|
|
89
89
|
writer.appendBalance(asset, amount);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
closeValue(c.account, budget);
|
|
93
93
|
request.complete();
|
|
94
94
|
return writer.finish();
|
|
95
95
|
}
|
package/commands/Provision.sol
CHANGED
|
@@ -78,7 +78,7 @@ abstract contract ProvisionPayable is CommandBase, Payable, ProvisionPayableHook
|
|
|
78
78
|
) external payable onlyCommand returns (bytes memory) {
|
|
79
79
|
(Cur memory request, uint groups, ) = Cursors.init(c.request, 1);
|
|
80
80
|
Writer memory writer = Writers.allocCustodies(groups);
|
|
81
|
-
Budget memory budget =
|
|
81
|
+
Budget memory budget = openValue();
|
|
82
82
|
|
|
83
83
|
while (request.i < request.len) {
|
|
84
84
|
HostAmount memory allocation = request.unpackAllocationValue();
|
|
@@ -86,7 +86,7 @@ abstract contract ProvisionPayable is CommandBase, Payable, ProvisionPayableHook
|
|
|
86
86
|
writer.appendCustody(allocation);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
closeValue(c.account, budget);
|
|
90
90
|
request.complete();
|
|
91
91
|
return writer.finish();
|
|
92
92
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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 RecoverContextPayableHook {
|
|
12
|
+
/// @notice Override to recover one committed context witness.
|
|
13
|
+
/// @param port Recovery handler port node ID.
|
|
14
|
+
/// @param key Commitment or recovery lookup key.
|
|
15
|
+
/// @param resources Chain resources assigned to the recovery attempt.
|
|
16
|
+
/// @param context Cursor scoped to the embedded CONTEXT witness block.
|
|
17
|
+
/// @param budget Mutable native-value budget available to the recovery attempt.
|
|
18
|
+
function recoverContext(uint port, bytes32 key, uint resources, Cur memory context, Budget memory budget) internal virtual;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @title RecoverContextPayable
|
|
22
|
+
/// @notice Command that forwards ContextRecovery request blocks to a virtual hook.
|
|
23
|
+
/// Produces no output state.
|
|
24
|
+
abstract contract RecoverContextPayable is CommandBase, Payable, RecoverContextPayableHook {
|
|
25
|
+
uint internal immutable recoverContextPayableId = commandId(this.recoverContextPayable.selector);
|
|
26
|
+
|
|
27
|
+
constructor() {
|
|
28
|
+
emit Command(host, recoverContextPayableId, "1:0:0", Schemas.ContextRecovery, Keys.Empty, Keys.Empty, true);
|
|
29
|
+
emit Labeled(recoverContextPayableId, bytes32(0), "recoverContextPayable");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// @notice Recover each ContextRecovery block in the command request.
|
|
33
|
+
/// @param c Command context; `c.request` must contain ContextRecovery blocks.
|
|
34
|
+
/// @return Empty output state.
|
|
35
|
+
function recoverContextPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory) {
|
|
36
|
+
(Cur memory request, , ) = Cursors.init(c.request, 1);
|
|
37
|
+
Budget memory budget = openValue();
|
|
38
|
+
|
|
39
|
+
while (request.i < request.len) {
|
|
40
|
+
(uint port, bytes32 key, uint resources, Cur memory context) = request.unpackContextRecovery();
|
|
41
|
+
recoverContext(port, key, resources, context, budget);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
closeValue(c.account, budget);
|
|
45
|
+
request.complete();
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
}
|
package/commands/Relay.sol
CHANGED
|
@@ -37,12 +37,12 @@ abstract contract RelayPayable is CommandBase, Payable, DispatchPayableHook {
|
|
|
37
37
|
/// @return output Empty output state.
|
|
38
38
|
function relayPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory output) {
|
|
39
39
|
(Cur memory request, ) = Cursors.init(c.request, 1, 1);
|
|
40
|
-
Budget memory budget =
|
|
40
|
+
Budget memory budget = openValue();
|
|
41
41
|
|
|
42
|
-
(uint chain, uint resources, bytes memory
|
|
43
|
-
dispatch(chain, resources,
|
|
42
|
+
(uint chain, uint resources, bytes memory context) = request.relayToContext(c.account, c.state);
|
|
43
|
+
dispatch(chain, resources, context, budget);
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
closeValue(c.account, budget);
|
|
46
46
|
request.complete();
|
|
47
47
|
return "";
|
|
48
48
|
}
|
|
@@ -27,7 +27,7 @@ abstract contract ExecutePayable is AdminBase, Payable {
|
|
|
27
27
|
/// @return Empty output state.
|
|
28
28
|
function executePayable(CommandContext calldata c) external payable onlyAdmin(c.account) returns (bytes memory) {
|
|
29
29
|
(Cur memory request, , ) = Cursors.init(c.request, 1);
|
|
30
|
-
Budget memory budget =
|
|
30
|
+
Budget memory budget = openValue();
|
|
31
31
|
|
|
32
32
|
while (request.i < request.len) {
|
|
33
33
|
(uint target, uint resources, bytes calldata data) = request.unpackCall();
|
package/core/Commitments.sol
CHANGED
|
@@ -4,7 +4,7 @@ pragma solidity ^0.8.33;
|
|
|
4
4
|
import {CommitmentEvent} from "../events/Commitment.sol";
|
|
5
5
|
|
|
6
6
|
/// @title Commitments
|
|
7
|
-
/// @notice On-chain registry for
|
|
7
|
+
/// @notice On-chain registry for digest commitments.
|
|
8
8
|
abstract contract Commitments is CommitmentEvent {
|
|
9
9
|
/// @dev key -> committed digest.
|
|
10
10
|
mapping(bytes32 key => bytes32 digest) internal commitments;
|
package/core/Payable.sol
CHANGED
|
@@ -5,16 +5,14 @@ import {Budget, Values} from "../utils/Value.sol";
|
|
|
5
5
|
|
|
6
6
|
/// @title Payable
|
|
7
7
|
/// @notice Abstract mixin for entrypoints that accept native value (`msg.value`).
|
|
8
|
-
/// Provides
|
|
9
|
-
/// mutable budget after execution completes.
|
|
8
|
+
/// Provides shared helpers for mutable native-value budgets.
|
|
10
9
|
abstract contract Payable {
|
|
11
10
|
/// @dev Thrown when a payable entrypoint completes with unspent native value.
|
|
12
|
-
/// Override `settleValue` to implement refund or forwarding behavior instead.
|
|
13
11
|
error UnusedValue(uint remaining);
|
|
14
12
|
|
|
15
|
-
/// @notice
|
|
16
|
-
/// @return Budget
|
|
17
|
-
function
|
|
13
|
+
/// @notice Open a native-value budget from the current call's `msg.value`.
|
|
14
|
+
/// @return Budget initialized with the full `msg.value`.
|
|
15
|
+
function openValue() internal view returns (Budget memory) {
|
|
18
16
|
return Budget({remaining: msg.value});
|
|
19
17
|
}
|
|
20
18
|
|
|
@@ -24,36 +22,25 @@ abstract contract Payable {
|
|
|
24
22
|
/// @param resources Packed chain resources.
|
|
25
23
|
/// @return value Native value to forward in wei.
|
|
26
24
|
function useValue(Budget memory budget, uint resources) internal pure returns (uint128 value) {
|
|
27
|
-
|
|
25
|
+
value = uint128(resources);
|
|
26
|
+
Values.use(budget, value);
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
/// @notice
|
|
31
|
-
/// @dev EVM resources use the low 128 bits as native value/endowment.
|
|
32
|
-
/// @param budget Mutable parent budget to deduct from.
|
|
33
|
-
/// @param resources Packed chain resources.
|
|
34
|
-
/// @return A new budget with the EVM value lane remaining.
|
|
35
|
-
function allocateValue(Budget memory budget, uint resources) internal pure returns (Budget memory) {
|
|
36
|
-
return Values.allocate(budget, uint128(resources));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/// @notice Drains the budget and settles any remaining native value.
|
|
40
|
-
/// @dev Calls the amount-based `settleValue` hook only when some value remains.
|
|
29
|
+
/// @notice Close a native-value budget and settle any drained value.
|
|
41
30
|
/// @param account Account identifier for the current invocation.
|
|
42
|
-
/// @param budget Mutable native-value budget
|
|
43
|
-
function
|
|
44
|
-
uint value = budget
|
|
31
|
+
/// @param budget Mutable native-value budget to close.
|
|
32
|
+
function closeValue(bytes32 account, Budget memory budget) internal {
|
|
33
|
+
uint value = Values.drain(budget);
|
|
45
34
|
if (value == 0) return;
|
|
46
|
-
budget.remaining = 0;
|
|
47
35
|
settleValue(account, value);
|
|
48
36
|
}
|
|
49
37
|
|
|
50
|
-
/// @notice
|
|
51
|
-
/// @dev Override
|
|
52
|
-
/// The default implementation rejects any leftover amount.
|
|
38
|
+
/// @notice Handle a drained native value amount.
|
|
39
|
+
/// @dev Override to refund or redirect unused value. The default rejects it.
|
|
53
40
|
/// @param account Account identifier for the current invocation.
|
|
54
|
-
/// @param
|
|
55
|
-
function settleValue(bytes32 account, uint
|
|
41
|
+
/// @param value Drained native value amount to settle, in wei.
|
|
42
|
+
function settleValue(bytes32 account, uint value) internal virtual {
|
|
56
43
|
account;
|
|
57
|
-
revert UnusedValue(
|
|
44
|
+
revert UnusedValue(value);
|
|
58
45
|
}
|
|
59
46
|
}
|
package/core/Pipeline.sol
CHANGED
|
@@ -32,6 +32,7 @@ abstract contract Pipeline is Payable {
|
|
|
32
32
|
|
|
33
33
|
/// @notice Execute a STEP block stream through the pipeline.
|
|
34
34
|
/// @dev Reverts with `UnexpectedState` if the final threaded state is non-empty.
|
|
35
|
+
/// Callers remain responsible for settling any unspent value in `budget`.
|
|
35
36
|
/// @param account Account identifier used for each dispatched step.
|
|
36
37
|
/// @param state Initial state block stream passed to the first step.
|
|
37
38
|
/// @param steps STEP block stream to execute.
|
|
@@ -50,7 +51,6 @@ abstract contract Pipeline is Payable {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
if (state.length != 0) revert UnexpectedState();
|
|
53
|
-
settleValue(account, budget);
|
|
54
54
|
input.complete();
|
|
55
55
|
}
|
|
56
56
|
}
|
package/docs/Schema.md
CHANGED
|
@@ -58,7 +58,6 @@ Once a child block appears, no more fixed fields may follow.
|
|
|
58
58
|
```txt
|
|
59
59
|
#call { uint target, uint resources, #bytes as payload }
|
|
60
60
|
#context { bytes32 account, #bytes as state, #bytes as request }
|
|
61
|
-
#pipe { uint resources, #context { bytes32 account, #bytes as state, #bytes as steps } }
|
|
62
61
|
```
|
|
63
62
|
|
|
64
63
|
The tail is embedded directly as child block bytes. There is no wrapper around a
|
|
@@ -118,6 +117,18 @@ maybe #account { bytes32 account } as recipient
|
|
|
118
117
|
|
|
119
118
|
Aliases may be used on any block item, including child blocks and prime items.
|
|
120
119
|
|
|
120
|
+
A child block without an inline body may also be used as a schema reference:
|
|
121
|
+
|
|
122
|
+
```txt
|
|
123
|
+
#contextRecovery { uint port, bytes32 key, uint resources, #context as witness }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Alias resolution is context-dependent. A consumer may resolve `#context` from the
|
|
127
|
+
standard `Schemas` table, from app-specific schemas, or from another active
|
|
128
|
+
schema context. Consumers should reject schemas with unresolved aliases. The
|
|
129
|
+
runtime encoding is still an embedded child block with the referenced key and
|
|
130
|
+
layout.
|
|
131
|
+
|
|
121
132
|
## Field Paths
|
|
122
133
|
|
|
123
134
|
Field names and aliases may use dotted paths for offchain projection. A dotted
|
|
@@ -271,7 +282,7 @@ Common protocol schemas live in `contracts/blocks/Schema.sol`:
|
|
|
271
282
|
#call { uint target, uint resources, #bytes as payload }
|
|
272
283
|
#step { uint target, uint resources, #bytes as request }
|
|
273
284
|
#context { bytes32 account, #bytes as state, #bytes as request }
|
|
274
|
-
#
|
|
285
|
+
#contextRecovery { uint port, bytes32 key, uint resources, #context as witness }
|
|
275
286
|
#auth { uint cid, uint deadline, #bytes as proof }
|
|
276
287
|
```
|
|
277
288
|
|