@rootzero/contracts 0.9.8 → 1.0.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/Core.sol +1 -1
- package/Endpoints.sol +3 -1
- package/Events.sol +2 -0
- package/README.md +19 -18
- package/blocks/Cursors.sol +152 -162
- package/blocks/Keys.sol +10 -6
- package/blocks/Schema.sol +17 -9
- package/blocks/Writers.sol +4 -4
- package/commands/Burn.sol +7 -4
- package/commands/Credit.sol +9 -9
- package/commands/Debit.sol +7 -4
- package/commands/Deposit.sol +14 -8
- package/commands/Payout.sol +49 -0
- package/commands/Provision.sol +14 -8
- package/commands/Relay.sol +58 -0
- package/commands/Withdraw.sol +10 -9
- package/commands/admin/AllowAssets.sol +9 -4
- package/commands/admin/Allowance.sol +7 -4
- package/commands/admin/Appoint.sol +7 -4
- package/commands/admin/Authorize.sol +7 -4
- package/commands/admin/DenyAssets.sol +9 -4
- package/commands/admin/Destroy.sol +5 -3
- package/commands/admin/Dismiss.sol +7 -4
- package/commands/admin/Execute.sol +8 -5
- package/commands/admin/Init.sol +5 -3
- package/commands/admin/Unauthorize.sol +7 -4
- package/core/Host.sol +10 -1
- package/core/Pipeline.sol +4 -3
- package/core/Runtime.sol +3 -36
- package/core/Types.sol +1 -1
- package/docs/Schema.md +0 -1
- package/events/Admin.sol +11 -8
- package/events/Chain.sol +20 -0
- package/events/Command.sol +11 -8
- package/events/Peer.sol +5 -5
- package/events/Query.sol +2 -4
- package/events/Transfer.sol +22 -0
- package/guards/Revoke.sol +3 -3
- package/package.json +1 -1
- package/peer/AllowAssets.sol +5 -3
- package/peer/Allowance.sol +5 -3
- package/peer/BalancePull.sol +5 -3
- package/peer/DenyAssets.sol +5 -3
- package/peer/Dispatch.sol +51 -0
- package/peer/Pipe.sol +7 -5
- package/peer/Settle.sol +13 -8
- package/queries/Assets.sol +3 -3
- package/queries/Balances.sol +3 -3
- package/queries/Positions.sol +3 -3
- package/utils/Accounts.sol +6 -31
- package/utils/Actions.sol +11 -9
- 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/commands/Transfer.sol +0 -54
|
@@ -22,14 +22,16 @@ abstract contract Destroy is CommandBase, AdminEvent, DestroyHook {
|
|
|
22
22
|
uint internal immutable destroyId = commandId(NAME);
|
|
23
23
|
|
|
24
24
|
constructor(string memory input) {
|
|
25
|
-
emit Admin(host, destroyId, NAME, "1:0:0", input, Keys.Empty, Keys.Empty, false);
|
|
25
|
+
emit Admin(host, destroyId, NAME, "1:0:0", input, Keys.Empty, Keys.Empty, false, false);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/// @notice Run host teardown logic over the full admin request.
|
|
29
|
+
/// @param c Admin command context; `c.request` is passed through as a cursor.
|
|
30
|
+
/// @return Empty output state.
|
|
28
31
|
function destroy(
|
|
29
32
|
CommandContext calldata c
|
|
30
33
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
31
|
-
|
|
32
|
-
destroy(input);
|
|
34
|
+
destroy(Cursors.open(c.request));
|
|
33
35
|
return "";
|
|
34
36
|
}
|
|
35
37
|
}
|
|
@@ -16,20 +16,23 @@ abstract contract Dismiss is CommandBase, AdminEvent {
|
|
|
16
16
|
uint internal immutable dismissId = commandId(NAME);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
|
-
emit Admin(host, dismissId, NAME, "1:0:0", Schemas.Account, Keys.Empty, Keys.Empty, false);
|
|
19
|
+
emit Admin(host, dismissId, NAME, "1:0:0", Schemas.Account, Keys.Empty, Keys.Empty, false, false);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/// @notice Dismiss each ACCOUNT block in the admin request from guardian status.
|
|
23
|
+
/// @param c Admin command context; `c.request` must contain ACCOUNT blocks.
|
|
24
|
+
/// @return Empty output state.
|
|
22
25
|
function dismiss(
|
|
23
26
|
CommandContext calldata c
|
|
24
27
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
25
|
-
(Cur memory request, ) =
|
|
28
|
+
(Cur memory request, , ) = Cursors.init(c.request, 0, 1);
|
|
26
29
|
|
|
27
|
-
while (request.i < request.
|
|
30
|
+
while (request.i < request.len) {
|
|
28
31
|
bytes32 account = request.unpackAccount();
|
|
29
32
|
setGuardian(account, false);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
request.
|
|
35
|
+
request.complete();
|
|
33
36
|
return "";
|
|
34
37
|
}
|
|
35
38
|
}
|
|
@@ -14,27 +14,30 @@ using Cursors for Cur;
|
|
|
14
14
|
/// @notice Admin command that forwards raw calldata to one or more target nodes.
|
|
15
15
|
/// Each CALL block specifies a target node ID, native value, and raw calldata payload.
|
|
16
16
|
/// Only callable by the admin account.
|
|
17
|
+
/// Unspent top-level `msg.value` remains on this host.
|
|
17
18
|
abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
|
|
18
19
|
string private constant NAME = "executePayable";
|
|
19
20
|
|
|
20
21
|
uint internal immutable executePayableId = commandId(NAME);
|
|
21
22
|
|
|
22
23
|
constructor() {
|
|
23
|
-
emit Admin(host, executePayableId, NAME, "1:0:0", Schemas.Call, Keys.Empty, Keys.Empty, true);
|
|
24
|
+
emit Admin(host, executePayableId, NAME, "1:0:0", Schemas.Call, Keys.Empty, Keys.Empty, false, true);
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
/// @notice Execute each CALL block in the admin request.
|
|
28
|
+
/// @param c Admin command context; `c.request` must contain CALL blocks.
|
|
29
|
+
/// @return Empty output state.
|
|
26
30
|
function executePayable(CommandContext calldata c) external payable onlyAdmin(c.account) returns (bytes memory) {
|
|
27
|
-
(Cur memory request, ) =
|
|
31
|
+
(Cur memory request, , ) = Cursors.init(c.request, 0, 1);
|
|
28
32
|
Budget memory budget = valueBudget();
|
|
29
33
|
|
|
30
|
-
while (request.i < request.
|
|
34
|
+
while (request.i < request.len) {
|
|
31
35
|
(uint target, uint value, bytes calldata data) = request.unpackCall();
|
|
32
36
|
address addr = Ids.nodeAddr(target);
|
|
33
37
|
callAddr(addr, useValue(budget, value), data);
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
request.
|
|
37
|
-
settleValue(c.account, budget);
|
|
40
|
+
request.complete();
|
|
38
41
|
return "";
|
|
39
42
|
}
|
|
40
43
|
}
|
package/commands/admin/Init.sol
CHANGED
|
@@ -22,14 +22,16 @@ abstract contract Init is CommandBase, AdminEvent, InitHook {
|
|
|
22
22
|
uint internal immutable initId = commandId(NAME);
|
|
23
23
|
|
|
24
24
|
constructor(string memory input) {
|
|
25
|
-
emit Admin(host, initId, NAME, "1:0:0", input, Keys.Empty, Keys.Empty, false);
|
|
25
|
+
emit Admin(host, initId, NAME, "1:0:0", input, Keys.Empty, Keys.Empty, false, false);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/// @notice Run host initialization logic over the full admin request.
|
|
29
|
+
/// @param c Admin command context; `c.request` is passed through as a cursor.
|
|
30
|
+
/// @return Empty output state.
|
|
28
31
|
function init(
|
|
29
32
|
CommandContext calldata c
|
|
30
33
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
31
|
-
|
|
32
|
-
init(input);
|
|
34
|
+
init(Cursors.open(c.request));
|
|
33
35
|
return "";
|
|
34
36
|
}
|
|
35
37
|
}
|
|
@@ -16,20 +16,23 @@ abstract contract Unauthorize is CommandBase, AdminEvent {
|
|
|
16
16
|
uint internal immutable unauthorizeId = commandId(NAME);
|
|
17
17
|
|
|
18
18
|
constructor() {
|
|
19
|
-
emit Admin(host, unauthorizeId, NAME, "1:0:0", Schemas.Node, Keys.Empty, Keys.Empty, false);
|
|
19
|
+
emit Admin(host, unauthorizeId, NAME, "1:0:0", Schemas.Node, Keys.Empty, Keys.Empty, false, false);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/// @notice Unauthorize each NODE block in the admin request.
|
|
23
|
+
/// @param c Admin command context; `c.request` must contain NODE blocks.
|
|
24
|
+
/// @return Empty output state.
|
|
22
25
|
function unauthorize(
|
|
23
26
|
CommandContext calldata c
|
|
24
27
|
) external onlyAdmin(c.account) returns (bytes memory) {
|
|
25
|
-
(Cur memory request, ) =
|
|
28
|
+
(Cur memory request, , ) = Cursors.init(c.request, 0, 1);
|
|
26
29
|
|
|
27
|
-
while (request.i < request.
|
|
30
|
+
while (request.i < request.len) {
|
|
28
31
|
uint node = request.unpackNode();
|
|
29
32
|
setNode(node, false);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
request.
|
|
35
|
+
request.complete();
|
|
33
36
|
return "";
|
|
34
37
|
}
|
|
35
38
|
}
|
package/core/Host.sol
CHANGED
|
@@ -28,7 +28,16 @@ interface IHostIntroduction {
|
|
|
28
28
|
/// guardian management, the default guardian revoke action, and
|
|
29
29
|
/// optionally introduces itself to a commander host at deployment.
|
|
30
30
|
/// Accepts native ETH payments via the `receive` function.
|
|
31
|
-
abstract contract Host is
|
|
31
|
+
abstract contract Host is
|
|
32
|
+
Authorize,
|
|
33
|
+
Unauthorize,
|
|
34
|
+
Revoke,
|
|
35
|
+
Appoint,
|
|
36
|
+
Dismiss,
|
|
37
|
+
ExecutePayable,
|
|
38
|
+
IntroductionEvent,
|
|
39
|
+
IHostIntroduction
|
|
40
|
+
{
|
|
32
41
|
/// @param cmdr Commander address; passed to `AccessControl`.
|
|
33
42
|
/// If `cmdr` is a deployed contract, the host calls `introduce`
|
|
34
43
|
/// on it during construction.
|
package/core/Pipeline.sol
CHANGED
|
@@ -10,6 +10,7 @@ using Cursors for Cur;
|
|
|
10
10
|
/// @title Pipeline
|
|
11
11
|
/// @notice Core pipeline functionality shared by higher-level surfaces.
|
|
12
12
|
abstract contract Pipeline is Payable {
|
|
13
|
+
/// @dev Thrown when the pipeline finishes with non-empty threaded state.
|
|
13
14
|
error UnexpectedState();
|
|
14
15
|
|
|
15
16
|
/// @notice Override to dispatch one piped step.
|
|
@@ -41,15 +42,15 @@ abstract contract Pipeline is Payable {
|
|
|
41
42
|
bytes calldata steps,
|
|
42
43
|
Budget memory budget
|
|
43
44
|
) internal {
|
|
44
|
-
(Cur memory input, ) = Cursors.init(steps, 1);
|
|
45
|
+
(Cur memory input, , ) = Cursors.init(steps, 0, 1);
|
|
45
46
|
|
|
46
|
-
while (input.i < input.
|
|
47
|
+
while (input.i < input.len) {
|
|
47
48
|
(uint target, uint value, bytes calldata request) = input.unpackStep();
|
|
48
49
|
state = dispatch(target, account, state, request, useValue(budget, value));
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
if (state.length != 0) revert UnexpectedState();
|
|
52
53
|
settleValue(account, budget);
|
|
53
|
-
input.
|
|
54
|
+
input.complete();
|
|
54
55
|
}
|
|
55
56
|
}
|
package/core/Runtime.sol
CHANGED
|
@@ -1,47 +1,14 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {Cur, Cursors} from "../Cursors.sol";
|
|
5
4
|
import {Assets} from "../utils/Assets.sol";
|
|
6
5
|
import {Ids} from "../utils/Ids.sol";
|
|
7
6
|
|
|
8
|
-
using Cursors for Cur;
|
|
9
|
-
|
|
10
7
|
/// @title Runtime
|
|
11
|
-
/// @notice Shared runtime for host identity
|
|
8
|
+
/// @notice Shared runtime for host identity and native asset identity.
|
|
12
9
|
abstract contract Runtime {
|
|
13
10
|
/// @dev This contract's host node ID, set to `Ids.toHost(address(this))` at construction.
|
|
14
11
|
uint public immutable host = Ids.toHost(address(this));
|
|
15
|
-
/// @dev Asset ID for the native chain
|
|
16
|
-
bytes32 internal immutable
|
|
17
|
-
|
|
18
|
-
/// @notice Open a cursor over a calldata block stream.
|
|
19
|
-
/// @param source Calldata slice to parse.
|
|
20
|
-
/// @return cur Cursor positioned at the beginning of `source`.
|
|
21
|
-
function cursor(bytes calldata source) internal pure returns (Cur memory cur) {
|
|
22
|
-
return Cursors.open(source);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/// @notice Open a cursor and prime it for a grouped iteration pass in one call.
|
|
26
|
-
/// Equivalent to `open(source)` followed by `primeRun(group)`.
|
|
27
|
-
/// @param source Calldata slice to parse.
|
|
28
|
-
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
29
|
-
/// @return cur Cursor with `bound` set to the end of the first run.
|
|
30
|
-
/// @return groups Number of block groups in the run (`prime block count / group`).
|
|
31
|
-
function cursor(bytes calldata source, uint group) internal pure returns (Cur memory cur, uint groups) {
|
|
32
|
-
return Cursors.init(source, group);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/// @notice Open a cursor, prime it, and assert that its group count matches `expectedGroups`.
|
|
36
|
-
/// Equivalent to `open(source)` followed by `primeRun(group)` and a direct group-count equality check.
|
|
37
|
-
/// Reverts with `Cursors.BadRatio` when the group count does not match.
|
|
38
|
-
/// @param source Calldata slice to parse.
|
|
39
|
-
/// @param group Expected block group size (e.g. 1 for single, 2 for paired).
|
|
40
|
-
/// @param expectedGroups Required number of groups in the first run.
|
|
41
|
-
/// @return cur Cursor with `bound` set to the end of the first run.
|
|
42
|
-
function cursor(bytes calldata source, uint group, uint expectedGroups) internal pure returns (Cur memory cur) {
|
|
43
|
-
uint groups;
|
|
44
|
-
(cur, groups) = Cursors.init(source, group);
|
|
45
|
-
if (groups != expectedGroups) revert Cursors.BadRatio();
|
|
46
|
-
}
|
|
12
|
+
/// @dev Asset ID for the native chain coin/token, bound to the current chain at deployment.
|
|
13
|
+
bytes32 internal immutable nativeAsset = Assets.toNative();
|
|
47
14
|
}
|
package/core/Types.sol
CHANGED
|
@@ -21,7 +21,7 @@ struct AccountAsset {
|
|
|
21
21
|
bytes32 meta;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
/// @notice Account-scoped amount shape
|
|
24
|
+
/// @notice Account-scoped amount shape for requests, responses, and reporting.
|
|
25
25
|
struct AccountAmount {
|
|
26
26
|
/// @dev Account identifier.
|
|
27
27
|
bytes32 account;
|
package/docs/Schema.md
CHANGED
|
@@ -185,7 +185,6 @@ Common protocol schemas live in `contracts/blocks/Schema.sol`:
|
|
|
185
185
|
#amount { bytes32 asset, bytes32 meta, uint amount }
|
|
186
186
|
#balance { bytes32 asset, bytes32 meta, uint amount }
|
|
187
187
|
#custody { uint host, bytes32 asset, bytes32 meta, uint amount }
|
|
188
|
-
#payout { bytes32 account, bytes32 asset, bytes32 meta, uint amount }
|
|
189
188
|
#call { uint target, uint value, #bytes as payload }
|
|
190
189
|
#step { uint target, uint value, #bytes as request }
|
|
191
190
|
#context { bytes32 account, #bytes as state, #bytes as request }
|
package/events/Admin.sol
CHANGED
|
@@ -6,18 +6,20 @@ import { EventEmitter } from "./Emitter.sol";
|
|
|
6
6
|
/// @notice Emitted once per admin command during host deployment to publish its request schema and state keys.
|
|
7
7
|
abstract contract AdminEvent is EventEmitter {
|
|
8
8
|
string private constant ABI =
|
|
9
|
-
"event Admin(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool
|
|
9
|
+
"event Admin(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool postcheck, bool funded)";
|
|
10
10
|
|
|
11
11
|
/// @param host Host node ID that owns this admin command.
|
|
12
12
|
/// @param id Command node ID.
|
|
13
13
|
/// @param name Human-readable command name.
|
|
14
|
-
/// @param shape Per-operation
|
|
15
|
-
///
|
|
16
|
-
///
|
|
17
|
-
///
|
|
18
|
-
/// @param
|
|
14
|
+
/// @param shape Per-operation block counts encoded as `request:state:output`.
|
|
15
|
+
/// The request count covers only the input request run. If `postcheck` is true,
|
|
16
|
+
/// a constraint run follows the input run, or starts the request when `request`
|
|
17
|
+
/// is empty. State globals may follow the state run and are excluded.
|
|
18
|
+
/// @param request Schema DSL string describing the input request run, or empty if none.
|
|
19
|
+
/// @param state Block key expected for input state, `Keys.Empty`, or `Keys.Any`.
|
|
19
20
|
/// @param output Block key produced for output state, or `Keys.Empty`.
|
|
20
|
-
/// @param
|
|
21
|
+
/// @param postcheck Whether command output is validated after execution.
|
|
22
|
+
/// @param funded Whether the command entrypoint accepts nonzero `msg.value`.
|
|
21
23
|
event Admin(
|
|
22
24
|
uint indexed host,
|
|
23
25
|
uint id,
|
|
@@ -26,7 +28,8 @@ abstract contract AdminEvent is EventEmitter {
|
|
|
26
28
|
string request,
|
|
27
29
|
bytes4 state,
|
|
28
30
|
bytes4 output,
|
|
29
|
-
bool
|
|
31
|
+
bool postcheck,
|
|
32
|
+
bool funded
|
|
30
33
|
);
|
|
31
34
|
|
|
32
35
|
constructor() {
|
package/events/Chain.sol
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
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 chain/domain node is announced.
|
|
7
|
+
abstract contract ChainEvent is EventEmitter {
|
|
8
|
+
string private constant ABI = "event Chain(uint indexed chain, bytes32 native, uint commander, bytes32 admin, string name)";
|
|
9
|
+
|
|
10
|
+
/// @param chain Chain node ID.
|
|
11
|
+
/// @param native Native asset ID for the chain.
|
|
12
|
+
/// @param commander Commander host node ID for the chain.
|
|
13
|
+
/// @param admin Admin account for the commander host on the chain.
|
|
14
|
+
/// @param name Chain or domain name.
|
|
15
|
+
event Chain(uint indexed chain, bytes32 native, uint commander, bytes32 admin, string name);
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
emit EventAbi(ABI);
|
|
19
|
+
}
|
|
20
|
+
}
|
package/events/Command.sol
CHANGED
|
@@ -6,18 +6,20 @@ import { EventEmitter } from "./Emitter.sol";
|
|
|
6
6
|
/// @notice Emitted once per command during host deployment to publish its request schema and state keys.
|
|
7
7
|
abstract contract CommandEvent is EventEmitter {
|
|
8
8
|
string private constant ABI =
|
|
9
|
-
"event Command(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool
|
|
9
|
+
"event Command(uint indexed host, uint id, string name, bytes32 shape, string request, bytes4 state, bytes4 output, bool postcheck, bool funded)";
|
|
10
10
|
|
|
11
11
|
/// @param host Host node ID that owns this command.
|
|
12
12
|
/// @param id Command node ID.
|
|
13
13
|
/// @param name Human-readable command name.
|
|
14
|
-
/// @param shape Per-operation
|
|
15
|
-
///
|
|
16
|
-
///
|
|
17
|
-
///
|
|
18
|
-
/// @param
|
|
14
|
+
/// @param shape Per-operation block counts encoded as `request:state:output`.
|
|
15
|
+
/// The request count covers only the input request run. If `postcheck` is true,
|
|
16
|
+
/// a constraint run follows the input run, or starts the request when `request`
|
|
17
|
+
/// is empty. State globals may follow the state run and are excluded.
|
|
18
|
+
/// @param request Schema string describing the input request run, or empty if none.
|
|
19
|
+
/// @param state Block key expected for input state, `Keys.Empty`, or `Keys.Any`.
|
|
19
20
|
/// @param output Block key produced for output state, or `Keys.Empty`.
|
|
20
|
-
/// @param
|
|
21
|
+
/// @param postcheck Whether command output is validated after execution.
|
|
22
|
+
/// @param funded Whether the command entrypoint accepts nonzero `msg.value`.
|
|
21
23
|
event Command(
|
|
22
24
|
uint indexed host,
|
|
23
25
|
uint id,
|
|
@@ -26,7 +28,8 @@ abstract contract CommandEvent is EventEmitter {
|
|
|
26
28
|
string request,
|
|
27
29
|
bytes4 state,
|
|
28
30
|
bytes4 output,
|
|
29
|
-
bool
|
|
31
|
+
bool postcheck,
|
|
32
|
+
bool funded
|
|
30
33
|
);
|
|
31
34
|
|
|
32
35
|
constructor() {
|
package/events/Peer.sol
CHANGED
|
@@ -6,15 +6,15 @@ import {EventEmitter} from "./Emitter.sol";
|
|
|
6
6
|
/// @notice Emitted once per peer during host deployment to publish its request and response schemas.
|
|
7
7
|
abstract contract PeerEvent is EventEmitter {
|
|
8
8
|
string private constant ABI =
|
|
9
|
-
"event Peer(uint indexed host, uint id, string name, bytes32 shape, string request, string response, bool
|
|
9
|
+
"event Peer(uint indexed host, uint id, string name, bytes32 shape, string request, string response, bool funded)";
|
|
10
10
|
|
|
11
11
|
/// @param host Host node ID that owns this peer.
|
|
12
12
|
/// @param id Peer node ID.
|
|
13
13
|
/// @param name Human-readable peer name.
|
|
14
|
-
/// @param shape
|
|
15
|
-
/// @param request Schema DSL string describing the
|
|
14
|
+
/// @param shape Per-operation block counts encoded as `request:response`.
|
|
15
|
+
/// @param request Schema DSL string describing the input request run, or empty if none.
|
|
16
16
|
/// @param response Schema DSL string describing the peer response shape.
|
|
17
|
-
/// @param
|
|
17
|
+
/// @param funded Whether the peer entrypoint accepts nonzero `msg.value`.
|
|
18
18
|
event Peer(
|
|
19
19
|
uint indexed host,
|
|
20
20
|
uint id,
|
|
@@ -22,7 +22,7 @@ abstract contract PeerEvent is EventEmitter {
|
|
|
22
22
|
bytes32 shape,
|
|
23
23
|
string request,
|
|
24
24
|
string response,
|
|
25
|
-
bool
|
|
25
|
+
bool funded
|
|
26
26
|
);
|
|
27
27
|
|
|
28
28
|
constructor() {
|
package/events/Query.sol
CHANGED
|
@@ -10,10 +10,8 @@ abstract contract QueryEvent is EventEmitter {
|
|
|
10
10
|
/// @param host Host node ID that owns this query.
|
|
11
11
|
/// @param id Query node ID.
|
|
12
12
|
/// @param name Human-readable query name.
|
|
13
|
-
/// @param shape Per-operation
|
|
14
|
-
///
|
|
15
|
-
/// from the counts.
|
|
16
|
-
/// @param request Schema DSL string describing the query request shape.
|
|
13
|
+
/// @param shape Per-operation block counts encoded as `request:response`.
|
|
14
|
+
/// @param request Schema DSL string describing the input request run, or empty if none.
|
|
17
15
|
/// @param response Schema DSL string describing the query response shape.
|
|
18
16
|
event Query(uint indexed host, uint id, string name, bytes32 shape, string request, string response);
|
|
19
17
|
|
|
@@ -0,0 +1,22 @@
|
|
|
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 an asset moves from one account to another.
|
|
7
|
+
abstract contract TransferEvent is EventEmitter {
|
|
8
|
+
string private constant ABI = "event Transfer(bytes32 indexed from, bytes32 to, bytes32 asset, bytes32 meta, uint amount, uint32 action, uint context)";
|
|
9
|
+
|
|
10
|
+
/// @param account Source account identifier.
|
|
11
|
+
/// @param to Destination account identifier.
|
|
12
|
+
/// @param asset Asset identifier.
|
|
13
|
+
/// @param meta Asset metadata slot.
|
|
14
|
+
/// @param amount Amount transferred.
|
|
15
|
+
/// @param action Primary operation hint from `Actions`.
|
|
16
|
+
/// @param context Reserved context value for future use.
|
|
17
|
+
event Transfer(bytes32 indexed account, bytes32 to, bytes32 asset, bytes32 meta, uint amount, uint32 action, uint context);
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
emit EventAbi(ABI);
|
|
21
|
+
}
|
|
22
|
+
}
|
package/guards/Revoke.sol
CHANGED
|
@@ -19,13 +19,13 @@ abstract contract Revoke is GuardBase {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function revoke(bytes calldata request) external onlyGuardian {
|
|
22
|
-
(Cur memory input, ) =
|
|
22
|
+
(Cur memory input, , ) = Cursors.init(request, 0, 1);
|
|
23
23
|
|
|
24
|
-
while (input.i < input.
|
|
24
|
+
while (input.i < input.len) {
|
|
25
25
|
uint node = input.unpackNode();
|
|
26
26
|
setNode(node, false);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
input.
|
|
29
|
+
input.complete();
|
|
30
30
|
}
|
|
31
31
|
}
|
package/package.json
CHANGED
package/peer/AllowAssets.sol
CHANGED
|
@@ -19,15 +19,17 @@ abstract contract PeerAllowAssets is PeerBase, AllowAssetsHook {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/// @notice Execute the allow-assets peer call.
|
|
22
|
+
/// @param request ASSET block stream supplied by the trusted peer.
|
|
23
|
+
/// @return Empty response bytes.
|
|
22
24
|
function peerAllowAssets(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
23
|
-
(Cur memory assets, ) =
|
|
25
|
+
(Cur memory assets, , ) = Cursors.init(request, 0, 1);
|
|
24
26
|
|
|
25
|
-
while (assets.i < assets.
|
|
27
|
+
while (assets.i < assets.len) {
|
|
26
28
|
(bytes32 asset, bytes32 meta) = assets.unpackAsset();
|
|
27
29
|
allowAsset(asset, meta);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
assets.
|
|
32
|
+
assets.complete();
|
|
31
33
|
return "";
|
|
32
34
|
}
|
|
33
35
|
}
|
package/peer/Allowance.sol
CHANGED
|
@@ -20,16 +20,18 @@ abstract contract PeerAllowance is PeerBase, AllowanceHook {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/// @notice Execute the allowance peer call.
|
|
23
|
+
/// @param request AMOUNT block stream requested by the trusted peer.
|
|
24
|
+
/// @return Empty response bytes.
|
|
23
25
|
function peerAllowance(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
24
|
-
(Cur memory amounts, ) =
|
|
26
|
+
(Cur memory amounts, , ) = Cursors.init(request, 0, 1);
|
|
25
27
|
uint peer = caller();
|
|
26
28
|
|
|
27
|
-
while (amounts.i < amounts.
|
|
29
|
+
while (amounts.i < amounts.len) {
|
|
28
30
|
(bytes32 asset, bytes32 meta, uint amount) = amounts.unpackAmount();
|
|
29
31
|
allowance(peer, asset, meta, amount);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
amounts.
|
|
34
|
+
amounts.complete();
|
|
33
35
|
return "";
|
|
34
36
|
}
|
|
35
37
|
}
|
package/peer/BalancePull.sol
CHANGED
|
@@ -28,16 +28,18 @@ abstract contract PeerBalancePull is PeerBase, BalancePullHook {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/// @notice Execute the balance-pull peer call.
|
|
31
|
+
/// @param request BALANCE block stream requested by the trusted peer.
|
|
32
|
+
/// @return Empty response bytes.
|
|
31
33
|
function peerBalancePull(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
32
|
-
(Cur memory input, ) =
|
|
34
|
+
(Cur memory input, , ) = Cursors.init(request, 0, 1);
|
|
33
35
|
uint peer = caller();
|
|
34
36
|
|
|
35
|
-
while (input.i < input.
|
|
37
|
+
while (input.i < input.len) {
|
|
36
38
|
(bytes32 asset, bytes32 meta, uint amount) = input.unpackBalance();
|
|
37
39
|
balancePull(peer, asset, meta, amount);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
input.
|
|
42
|
+
input.complete();
|
|
41
43
|
return "";
|
|
42
44
|
}
|
|
43
45
|
}
|
package/peer/DenyAssets.sol
CHANGED
|
@@ -19,15 +19,17 @@ abstract contract PeerDenyAssets is PeerBase, DenyAssetsHook {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/// @notice Execute the deny-assets peer call.
|
|
22
|
+
/// @param request ASSET block stream supplied by the trusted peer.
|
|
23
|
+
/// @return Empty response bytes.
|
|
22
24
|
function peerDenyAssets(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
23
|
-
(Cur memory assets, ) =
|
|
25
|
+
(Cur memory assets, , ) = Cursors.init(request, 0, 1);
|
|
24
26
|
|
|
25
|
-
while (assets.i < assets.
|
|
27
|
+
while (assets.i < assets.len) {
|
|
26
28
|
(bytes32 asset, bytes32 meta) = assets.unpackAsset();
|
|
27
29
|
denyAsset(asset, meta);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
assets.
|
|
32
|
+
assets.complete();
|
|
31
33
|
return "";
|
|
32
34
|
}
|
|
33
35
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import { PeerBase } 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 PeerDispatchPayableHook {
|
|
12
|
+
/// @notice Override to dispatch an already encoded payload to `chain`.
|
|
13
|
+
/// @param chain Destination chain node ID.
|
|
14
|
+
/// @param endowment Native value requested for the destination dispatch. The
|
|
15
|
+
/// hook decides how much source-chain budget must be spent to fund this
|
|
16
|
+
/// value on the destination chain.
|
|
17
|
+
/// @param payload Encoded payload ready for the transport layer.
|
|
18
|
+
/// @param budget Source-chain native-value budget available for transport
|
|
19
|
+
/// fees and destination endowment funding.
|
|
20
|
+
function dispatch(uint chain, uint endowment, bytes calldata payload, Budget memory budget) internal virtual;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// @title PeerDispatchPayable
|
|
24
|
+
/// @notice Peer endpoint that forwards DISPATCH blocks to a host-defined dispatch hook.
|
|
25
|
+
abstract contract PeerDispatchPayable is PeerBase, Payable, PeerDispatchPayableHook {
|
|
26
|
+
string private constant NAME = "peerDispatchPayable";
|
|
27
|
+
uint internal immutable peerDispatchPayableId = peerId(NAME);
|
|
28
|
+
|
|
29
|
+
constructor() {
|
|
30
|
+
emit Peer(host, peerDispatchPayableId, NAME, "1:0", Schemas.Dispatch, "", true);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// @notice Forward peer-supplied dispatches to the host-defined dispatch hook.
|
|
34
|
+
/// @dev Dispatch hooks receive the shared top-level source-chain value
|
|
35
|
+
/// budget. Any `msg.value` not spent by the hook remains on this host.
|
|
36
|
+
/// @param request DISPATCH block stream supplied by the trusted peer.
|
|
37
|
+
/// @return output Empty response bytes.
|
|
38
|
+
function peerDispatchPayable(bytes calldata request) external payable onlyPeer returns (bytes memory output) {
|
|
39
|
+
(Cur memory input, , ) = Cursors.init(request, 0, 1);
|
|
40
|
+
Budget memory budget = valueBudget();
|
|
41
|
+
|
|
42
|
+
while (input.i < input.len) {
|
|
43
|
+
(uint chain, uint endowment, bytes calldata payload) = input.unpackDispatch();
|
|
44
|
+
dispatch(chain, endowment, payload, budget);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
input.complete();
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
}
|
package/peer/Pipe.sol
CHANGED
|
@@ -9,9 +9,9 @@ import {Budget} from "../utils/Value.sol";
|
|
|
9
9
|
using Cursors for Cur;
|
|
10
10
|
|
|
11
11
|
/// @title PeerPipePayable
|
|
12
|
-
/// @notice Peer that consumes PIPE blocks and executes each context
|
|
12
|
+
/// @notice Peer that consumes PIPE blocks and executes each context step stream.
|
|
13
13
|
/// Each PIPE block carries a value budget plus a CONTEXT block; the nested
|
|
14
|
-
/// context
|
|
14
|
+
/// context steps are passed to the shared pipeline as the step stream.
|
|
15
15
|
abstract contract PeerPipePayable is PeerBase, Pipeline {
|
|
16
16
|
string private constant NAME = "peerPipePayable";
|
|
17
17
|
uint internal immutable peerPipePayableId = peerId(NAME);
|
|
@@ -23,16 +23,18 @@ abstract contract PeerPipePayable is PeerBase, Pipeline {
|
|
|
23
23
|
/// @notice Execute peer-supplied pipes through the shared payable pipe.
|
|
24
24
|
/// @dev Each pipe receives its own explicit value sub-budget. Any top-level
|
|
25
25
|
/// `msg.value` not assigned to a pipe remains on this host.
|
|
26
|
+
/// @param request PIPE block stream supplied by the trusted peer.
|
|
27
|
+
/// @return Empty response bytes.
|
|
26
28
|
function peerPipePayable(bytes calldata request) external payable onlyPeer returns (bytes memory) {
|
|
27
|
-
(Cur memory input, ) =
|
|
29
|
+
(Cur memory input, , ) = Cursors.init(request, 0, 1);
|
|
28
30
|
Budget memory budget = valueBudget();
|
|
29
31
|
|
|
30
|
-
while (input.i < input.
|
|
32
|
+
while (input.i < input.len) {
|
|
31
33
|
(uint value, bytes32 account, bytes calldata state, bytes calldata steps) = input.unpackPipe();
|
|
32
34
|
pipe(account, state, steps, allocateValue(budget, value));
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
input.
|
|
37
|
+
input.complete();
|
|
36
38
|
return "";
|
|
37
39
|
}
|
|
38
40
|
}
|