@rootzero/contracts 1.8.0 → 1.9.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 +20 -0
- package/Core.sol +1 -1
- package/Endpoints.sol +3 -2
- package/Events.sol +2 -1
- package/README.md +13 -12
- package/blocks/Cursors.sol +39 -39
- package/blocks/Keys.sol +4 -4
- package/blocks/Schema.sol +8 -7
- package/blocks/Writers.sol +2 -2
- package/commands/Recover.sol +14 -21
- package/commands/Relay.sol +5 -15
- package/commands/admin/Destroy.sol +1 -0
- package/commands/admin/Execute.sol +1 -1
- package/commands/admin/Init.sol +1 -0
- package/core/Access.sol +1 -0
- package/core/Calls.sol +12 -1
- package/core/Payable.sol +1 -1
- package/core/Portal.sol +68 -0
- package/docs/Schema.md +15 -11
- package/events/Dispatch.sol +5 -5
- package/events/Resolved.sol +17 -0
- package/events/Route.sol +5 -5
- package/events/Undelivered.sol +18 -0
- package/package.json +1 -1
- package/ports/Dispatch.sol +7 -7
- package/queries/Positions.sol +1 -0
- package/core/Commitments.sol +0 -19
- package/events/Commitment.sol +0 -19
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
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.9.0
|
|
7
|
+
|
|
8
|
+
### Breaking Changes
|
|
9
|
+
|
|
10
|
+
- Renamed relay and dispatch routing fields from `chain` to `portal` across
|
|
11
|
+
schemas, cursor helpers, dispatch hooks, and dispatch/route events.
|
|
12
|
+
- Replaced the context-specific `RecoverContextPayable` / `#contextRecovery`
|
|
13
|
+
surface with generic `RecoverPayable` / `#recover` using byte witnesses.
|
|
14
|
+
- Renamed the `Dispatch` event correlation field from `ref` to `key`.
|
|
15
|
+
- Replaced `DispatchPayableHook.dispatch` with `RoutePayableHook.route` in the
|
|
16
|
+
portal core layer.
|
|
17
|
+
- Added `status` to `Route(uint indexed host, uint portal, uint status)`
|
|
18
|
+
so routes can be removed by emitting zero status.
|
|
19
|
+
- Added `Undelivered(uint indexed host, bytes32 key, bytes32 digest)` for portal
|
|
20
|
+
messages that could not be delivered to their handler port.
|
|
21
|
+
- Added `Resolved(uint indexed host, bytes32 key)` as the
|
|
22
|
+
matching event for resolved undelivered digests.
|
|
23
|
+
- Removed the generic `Commitments` core mixin and `Commitment` event in favor
|
|
24
|
+
of domain-specific events such as `Undelivered` and `Resolved`.
|
|
25
|
+
|
|
6
26
|
## 1.8.0
|
|
7
27
|
|
|
8
28
|
### Breaking Changes
|
package/Core.sol
CHANGED
|
@@ -6,13 +6,13 @@ pragma solidity ^0.8.33;
|
|
|
6
6
|
|
|
7
7
|
import { AccessControl } from "./core/Access.sol";
|
|
8
8
|
import { Balances, InsufficientFunds } from "./core/Balances.sol";
|
|
9
|
-
import { Commitments } from "./core/Commitments.sol";
|
|
10
9
|
import { Escrows, InsufficientEscrow } from "./core/Escrows.sol";
|
|
11
10
|
import { NativeAsset, Runtime } from "./core/Runtime.sol";
|
|
12
11
|
import { Host, IHostIntroduction } from "./core/Host.sol";
|
|
13
12
|
import { CommandCalls, FailedCall, NodeCalls, PortCalls } from "./core/Calls.sol";
|
|
14
13
|
import { Payable } from "./core/Payable.sol";
|
|
15
14
|
import { Pipeline } from "./core/Pipeline.sol";
|
|
15
|
+
import { Portal, RecoverHook, RoutePayableHook } from "./core/Portal.sol";
|
|
16
16
|
import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
|
|
17
17
|
import { Validator } from "./core/Validator.sol";
|
|
18
18
|
|
package/Endpoints.sol
CHANGED
|
@@ -16,8 +16,9 @@ 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 {
|
|
20
|
-
import { RelayPayable
|
|
19
|
+
import { RecoverPayable } from "./commands/Recover.sol";
|
|
20
|
+
import { RelayPayable } from "./commands/Relay.sol";
|
|
21
|
+
import { RecoverHook, RoutePayableHook } from "./core/Portal.sol";
|
|
21
22
|
import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
|
|
22
23
|
|
|
23
24
|
// Admin commands
|
package/Events.sol
CHANGED
|
@@ -10,10 +10,10 @@ import { Actions } from "./utils/Actions.sol";
|
|
|
10
10
|
import { BalanceEvent } from "./events/Balance.sol";
|
|
11
11
|
import { CommanderEvent } from "./events/Commander.sol";
|
|
12
12
|
import { CommandEvent } from "./events/Command.sol";
|
|
13
|
-
import { CommitmentEvent } from "./events/Commitment.sol";
|
|
14
13
|
import { DispatchEvent } from "./events/Dispatch.sol";
|
|
15
14
|
import { PositionEvent } from "./events/Position.sol";
|
|
16
15
|
import { ReceivedEvent } from "./events/Received.sol";
|
|
16
|
+
import { ResolvedEvent } from "./events/Resolved.sol";
|
|
17
17
|
import { EventEmitter } from "./events/Emitter.sol";
|
|
18
18
|
import { GuardEvent } from "./events/Guard.sol";
|
|
19
19
|
import { GuardianEvent } from "./events/Guardian.sol";
|
|
@@ -26,6 +26,7 @@ import { QueryEvent } from "./events/Query.sol";
|
|
|
26
26
|
import { RootedEvent } from "./events/Rooted.sol";
|
|
27
27
|
import { RouteEvent } from "./events/Route.sol";
|
|
28
28
|
import { SpentEvent } from "./events/Spent.sol";
|
|
29
|
+
import { UndeliveredEvent } from "./events/Undelivered.sol";
|
|
29
30
|
import { UnlockedEvent } from "./events/Unlocked.sol";
|
|
30
31
|
|
|
31
32
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
rootzero is a protocol for building **hosts**: contracts that expose a uniform
|
|
4
4
|
set of endpoints over accounts and assets — commands that change state,
|
|
5
|
-
queries that read it, and
|
|
5
|
+
queries that read it, and port links that connect hosts to each other, on the
|
|
6
6
|
same chain or across chains.
|
|
7
7
|
|
|
8
8
|
This repository is `@rootzero/contracts`, the Solidity library for the EVM port
|
|
@@ -160,7 +160,7 @@ structured ID announces what it is (an account, an asset, a node) and which
|
|
|
160
160
|
chain it lives on, and the payload usually embeds the underlying address. User
|
|
161
161
|
accounts are chain-agnostic; admin and guardian accounts are chain-local.
|
|
162
162
|
Assets are unique IDs in the same single-word form as accounts and nodes.
|
|
163
|
-
Nodes are hosts, commands,
|
|
163
|
+
Nodes are hosts, commands, ports, queries, and guards.
|
|
164
164
|
|
|
165
165
|
Opaque asset declarations use `Asset(host, asset, preimage)`. The preimage
|
|
166
166
|
starts with a one-byte format/hash tag, letting offchain indexers or witnesses
|
|
@@ -258,7 +258,7 @@ The standard commands cover the common ledger movements: `deposit` and
|
|
|
258
258
|
`depositPayable` (external funds in), `withdraw` and `burn` (funds out),
|
|
259
259
|
`debitAccount` and `creditAccount` (internal movements), `payout` (deliver
|
|
260
260
|
state to other accounts), `provision` (allocate custody on another host), and
|
|
261
|
-
`relayPayable` (hand a pipeline to another
|
|
261
|
+
`relayPayable` (hand a pipeline to another portal).
|
|
262
262
|
|
|
263
263
|
## Pipelines
|
|
264
264
|
|
|
@@ -285,9 +285,9 @@ if (state.length != 0) revert UnexpectedState();
|
|
|
285
285
|
A transfer, for instance, is a two-step pipeline: `debitAccount` turns an
|
|
286
286
|
`#amount` request into `#balance` state, and `payout` consumes that state
|
|
287
287
|
toward a recipient. Because a pipeline is just blocks, it is also the unit of
|
|
288
|
-
command batching — and `resources` is a chain-
|
|
289
|
-
bits are native value in wei, drawn from a
|
|
290
|
-
bytes are meaningful to every port.
|
|
288
|
+
command batching — and `resources` is a chain-specific word interpreted by the
|
|
289
|
+
portal adapter (on EVM, the low 128 bits are native value in wei, drawn from a
|
|
290
|
+
shared budget), so the same pipeline bytes are meaningful to every port.
|
|
291
291
|
|
|
292
292
|
## Queries
|
|
293
293
|
|
|
@@ -314,10 +314,11 @@ central ones are batches all the way down:
|
|
|
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 against the
|
|
317
|
+
host, executed locally against the port call's shared value budget.
|
|
318
318
|
|
|
319
|
-
This is also the cross-
|
|
320
|
-
wraps a pipe and addresses it to a
|
|
319
|
+
This is also the cross-portal mechanism. `relayPayable` (or `portDispatchPayable`)
|
|
320
|
+
wraps a pipe and addresses it to a portal, commonly the destination host ID;
|
|
321
|
+
a bridge adapter moves the **raw
|
|
321
322
|
bytes**; the destination host parses them with the same cursor rules and runs
|
|
322
323
|
the same pipeline loop. Nothing in the payload is EVM-specific — step targets
|
|
323
324
|
are destination-local node IDs, and only the adapter boundary (native
|
|
@@ -350,8 +351,8 @@ names, access sets, balances — from logs alone, with no artifact files.
|
|
|
350
351
|
Import from the package entry points rather than deep paths:
|
|
351
352
|
|
|
352
353
|
- `@rootzero/contracts/Core.sol` — `Host`, access control, `Balances`,
|
|
353
|
-
`Pipeline`, validator
|
|
354
|
-
- `@rootzero/contracts/Endpoints.sol` — command, admin,
|
|
354
|
+
`Pipeline`, `Portal`, validator
|
|
355
|
+
- `@rootzero/contracts/Endpoints.sol` — command, admin, port, guard, and query
|
|
355
356
|
mixins and their hooks
|
|
356
357
|
- `@rootzero/contracts/Cursors.sol` — `Cur` cursor reader, `Writers`, `Schemas`,
|
|
357
358
|
`Keys`
|
|
@@ -363,7 +364,7 @@ Repo layout:
|
|
|
363
364
|
|
|
364
365
|
- `contracts/core` — host, access control, balances, pipeline, validation
|
|
365
366
|
- `contracts/commands` — standard commands and admin commands
|
|
366
|
-
- `contracts/ports` —
|
|
367
|
+
- `contracts/ports` — port surfaces for inter-host and cross-portal flows
|
|
367
368
|
- `contracts/guards` — guardian direct actions
|
|
368
369
|
- `contracts/queries` — read-only query endpoints
|
|
369
370
|
- `contracts/blocks` — block schema, cursor parsing, writers
|
package/blocks/Cursors.sol
CHANGED
|
@@ -519,7 +519,7 @@ library Cursors {
|
|
|
519
519
|
|
|
520
520
|
/// @notice Encode a STEP block.
|
|
521
521
|
/// @param target Command target identifier.
|
|
522
|
-
/// @param resources
|
|
522
|
+
/// @param resources Packed resources assigned to the step.
|
|
523
523
|
/// @param request Raw nested request payload.
|
|
524
524
|
/// @return Encoded STEP block bytes.
|
|
525
525
|
function toStepBlock(uint target, uint resources, bytes memory request) internal pure returns (bytes memory) {
|
|
@@ -528,7 +528,7 @@ library Cursors {
|
|
|
528
528
|
|
|
529
529
|
/// @notice Encode a CALL block.
|
|
530
530
|
/// @param target Target node identifier.
|
|
531
|
-
/// @param resources
|
|
531
|
+
/// @param resources Packed resources assigned to the call.
|
|
532
532
|
/// @param data Raw calldata payload for the target.
|
|
533
533
|
/// @return Encoded CALL block bytes.
|
|
534
534
|
function toCallBlock(uint target, uint resources, bytes memory data) internal pure returns (bytes memory) {
|
|
@@ -549,21 +549,21 @@ library Cursors {
|
|
|
549
549
|
}
|
|
550
550
|
|
|
551
551
|
/// @notice Encode a RELAY block.
|
|
552
|
-
/// @param
|
|
553
|
-
/// @param resources Chain-
|
|
552
|
+
/// @param portal Destination portal identifier, often the destination host ID.
|
|
553
|
+
/// @param resources Chain-specific resources for the destination context.
|
|
554
554
|
/// @param request Nested request block stream.
|
|
555
555
|
/// @return Encoded RELAY block bytes.
|
|
556
|
-
function toRelayBlock(uint
|
|
557
|
-
return createBlock(Keys.Relay, bytes.concat(bytes32(
|
|
556
|
+
function toRelayBlock(uint portal, uint resources, bytes memory request) internal pure returns (bytes memory) {
|
|
557
|
+
return createBlock(Keys.Relay, bytes.concat(bytes32(portal), bytes32(resources), toBytesBlock(request)));
|
|
558
558
|
}
|
|
559
559
|
|
|
560
560
|
/// @notice Encode a DISPATCH block.
|
|
561
|
-
/// @param
|
|
562
|
-
/// @param resources Chain-
|
|
563
|
-
/// @param payload Encoded
|
|
561
|
+
/// @param portal Destination portal identifier, often the destination host ID.
|
|
562
|
+
/// @param resources Chain-specific resources for the destination dispatch.
|
|
563
|
+
/// @param payload Encoded payload.
|
|
564
564
|
/// @return Encoded DISPATCH block bytes.
|
|
565
|
-
function toDispatchBlock(uint
|
|
566
|
-
return createBlock(Keys.Dispatch, bytes.concat(bytes32(
|
|
565
|
+
function toDispatchBlock(uint portal, uint resources, bytes memory payload) internal pure returns (bytes memory) {
|
|
566
|
+
return createBlock(Keys.Dispatch, bytes.concat(bytes32(portal), bytes32(resources), toBytesBlock(payload)));
|
|
567
567
|
}
|
|
568
568
|
|
|
569
569
|
// -------------------------------------------------------------------------
|
|
@@ -1100,7 +1100,7 @@ library Cursors {
|
|
|
1100
1100
|
/// The `req` slice is the raw payload of the block's required BYTES child.
|
|
1101
1101
|
/// @param cur Cursor; advanced past the block.
|
|
1102
1102
|
/// @return target Destination node ID for the sub-command.
|
|
1103
|
-
/// @return resources
|
|
1103
|
+
/// @return resources Packed resources assigned to the step.
|
|
1104
1104
|
/// @return req Embedded request bytes for the sub-command.
|
|
1105
1105
|
function unpackStep(Cur memory cur) internal pure returns (uint target, uint resources, bytes calldata req) {
|
|
1106
1106
|
uint end = cur.enter(Keys.Step, 64 + Sizes.Header, 0);
|
|
@@ -1114,7 +1114,7 @@ library Cursors {
|
|
|
1114
1114
|
/// The `data` slice is the raw payload of the block's required BYTES child.
|
|
1115
1115
|
/// @param cur Cursor; advanced past the block.
|
|
1116
1116
|
/// @return target Target node ID to call.
|
|
1117
|
-
/// @return resources
|
|
1117
|
+
/// @return resources Packed resources assigned to the call.
|
|
1118
1118
|
/// @return data Raw calldata payload for the target.
|
|
1119
1119
|
function unpackCall(Cur memory cur) internal pure returns (uint target, uint resources, bytes calldata data) {
|
|
1120
1120
|
uint end = cur.enter(Keys.Call, 64 + Sizes.Header, 0);
|
|
@@ -1140,50 +1140,50 @@ library Cursors {
|
|
|
1140
1140
|
cur.exit(end);
|
|
1141
1141
|
}
|
|
1142
1142
|
|
|
1143
|
-
/// @notice Consume a RELAY block and return its destination
|
|
1143
|
+
/// @notice Consume a RELAY block and return its destination portal, resources, and request stream.
|
|
1144
1144
|
/// @param cur Cursor; advanced past the block.
|
|
1145
|
-
/// @return
|
|
1146
|
-
/// @return resources Chain-
|
|
1145
|
+
/// @return portal Destination portal identifier, often the destination host ID.
|
|
1146
|
+
/// @return resources Chain-specific resources for the destination context.
|
|
1147
1147
|
/// @return request Embedded request block stream.
|
|
1148
1148
|
function unpackRelay(
|
|
1149
1149
|
Cur memory cur
|
|
1150
|
-
) internal pure returns (uint
|
|
1150
|
+
) internal pure returns (uint portal, uint resources, bytes calldata request) {
|
|
1151
1151
|
uint end = cur.enter(Keys.Relay, 64 + Sizes.Header, 0);
|
|
1152
|
-
|
|
1152
|
+
portal = cur.readUint();
|
|
1153
1153
|
resources = cur.readUint();
|
|
1154
1154
|
request = cur.unpackBytes();
|
|
1155
1155
|
cur.exit(end);
|
|
1156
1156
|
}
|
|
1157
1157
|
|
|
1158
|
-
/// @notice Consume a DISPATCH block and return its destination
|
|
1158
|
+
/// @notice Consume a DISPATCH block and return its destination portal, resources, and payload.
|
|
1159
1159
|
/// @param cur Cursor; advanced past the block.
|
|
1160
|
-
/// @return
|
|
1161
|
-
/// @return resources Chain-
|
|
1162
|
-
/// @return payload Encoded
|
|
1160
|
+
/// @return portal Destination portal identifier, often the destination host ID.
|
|
1161
|
+
/// @return resources Chain-specific resources for the destination dispatch.
|
|
1162
|
+
/// @return payload Encoded payload.
|
|
1163
1163
|
function unpackDispatch(
|
|
1164
1164
|
Cur memory cur
|
|
1165
|
-
) internal pure returns (uint
|
|
1165
|
+
) internal pure returns (uint portal, uint resources, bytes calldata payload) {
|
|
1166
1166
|
uint end = cur.enter(Keys.Dispatch, 64 + Sizes.Header, 0);
|
|
1167
|
-
|
|
1167
|
+
portal = cur.readUint();
|
|
1168
1168
|
resources = cur.readUint();
|
|
1169
1169
|
payload = cur.unpackBytes();
|
|
1170
1170
|
cur.exit(end);
|
|
1171
1171
|
}
|
|
1172
1172
|
|
|
1173
|
-
/// @notice Consume a
|
|
1173
|
+
/// @notice Consume a RECOVER block and return its handler, resources, key, and witness bytes.
|
|
1174
1174
|
/// @param cur Cursor; advanced past the block.
|
|
1175
|
-
/// @return
|
|
1176
|
-
/// @return
|
|
1177
|
-
/// @return
|
|
1178
|
-
/// @return
|
|
1179
|
-
function
|
|
1175
|
+
/// @return handler Recovery handler port node ID.
|
|
1176
|
+
/// @return resources Packed resources assigned to the recovery attempt.
|
|
1177
|
+
/// @return key Recovery lookup key.
|
|
1178
|
+
/// @return witness Witness bytes used by the recovery handler.
|
|
1179
|
+
function unpackRecover(
|
|
1180
1180
|
Cur memory cur
|
|
1181
|
-
) internal pure returns (uint
|
|
1182
|
-
uint end = cur.enter(Keys.
|
|
1183
|
-
|
|
1184
|
-
key = cur.read32();
|
|
1181
|
+
) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness) {
|
|
1182
|
+
uint end = cur.enter(Keys.Recover, 96 + Sizes.Header, 0);
|
|
1183
|
+
handler = cur.readUint();
|
|
1185
1184
|
resources = cur.readUint();
|
|
1186
|
-
|
|
1185
|
+
key = cur.read32();
|
|
1186
|
+
witness = cur.unpackBytes();
|
|
1187
1187
|
cur.exit(end);
|
|
1188
1188
|
}
|
|
1189
1189
|
|
|
@@ -1379,16 +1379,16 @@ library Cursors {
|
|
|
1379
1379
|
/// @param cur Cursor; advanced past the RELAY block.
|
|
1380
1380
|
/// @param account Account identifier to embed in the destination context.
|
|
1381
1381
|
/// @param state State block stream to embed in the destination context.
|
|
1382
|
-
/// @return
|
|
1383
|
-
/// @return resources Chain resources assigned to the destination context.
|
|
1382
|
+
/// @return portal Destination portal identifier, often the destination host ID.
|
|
1383
|
+
/// @return resources Chain-specific resources assigned to the destination context.
|
|
1384
1384
|
/// @return context Encoded CONTEXT block containing `account`, `state`, and relay request.
|
|
1385
1385
|
function relayToContext(
|
|
1386
1386
|
Cur memory cur,
|
|
1387
1387
|
bytes32 account,
|
|
1388
1388
|
bytes calldata state
|
|
1389
|
-
) internal pure returns (uint
|
|
1389
|
+
) internal pure returns (uint portal, uint resources, bytes memory context) {
|
|
1390
1390
|
bytes calldata request;
|
|
1391
|
-
(
|
|
1391
|
+
(portal, resources, request) = cur.unpackRelay();
|
|
1392
1392
|
context = toContextBlock(account, bytes(state), bytes(request));
|
|
1393
1393
|
}
|
|
1394
1394
|
|
package/blocks/Keys.sol
CHANGED
|
@@ -41,13 +41,13 @@ 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
|
|
44
|
+
/// @dev Portal relay request - (uint portal, uint resources, #bytes as request)
|
|
45
45
|
bytes4 constant Relay = bytes4(keccak256("#relay"));
|
|
46
46
|
/// @dev Command context transport - (bytes32 account, #bytes as state, #bytes as request)
|
|
47
47
|
bytes4 constant Context = bytes4(keccak256("#context"));
|
|
48
|
-
/// @dev Recoverable
|
|
49
|
-
bytes4 constant
|
|
50
|
-
/// @dev
|
|
48
|
+
/// @dev Recoverable witness - (uint handler, uint resources, bytes32 key, #bytes as witness)
|
|
49
|
+
bytes4 constant Recover = bytes4(keccak256("#recover"));
|
|
50
|
+
/// @dev Portal encoded payload dispatch - (uint portal, uint resources, #bytes as payload)
|
|
51
51
|
bytes4 constant Dispatch = bytes4(keccak256("#dispatch"));
|
|
52
52
|
/// @dev Raw external call - (uint target, uint resources, #bytes as payload)
|
|
53
53
|
bytes4 constant Call = bytes4(keccak256("#call"));
|
package/blocks/Schema.sol
CHANGED
|
@@ -16,10 +16,11 @@ pragma solidity ^0.8.33;
|
|
|
16
16
|
// - run items may repeat at top level for batching
|
|
17
17
|
// - `maybe #x { ... }` marks an optional block item
|
|
18
18
|
// - `many #x { ... }` emits one generic list block containing repeated `#x` items
|
|
19
|
-
// - `
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
19
|
+
// - `portal` fields are routing identifiers, often destination host IDs
|
|
20
|
+
// - `resources` fields are chain-specific resource words. A portal adapter
|
|
21
|
+
// interprets them for the destination runtime. EVM resources use the low
|
|
22
|
+
// 128 bits as native value.
|
|
23
|
+
// - dotted field names and aliases, e.g. `dst.portal` or `#bytes as dst.payload`,
|
|
23
24
|
// are offchain projection metadata only and do not change runtime encoding
|
|
24
25
|
// - a child block without an inline body, e.g. `#context as witness`, may resolve
|
|
25
26
|
// to a known schema in the active schema context; unresolved aliases are invalid
|
|
@@ -71,11 +72,11 @@ library Schemas {
|
|
|
71
72
|
string constant Allowance = "#allowance { uint host, bytes32 asset, uint amount }";
|
|
72
73
|
string constant Transaction = "#transaction { bytes32 from, bytes32 to, bytes32 asset, uint amount }";
|
|
73
74
|
string constant Context = "#context { bytes32 account, #bytes as state, #bytes as request }";
|
|
74
|
-
string constant
|
|
75
|
+
string constant Recover = "#recover { uint handler, uint resources, bytes32 key, #bytes as witness }";
|
|
75
76
|
string constant Call = "#call { uint target, uint resources, #bytes as payload }";
|
|
76
77
|
string constant Step = "#step { uint target, uint resources, #bytes as request }";
|
|
77
|
-
string constant Relay = "#relay { uint
|
|
78
|
-
string constant Dispatch = "#dispatch { uint
|
|
78
|
+
string constant Relay = "#relay { uint portal, uint resources, #bytes as request }";
|
|
79
|
+
string constant Dispatch = "#dispatch { uint portal, uint resources, #bytes as payload }";
|
|
79
80
|
string constant Bounty = "#bounty { uint amount, bytes32 relayer }";
|
|
80
81
|
string constant Fee = "#fee { uint amount }";
|
|
81
82
|
string constant Auth = "#auth { uint cid, uint deadline, #bytes as proof }";
|
package/blocks/Writers.sol
CHANGED
|
@@ -872,7 +872,7 @@ library Writers {
|
|
|
872
872
|
/// @notice Append a STEP block with a nested request BYTES payload.
|
|
873
873
|
/// @param writer Destination writer; `i` is advanced by the encoded STEP block length.
|
|
874
874
|
/// @param target Command target identifier.
|
|
875
|
-
/// @param resources
|
|
875
|
+
/// @param resources Packed resources assigned to the step.
|
|
876
876
|
/// @param request Raw nested request payload.
|
|
877
877
|
function appendStep(Writer memory writer, uint target, uint resources, bytes memory request) internal pure {
|
|
878
878
|
appendBlock64Bytes(writer, Keys.Step, bytes32(target), bytes32(resources), request);
|
|
@@ -881,7 +881,7 @@ library Writers {
|
|
|
881
881
|
/// @notice Append a CALL block with a nested payload BYTES block.
|
|
882
882
|
/// @param writer Destination writer; `i` is advanced by the encoded CALL block length.
|
|
883
883
|
/// @param target Call target identifier.
|
|
884
|
-
/// @param resources
|
|
884
|
+
/// @param resources Packed resources assigned to the call.
|
|
885
885
|
/// @param data Raw nested call payload.
|
|
886
886
|
function appendCall(Writer memory writer, uint target, uint resources, bytes memory data) internal pure {
|
|
887
887
|
appendBlock64Bytes(writer, Keys.Call, bytes32(target), bytes32(resources), data);
|
package/commands/Recover.sol
CHANGED
|
@@ -3,42 +3,35 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {CommandBase, CommandContext, Keys} from "./Base.sol";
|
|
5
5
|
import {Payable} from "../core/Payable.sol";
|
|
6
|
+
import {RecoverHook} from "../core/Portal.sol";
|
|
6
7
|
import {Cursors, Cur, Schemas} from "../Cursors.sol";
|
|
7
8
|
import {Budget} from "../utils/Value.sol";
|
|
8
9
|
|
|
9
10
|
using Cursors for Cur;
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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.
|
|
12
|
+
/// @title RecoverPayable
|
|
13
|
+
/// @notice Command that forwards recover request blocks to a virtual hook.
|
|
14
|
+
/// Recovery is witness-driven: the command account pays and receives leftover
|
|
15
|
+
/// value settlement, but the recovered subject is defined by each witness.
|
|
23
16
|
/// Produces no output state.
|
|
24
|
-
abstract contract
|
|
25
|
-
uint internal immutable
|
|
17
|
+
abstract contract RecoverPayable is CommandBase, Payable, RecoverHook {
|
|
18
|
+
uint internal immutable recoverPayableId = commandId(this.recoverPayable.selector);
|
|
26
19
|
|
|
27
20
|
constructor() {
|
|
28
|
-
emit Command(host,
|
|
29
|
-
emit Labeled(
|
|
21
|
+
emit Command(host, recoverPayableId, "1:0:0", Schemas.Recover, Keys.Empty, Keys.Empty, true);
|
|
22
|
+
emit Labeled(recoverPayableId, bytes32(0), "recoverPayable");
|
|
30
23
|
}
|
|
31
24
|
|
|
32
|
-
/// @notice Recover each
|
|
33
|
-
/// @param c Command context; `c.request` must contain
|
|
25
|
+
/// @notice Recover each recover block in the command request.
|
|
26
|
+
/// @param c Command context; `c.request` must contain Recover blocks.
|
|
34
27
|
/// @return Empty output state.
|
|
35
|
-
function
|
|
28
|
+
function recoverPayable(CommandContext calldata c) external payable onlyCommand returns (bytes memory) {
|
|
36
29
|
(Cur memory request, , ) = Cursors.init(c.request, 1);
|
|
37
30
|
Budget memory budget = openValue();
|
|
38
31
|
|
|
39
32
|
while (request.i < request.len) {
|
|
40
|
-
(uint
|
|
41
|
-
|
|
33
|
+
(uint handler, uint resources, bytes32 key, bytes calldata witness) = request.unpackRecover();
|
|
34
|
+
recover(handler, key, witness, useValue(budget, resources));
|
|
42
35
|
}
|
|
43
36
|
|
|
44
37
|
closeValue(c.account, budget);
|
package/commands/Relay.sol
CHANGED
|
@@ -3,28 +3,18 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {CommandBase, CommandContext, Keys} from "./Base.sol";
|
|
5
5
|
import {Payable} from "../core/Payable.sol";
|
|
6
|
+
import {RoutePayableHook} from "../core/Portal.sol";
|
|
6
7
|
import {Cursors, Cur, Schemas} from "../Cursors.sol";
|
|
7
8
|
import {Budget} from "../utils/Value.sol";
|
|
8
9
|
|
|
9
10
|
using Cursors for Cur;
|
|
10
11
|
|
|
11
|
-
abstract contract DispatchPayableHook {
|
|
12
|
-
/// @notice Override to dispatch an encoded payload to `chain`.
|
|
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 payload Encoded payload ready for the transport layer.
|
|
17
|
-
/// @param budget Source-chain native-value budget available for transport
|
|
18
|
-
/// fees and destination resource funding.
|
|
19
|
-
function dispatch(uint chain, uint resources, bytes memory payload, Budget memory budget) internal virtual;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
12
|
/// @title RelayPayable
|
|
23
13
|
/// @notice Command that forwards one RELAY block to a host-defined relay hook.
|
|
24
14
|
/// Reverts unless the request contains exactly one RELAY block, preventing
|
|
25
15
|
/// the same state from being duplicated across multiple relays.
|
|
26
16
|
/// Produces no output state.
|
|
27
|
-
abstract contract RelayPayable is CommandBase, Payable,
|
|
17
|
+
abstract contract RelayPayable is CommandBase, Payable, RoutePayableHook {
|
|
28
18
|
uint internal immutable relayPayableId = commandId(this.relayPayable.selector);
|
|
29
19
|
|
|
30
20
|
constructor() {
|
|
@@ -39,9 +29,9 @@ abstract contract RelayPayable is CommandBase, Payable, DispatchPayableHook {
|
|
|
39
29
|
(Cur memory request, ) = Cursors.init(c.request, 1, 1);
|
|
40
30
|
Budget memory budget = openValue();
|
|
41
31
|
|
|
42
|
-
(uint
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
(uint portal, uint resources, bytes memory context) = request.relayToContext(c.account, c.state);
|
|
33
|
+
route(portal, resources, context, budget);
|
|
34
|
+
|
|
45
35
|
closeValue(c.account, budget);
|
|
46
36
|
request.complete();
|
|
47
37
|
return "";
|
|
@@ -18,6 +18,7 @@ abstract contract DestroyHook {
|
|
|
18
18
|
abstract contract Destroy is AdminBase, DestroyHook {
|
|
19
19
|
uint internal immutable destroyId = commandId(this.destroy.selector);
|
|
20
20
|
|
|
21
|
+
/// @param input Request schema advertised for destruction input.
|
|
21
22
|
constructor(string memory input) {
|
|
22
23
|
emit Admin(host, destroyId, "1:0:0", input, Keys.Empty, Keys.Empty, false);
|
|
23
24
|
emit Labeled(destroyId, bytes32(0), "destroy");
|
|
@@ -10,7 +10,7 @@ using Cursors for Cur;
|
|
|
10
10
|
|
|
11
11
|
/// @title ExecutePayable
|
|
12
12
|
/// @notice Admin command that forwards raw calldata to one or more target nodes.
|
|
13
|
-
/// Each CALL block specifies a target node ID,
|
|
13
|
+
/// Each CALL block specifies a target node ID, packed resources, and raw calldata payload.
|
|
14
14
|
/// Only callable by the admin account.
|
|
15
15
|
/// Unspent top-level `msg.value` remains on this host.
|
|
16
16
|
abstract contract ExecutePayable is AdminBase, Payable {
|
package/commands/admin/Init.sol
CHANGED
|
@@ -18,6 +18,7 @@ abstract contract InitHook {
|
|
|
18
18
|
abstract contract Init is AdminBase, InitHook {
|
|
19
19
|
uint internal immutable initId = commandId(this.init.selector);
|
|
20
20
|
|
|
21
|
+
/// @param input Request schema advertised for initialization input.
|
|
21
22
|
constructor(string memory input) {
|
|
22
23
|
emit Admin(host, initId, "1:0:0", input, Keys.Empty, Keys.Empty, false);
|
|
23
24
|
emit Labeled(initId, bytes32(0), "init");
|
package/core/Access.sol
CHANGED
|
@@ -30,6 +30,7 @@ abstract contract AccessControl is Runtime, NodeEvent, GuardianEvent {
|
|
|
30
30
|
/// @dev Thrown when a caller, account, or node lacks required access.
|
|
31
31
|
error AccessDenied();
|
|
32
32
|
|
|
33
|
+
/// @param cmdr Commander address, or zero to make this contract self-managed.
|
|
33
34
|
constructor(address cmdr) {
|
|
34
35
|
commander = addrOr(cmdr, address(this));
|
|
35
36
|
admin = Accounts.toAdmin(commander);
|
package/core/Calls.sol
CHANGED
|
@@ -107,12 +107,23 @@ abstract contract CommandCalls is NodeCalls {
|
|
|
107
107
|
/// @title PortCalls
|
|
108
108
|
/// @notice Trusted port-call helpers for contracts that route port nodes.
|
|
109
109
|
abstract contract PortCalls is NodeCalls {
|
|
110
|
+
/// @notice Try to encode and call a trusted port node.
|
|
111
|
+
/// @param port Port node ID embedding the target selector.
|
|
112
|
+
/// @param value Native value to forward in wei.
|
|
113
|
+
/// @param input Port input block stream.
|
|
114
|
+
/// @return success True if the low-level port call succeeded.
|
|
115
|
+
function tryCallPort(uint port, uint128 value, bytes calldata input) internal returns (bool success) {
|
|
116
|
+
bytes4 selector = Nodes.portSelector(port);
|
|
117
|
+
bytes memory data = abi.encodeWithSelector(selector, input);
|
|
118
|
+
return tryTrustedCall(port, value, data);
|
|
119
|
+
}
|
|
120
|
+
|
|
110
121
|
/// @notice Encode and call a trusted port node.
|
|
111
122
|
/// @param port Port node ID embedding the target selector.
|
|
112
123
|
/// @param value Native value to forward in wei.
|
|
113
124
|
/// @param input Port input block stream.
|
|
114
125
|
/// @return Decoded port output block stream.
|
|
115
|
-
function callPort(uint port, uint128 value, bytes
|
|
126
|
+
function callPort(uint port, uint128 value, bytes calldata input) internal returns (bytes memory) {
|
|
116
127
|
bytes4 selector = Nodes.portSelector(port);
|
|
117
128
|
bytes memory data = abi.encodeWithSelector(selector, input);
|
|
118
129
|
return abi.decode(trustedCall(port, value, data), (bytes));
|
package/core/Payable.sol
CHANGED
|
@@ -19,7 +19,7 @@ abstract contract Payable {
|
|
|
19
19
|
/// @notice Deduct the EVM value lane from a packed resource word and return it.
|
|
20
20
|
/// @dev EVM resources use the low 128 bits as native value/endowment.
|
|
21
21
|
/// @param budget Mutable budget to deduct from.
|
|
22
|
-
/// @param resources Packed
|
|
22
|
+
/// @param resources Packed resources.
|
|
23
23
|
/// @return value Native value to forward in wei.
|
|
24
24
|
function useValue(Budget memory budget, uint resources) internal pure returns (uint128 value) {
|
|
25
25
|
value = uint128(resources);
|
package/core/Portal.sol
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {PortCalls} from "./Calls.sol";
|
|
5
|
+
import {ResolvedEvent} from "../events/Resolved.sol";
|
|
6
|
+
import {UndeliveredEvent} from "../events/Undelivered.sol";
|
|
7
|
+
import {Budget} from "../utils/Value.sol";
|
|
8
|
+
|
|
9
|
+
abstract contract RoutePayableHook {
|
|
10
|
+
/// @notice Override to route an encoded payload through `portal`.
|
|
11
|
+
/// @param portal Destination portal identifier, often the destination host ID.
|
|
12
|
+
/// @param resources Chain-specific destination resources. EVM adapters
|
|
13
|
+
/// may interpret this as packed execution gas and destination value.
|
|
14
|
+
/// @param payload Encoded payload ready for the transport layer.
|
|
15
|
+
/// @param budget Source native-value budget available for transport
|
|
16
|
+
/// fees and destination resource funding.
|
|
17
|
+
function route(uint portal, uint resources, bytes memory payload, Budget memory budget) internal virtual;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
abstract contract RecoverHook {
|
|
21
|
+
/// @notice Override to recover a previously undelivered witness through `handler`.
|
|
22
|
+
/// @param handler Port that should attempt recovery.
|
|
23
|
+
/// @param key Recovery lookup key.
|
|
24
|
+
/// @param witness Witness payload used to prove and replay recovery.
|
|
25
|
+
/// @param value Native EVM value assigned to the recovery attempt.
|
|
26
|
+
function recover(uint handler, bytes32 key, bytes calldata witness, uint128 value) internal virtual;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// @title Portal
|
|
30
|
+
/// @notice Base contract for hosts that route payloads through portal adapters.
|
|
31
|
+
abstract contract Portal is PortCalls, RecoverHook, ResolvedEvent, UndeliveredEvent {
|
|
32
|
+
error BadWitness();
|
|
33
|
+
|
|
34
|
+
/// @dev Remote port used to handle messages delivered through this portal.
|
|
35
|
+
uint private immutable port;
|
|
36
|
+
|
|
37
|
+
mapping(bytes32 key => bytes32 digest) internal undelivered;
|
|
38
|
+
|
|
39
|
+
/// @param handler Remote port used to handle messages delivered through this portal.
|
|
40
|
+
constructor(uint handler) {
|
|
41
|
+
port = handler;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// @notice Try to deliver `message` to this portal's handler port.
|
|
45
|
+
/// @dev Records `keccak256(message)` under `key` only when delivery fails.
|
|
46
|
+
/// @param key Delivery/recovery lookup key.
|
|
47
|
+
/// @param message Encoded port input to deliver.
|
|
48
|
+
/// @param value Native EVM value assigned to the delivery attempt.
|
|
49
|
+
function deliver(bytes32 key, bytes calldata message, uint128 value) internal {
|
|
50
|
+
if (tryCallPort(port, value, message)) return;
|
|
51
|
+
bytes32 digest = keccak256(message);
|
|
52
|
+
undelivered[key] = digest;
|
|
53
|
+
emit Undelivered(host, key, digest);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// @notice Recover a previously undelivered witness through `handler`.
|
|
57
|
+
/// @dev The witness must hash to the digest stored under `key`.
|
|
58
|
+
/// @param handler Port that should attempt recovery.
|
|
59
|
+
/// @param key Recovery lookup key.
|
|
60
|
+
/// @param witness Witness payload used to prove and replay recovery.
|
|
61
|
+
/// @param value Native EVM value assigned to the recovery attempt.
|
|
62
|
+
function recover(uint handler, bytes32 key, bytes calldata witness, uint128 value) internal virtual override {
|
|
63
|
+
if (keccak256(witness) != undelivered[key]) revert BadWitness();
|
|
64
|
+
delete undelivered[key];
|
|
65
|
+
callPort(handler, value, witness);
|
|
66
|
+
emit Resolved(host, key);
|
|
67
|
+
}
|
|
68
|
+
}
|
package/docs/Schema.md
CHANGED
|
@@ -120,7 +120,7 @@ Aliases may be used on any block item, including child blocks and prime items.
|
|
|
120
120
|
A child block without an inline body may also be used as a schema reference:
|
|
121
121
|
|
|
122
122
|
```txt
|
|
123
|
-
#
|
|
123
|
+
#recover { uint handler, uint resources, bytes32 key, #bytes as witness }
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
Alias resolution is context-dependent. A consumer may resolve `#context` from the
|
|
@@ -136,13 +136,13 @@ path does not change the block key, payload bytes, payload length, cursor
|
|
|
136
136
|
behavior, or any onchain validation. It is metadata only.
|
|
137
137
|
|
|
138
138
|
```txt
|
|
139
|
-
#dispatch { uint dst.
|
|
139
|
+
#dispatch { uint dst.portal, uint dst.resources, #bytes as dst.payload }
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
This has the same runtime layout as:
|
|
143
143
|
|
|
144
144
|
```txt
|
|
145
|
-
#dispatch { uint
|
|
145
|
+
#dispatch { uint portal, uint resources, #bytes as payload }
|
|
146
146
|
```
|
|
147
147
|
|
|
148
148
|
Offchain tooling may decode the dotted form into a nested object:
|
|
@@ -150,7 +150,7 @@ Offchain tooling may decode the dotted form into a nested object:
|
|
|
150
150
|
```ts
|
|
151
151
|
{
|
|
152
152
|
dst: {
|
|
153
|
-
|
|
153
|
+
portal,
|
|
154
154
|
resources,
|
|
155
155
|
payload
|
|
156
156
|
}
|
|
@@ -165,8 +165,8 @@ object.
|
|
|
165
165
|
Tooling should reject duplicate full paths and prefix/value collisions:
|
|
166
166
|
|
|
167
167
|
```txt
|
|
168
|
-
uint dst.
|
|
169
|
-
uint dst, uint dst.
|
|
168
|
+
uint dst.portal, uint dst.portal // duplicate path
|
|
169
|
+
uint dst, uint dst.portal // prefix/value collision
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
The same rule applies to block aliases:
|
|
@@ -196,10 +196,14 @@ true. `bytesN` values are encoded as exactly `N` bytes with no padding.
|
|
|
196
196
|
|
|
197
197
|
## Chain Resources
|
|
198
198
|
|
|
199
|
-
Fields named `
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
Fields named `portal` are routing identifiers; they are often the destination
|
|
200
|
+
host ID, but a transport adapter may define a different stable handle.
|
|
201
|
+
|
|
202
|
+
Fields named `resources` are chain-specific resource words. A portal adapter
|
|
203
|
+
interprets them for the destination runtime. Different runtimes may pack these
|
|
204
|
+
words differently, but a given runtime must use one stable format everywhere.
|
|
205
|
+
For EVM chains, the low 128 bits are native value / endowment in wei; higher
|
|
206
|
+
bits are reserved for execution resources such as gas.
|
|
203
207
|
|
|
204
208
|
## Protocol IDs
|
|
205
209
|
|
|
@@ -282,7 +286,7 @@ Common protocol schemas live in `contracts/blocks/Schema.sol`:
|
|
|
282
286
|
#call { uint target, uint resources, #bytes as payload }
|
|
283
287
|
#step { uint target, uint resources, #bytes as request }
|
|
284
288
|
#context { bytes32 account, #bytes as state, #bytes as request }
|
|
285
|
-
#
|
|
289
|
+
#recover { uint handler, uint resources, bytes32 key, #bytes as witness }
|
|
286
290
|
#auth { uint cid, uint deadline, #bytes as proof }
|
|
287
291
|
```
|
|
288
292
|
|
package/events/Dispatch.sol
CHANGED
|
@@ -5,14 +5,14 @@ import {EventEmitter} from "./Emitter.sol";
|
|
|
5
5
|
|
|
6
6
|
/// @notice Emitted when a host records an outbound dispatch reference.
|
|
7
7
|
abstract contract DispatchEvent is EventEmitter {
|
|
8
|
-
string private constant ABI = "event Dispatch(uint indexed host, uint
|
|
8
|
+
string private constant ABI = "event Dispatch(uint indexed host, uint portal, uint resources, bytes32 key, bytes32 digest)";
|
|
9
9
|
|
|
10
10
|
/// @param host Host node ID that owns the dispatch.
|
|
11
|
-
/// @param
|
|
12
|
-
/// @param resources Chain-
|
|
11
|
+
/// @param portal Destination portal identifier, often the destination host ID.
|
|
12
|
+
/// @param resources Chain-specific resources assigned to the dispatch.
|
|
13
|
+
/// @param key Dispatch correlation or recovery lookup key.
|
|
13
14
|
/// @param digest Digest of the dispatched payload or canonical envelope.
|
|
14
|
-
|
|
15
|
-
event Dispatch(uint indexed host, uint chain, uint resources, bytes32 digest, bytes32 ref);
|
|
15
|
+
event Dispatch(uint indexed host, uint portal, uint resources, bytes32 key, bytes32 digest);
|
|
16
16
|
|
|
17
17
|
constructor() {
|
|
18
18
|
emit EventAbi(ABI);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {EventEmitter} from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
/// @notice Emitted when a host resolves a previously recorded key.
|
|
7
|
+
abstract contract ResolvedEvent is EventEmitter {
|
|
8
|
+
string private constant ABI = "event Resolved(uint indexed host, bytes32 key)";
|
|
9
|
+
|
|
10
|
+
/// @param host Host node ID that owns the resolved key.
|
|
11
|
+
/// @param key Resolution lookup key.
|
|
12
|
+
event Resolved(uint indexed host, bytes32 key);
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
emit EventAbi(ABI);
|
|
16
|
+
}
|
|
17
|
+
}
|
package/events/Route.sol
CHANGED
|
@@ -3,14 +3,14 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {EventEmitter} from "./Emitter.sol";
|
|
5
5
|
|
|
6
|
-
/// @notice Emitted when a host
|
|
6
|
+
/// @notice Emitted when a host updates a portal route.
|
|
7
7
|
abstract contract RouteEvent is EventEmitter {
|
|
8
|
-
string private constant ABI = "event Route(uint indexed host, uint
|
|
8
|
+
string private constant ABI = "event Route(uint indexed host, uint portal, uint status)";
|
|
9
9
|
|
|
10
10
|
/// @param host Host node ID that owns the route.
|
|
11
|
-
/// @param
|
|
12
|
-
/// @param
|
|
13
|
-
event Route(uint indexed host, uint
|
|
11
|
+
/// @param portal Destination portal identifier, often the destination host ID.
|
|
12
|
+
/// @param status Route status. Zero means inactive; nonzero means active.
|
|
13
|
+
event Route(uint indexed host, uint portal, uint status);
|
|
14
14
|
|
|
15
15
|
constructor() {
|
|
16
16
|
emit EventAbi(ABI);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {EventEmitter} from "./Emitter.sol";
|
|
5
|
+
|
|
6
|
+
/// @notice Emitted when a host records an undelivered portal message.
|
|
7
|
+
abstract contract UndeliveredEvent is EventEmitter {
|
|
8
|
+
string private constant ABI = "event Undelivered(uint indexed host, bytes32 key, bytes32 digest)";
|
|
9
|
+
|
|
10
|
+
/// @param host Host node ID that owns the undelivered message.
|
|
11
|
+
/// @param key Delivery lookup key.
|
|
12
|
+
/// @param digest Digest of the undelivered message.
|
|
13
|
+
event Undelivered(uint indexed host, bytes32 key, bytes32 digest);
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
emit EventAbi(ABI);
|
|
17
|
+
}
|
|
18
|
+
}
|
package/package.json
CHANGED
package/ports/Dispatch.sol
CHANGED
|
@@ -3,15 +3,15 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import { PortBase } from "./Base.sol";
|
|
5
5
|
import { Payable } from "../core/Payable.sol";
|
|
6
|
+
import { RoutePayableHook } from "../core/Portal.sol";
|
|
6
7
|
import { Cursors, Cur, Schemas } from "../Cursors.sol";
|
|
7
|
-
import { DispatchPayableHook } from "../commands/Relay.sol";
|
|
8
8
|
import { Budget } from "../utils/Value.sol";
|
|
9
9
|
|
|
10
10
|
using Cursors for Cur;
|
|
11
11
|
|
|
12
12
|
/// @title PortDispatchPayable
|
|
13
|
-
/// @notice Port endpoint that forwards DISPATCH blocks to a host-defined
|
|
14
|
-
abstract contract PortDispatchPayable is PortBase, Payable,
|
|
13
|
+
/// @notice Port endpoint that forwards DISPATCH blocks to a host-defined route hook.
|
|
14
|
+
abstract contract PortDispatchPayable is PortBase, Payable, RoutePayableHook {
|
|
15
15
|
uint internal immutable portDispatchPayableId = portId(this.portDispatchPayable.selector);
|
|
16
16
|
|
|
17
17
|
constructor() {
|
|
@@ -19,8 +19,8 @@ abstract contract PortDispatchPayable is PortBase, Payable, DispatchPayableHook
|
|
|
19
19
|
emit Labeled(portDispatchPayableId, bytes32(0), "portDispatchPayable");
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/// @notice Forward peer-supplied dispatches to the host-defined
|
|
23
|
-
/// @dev
|
|
22
|
+
/// @notice Forward peer-supplied dispatches to the host-defined route hook.
|
|
23
|
+
/// @dev Route hooks receive the shared top-level source value
|
|
24
24
|
/// budget. Any `msg.value` not spent by the hook remains on this host.
|
|
25
25
|
/// @param data DISPATCH block stream supplied by the trusted peer.
|
|
26
26
|
/// @return output Empty response bytes.
|
|
@@ -29,8 +29,8 @@ abstract contract PortDispatchPayable is PortBase, Payable, DispatchPayableHook
|
|
|
29
29
|
Budget memory budget = openValue();
|
|
30
30
|
|
|
31
31
|
while (input.i < input.len) {
|
|
32
|
-
(uint
|
|
33
|
-
|
|
32
|
+
(uint portal, uint resources, bytes calldata payload) = input.unpackDispatch();
|
|
33
|
+
route(portal, resources, bytes(payload), budget);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
input.complete();
|
package/queries/Positions.sol
CHANGED
|
@@ -29,6 +29,7 @@ abstract contract GetPositionHook {
|
|
|
29
29
|
abstract contract GetPosition is QueryBase, GetPositionHook {
|
|
30
30
|
uint public immutable getPositionId = queryId(this.getPosition.selector);
|
|
31
31
|
|
|
32
|
+
/// @param output Response schema advertised for each position output block.
|
|
32
33
|
constructor(string memory output) {
|
|
33
34
|
emit Query(host, getPositionId, "1:1", Forms.AccountAsset, output);
|
|
34
35
|
emit Labeled(getPositionId, bytes32(0), "getPosition");
|
package/core/Commitments.sol
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
-
pragma solidity ^0.8.33;
|
|
3
|
-
|
|
4
|
-
import {CommitmentEvent} from "../events/Commitment.sol";
|
|
5
|
-
|
|
6
|
-
/// @title Commitments
|
|
7
|
-
/// @notice On-chain registry for digest commitments.
|
|
8
|
-
abstract contract Commitments is CommitmentEvent {
|
|
9
|
-
/// @dev key -> committed digest.
|
|
10
|
-
mapping(bytes32 key => bytes32 digest) internal commitments;
|
|
11
|
-
|
|
12
|
-
/// @notice Clear the commitment under `key` and return the removed digest.
|
|
13
|
-
/// @param key Commitment lookup key.
|
|
14
|
-
/// @return digest Removed digest.
|
|
15
|
-
function uncommit(bytes32 key) internal returns (bytes32 digest) {
|
|
16
|
-
digest = commitments[key];
|
|
17
|
-
delete commitments[key];
|
|
18
|
-
}
|
|
19
|
-
}
|
package/events/Commitment.sol
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
-
pragma solidity ^0.8.33;
|
|
3
|
-
|
|
4
|
-
import { EventEmitter } from "./Emitter.sol";
|
|
5
|
-
|
|
6
|
-
/// @notice Emitted when a host-scoped commitment is updated.
|
|
7
|
-
abstract contract CommitmentEvent is EventEmitter {
|
|
8
|
-
string private constant ABI = "event Commitment(uint indexed host, bytes32 key, bytes32 digest, uint status)";
|
|
9
|
-
|
|
10
|
-
/// @param host Host node ID that manages the commitment.
|
|
11
|
-
/// @param key Commitment lookup key.
|
|
12
|
-
/// @param digest Committed digest. Zero may be used when clearing without revealing the previous digest.
|
|
13
|
-
/// @param status Commitment status. Zero means cleared; nonzero means committed or application-defined.
|
|
14
|
-
event Commitment(uint indexed host, bytes32 key, bytes32 digest, uint status);
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
emit EventAbi(ABI);
|
|
18
|
-
}
|
|
19
|
-
}
|