@rootzero/contracts 0.9.9 → 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/Endpoints.sol +2 -0
- package/Events.sol +1 -0
- package/README.md +19 -18
- package/blocks/Cursors.sol +54 -26
- package/blocks/Keys.sol +6 -0
- package/blocks/Schema.sol +4 -2
- package/blocks/Writers.sol +4 -4
- package/commands/Burn.sol +4 -1
- package/commands/Credit.sol +4 -1
- package/commands/Debit.sol +4 -1
- package/commands/Deposit.sol +8 -2
- package/commands/Payout.sol +7 -3
- package/commands/Provision.sol +8 -2
- package/commands/Relay.sol +58 -0
- package/commands/Withdraw.sol +4 -1
- package/commands/admin/AllowAssets.sol +6 -1
- package/commands/admin/Allowance.sol +4 -1
- package/commands/admin/Appoint.sol +4 -1
- package/commands/admin/Authorize.sol +4 -1
- package/commands/admin/DenyAssets.sol +6 -1
- package/commands/admin/Destroy.sol +4 -2
- package/commands/admin/Dismiss.sol +4 -1
- package/commands/admin/Execute.sol +5 -2
- package/commands/admin/Init.sol +4 -2
- package/commands/admin/Unauthorize.sol +4 -1
- package/core/Host.sol +10 -1
- package/core/Pipeline.sol +2 -1
- package/core/Runtime.sol +3 -3
- package/events/Admin.sol +5 -5
- package/events/Chain.sol +20 -0
- package/events/Command.sol +5 -5
- package/guards/Revoke.sol +1 -1
- package/package.json +1 -1
- package/peer/AllowAssets.sol +3 -1
- package/peer/Allowance.sol +3 -1
- package/peer/BalancePull.sol +3 -1
- package/peer/DenyAssets.sol +3 -1
- package/peer/Dispatch.sol +51 -0
- package/peer/Pipe.sol +5 -3
- package/peer/Settle.sol +3 -1
- package/queries/Assets.sol +1 -1
- package/queries/Balances.sol +1 -1
- package/queries/Positions.sol +1 -1
- package/utils/Accounts.sol +1 -34
- package/utils/Assets.sol +21 -21
- package/utils/Ids.sol +12 -2
- package/utils/Layout.sol +21 -17
- package/utils/Utils.sol +2 -2
|
@@ -14,6 +14,7 @@ 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
|
|
|
@@ -23,8 +24,11 @@ abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
|
|
|
23
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, ) = Cursors.
|
|
31
|
+
(Cur memory request, , ) = Cursors.init(c.request, 0, 1);
|
|
28
32
|
Budget memory budget = valueBudget();
|
|
29
33
|
|
|
30
34
|
while (request.i < request.len) {
|
|
@@ -34,7 +38,6 @@ abstract contract ExecutePayable is CommandBase, Payable, AdminEvent {
|
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
request.complete();
|
|
37
|
-
settleValue(c.account, budget);
|
|
38
41
|
return "";
|
|
39
42
|
}
|
|
40
43
|
}
|
package/commands/admin/Init.sol
CHANGED
|
@@ -25,11 +25,13 @@ abstract contract Init is CommandBase, AdminEvent, InitHook {
|
|
|
25
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
|
}
|
|
@@ -19,10 +19,13 @@ abstract contract Unauthorize is CommandBase, AdminEvent {
|
|
|
19
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, ) = Cursors.
|
|
28
|
+
(Cur memory request, , ) = Cursors.init(c.request, 0, 1);
|
|
26
29
|
|
|
27
30
|
while (request.i < request.len) {
|
|
28
31
|
uint node = request.unpackNode();
|
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,7 +42,7 @@ abstract contract Pipeline is Payable {
|
|
|
41
42
|
bytes calldata steps,
|
|
42
43
|
Budget memory budget
|
|
43
44
|
) internal {
|
|
44
|
-
(Cur memory input, ) = Cursors.
|
|
45
|
+
(Cur memory input, , ) = Cursors.init(steps, 0, 1);
|
|
45
46
|
|
|
46
47
|
while (input.i < input.len) {
|
|
47
48
|
(uint target, uint value, bytes calldata request) = input.unpackStep();
|
package/core/Runtime.sol
CHANGED
|
@@ -5,10 +5,10 @@ import {Assets} from "../utils/Assets.sol";
|
|
|
5
5
|
import {Ids} from "../utils/Ids.sol";
|
|
6
6
|
|
|
7
7
|
/// @title Runtime
|
|
8
|
-
/// @notice Shared runtime for host identity and native
|
|
8
|
+
/// @notice Shared runtime for host identity and native asset identity.
|
|
9
9
|
abstract contract Runtime {
|
|
10
10
|
/// @dev This contract's host node ID, set to `Ids.toHost(address(this))` at construction.
|
|
11
11
|
uint public immutable host = Ids.toHost(address(this));
|
|
12
|
-
/// @dev Asset ID for the native chain
|
|
13
|
-
bytes32 internal immutable
|
|
12
|
+
/// @dev Asset ID for the native chain coin/token, bound to the current chain at deployment.
|
|
13
|
+
bytes32 internal immutable nativeAsset = Assets.toNative();
|
|
14
14
|
}
|
package/events/Admin.sol
CHANGED
|
@@ -6,19 +6,19 @@ 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
14
|
/// @param shape Per-operation block counts encoded as `request:state:output`.
|
|
15
|
-
/// The request count covers only the input request run. If `
|
|
15
|
+
/// The request count covers only the input request run. If `postcheck` is true,
|
|
16
16
|
/// a constraint run follows the input run, or starts the request when `request`
|
|
17
17
|
/// is empty. State globals may follow the state run and are excluded.
|
|
18
18
|
/// @param request Schema DSL string describing the input request run, or empty if none.
|
|
19
|
-
/// @param state Block key expected for input state, or `Keys.
|
|
19
|
+
/// @param state Block key expected for input state, `Keys.Empty`, or `Keys.Any`.
|
|
20
20
|
/// @param output Block key produced for output state, or `Keys.Empty`.
|
|
21
|
-
/// @param
|
|
21
|
+
/// @param postcheck Whether command output is validated after execution.
|
|
22
22
|
/// @param funded Whether the command entrypoint accepts nonzero `msg.value`.
|
|
23
23
|
event Admin(
|
|
24
24
|
uint indexed host,
|
|
@@ -28,7 +28,7 @@ abstract contract AdminEvent is EventEmitter {
|
|
|
28
28
|
string request,
|
|
29
29
|
bytes4 state,
|
|
30
30
|
bytes4 output,
|
|
31
|
-
bool
|
|
31
|
+
bool postcheck,
|
|
32
32
|
bool funded
|
|
33
33
|
);
|
|
34
34
|
|
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,19 +6,19 @@ 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
14
|
/// @param shape Per-operation block counts encoded as `request:state:output`.
|
|
15
|
-
/// The request count covers only the input request run. If `
|
|
15
|
+
/// The request count covers only the input request run. If `postcheck` is true,
|
|
16
16
|
/// a constraint run follows the input run, or starts the request when `request`
|
|
17
17
|
/// is empty. State globals may follow the state run and are excluded.
|
|
18
18
|
/// @param request Schema string describing the input request run, or empty if none.
|
|
19
|
-
/// @param state Block key expected for input state, or `Keys.
|
|
19
|
+
/// @param state Block key expected for input state, `Keys.Empty`, or `Keys.Any`.
|
|
20
20
|
/// @param output Block key produced for output state, or `Keys.Empty`.
|
|
21
|
-
/// @param
|
|
21
|
+
/// @param postcheck Whether command output is validated after execution.
|
|
22
22
|
/// @param funded Whether the command entrypoint accepts nonzero `msg.value`.
|
|
23
23
|
event Command(
|
|
24
24
|
uint indexed host,
|
|
@@ -28,7 +28,7 @@ abstract contract CommandEvent is EventEmitter {
|
|
|
28
28
|
string request,
|
|
29
29
|
bytes4 state,
|
|
30
30
|
bytes4 output,
|
|
31
|
-
bool
|
|
31
|
+
bool postcheck,
|
|
32
32
|
bool funded
|
|
33
33
|
);
|
|
34
34
|
|
package/guards/Revoke.sol
CHANGED
|
@@ -19,7 +19,7 @@ abstract contract Revoke is GuardBase {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function revoke(bytes calldata request) external onlyGuardian {
|
|
22
|
-
(Cur memory input, ) = Cursors.
|
|
22
|
+
(Cur memory input, , ) = Cursors.init(request, 0, 1);
|
|
23
23
|
|
|
24
24
|
while (input.i < input.len) {
|
|
25
25
|
uint node = input.unpackNode();
|
package/package.json
CHANGED
package/peer/AllowAssets.sol
CHANGED
|
@@ -19,8 +19,10 @@ 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, ) = Cursors.
|
|
25
|
+
(Cur memory assets, , ) = Cursors.init(request, 0, 1);
|
|
24
26
|
|
|
25
27
|
while (assets.i < assets.len) {
|
|
26
28
|
(bytes32 asset, bytes32 meta) = assets.unpackAsset();
|
package/peer/Allowance.sol
CHANGED
|
@@ -20,8 +20,10 @@ 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, ) = Cursors.
|
|
26
|
+
(Cur memory amounts, , ) = Cursors.init(request, 0, 1);
|
|
25
27
|
uint peer = caller();
|
|
26
28
|
|
|
27
29
|
while (amounts.i < amounts.len) {
|
package/peer/BalancePull.sol
CHANGED
|
@@ -28,8 +28,10 @@ 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, ) = Cursors.
|
|
34
|
+
(Cur memory input, , ) = Cursors.init(request, 0, 1);
|
|
33
35
|
uint peer = caller();
|
|
34
36
|
|
|
35
37
|
while (input.i < input.len) {
|
package/peer/DenyAssets.sol
CHANGED
|
@@ -19,8 +19,10 @@ 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, ) = Cursors.
|
|
25
|
+
(Cur memory assets, , ) = Cursors.init(request, 0, 1);
|
|
24
26
|
|
|
25
27
|
while (assets.i < assets.len) {
|
|
26
28
|
(bytes32 asset, bytes32 meta) = assets.unpackAsset();
|
|
@@ -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,8 +23,10 @@ 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, ) = Cursors.
|
|
29
|
+
(Cur memory input, , ) = Cursors.init(request, 0, 1);
|
|
28
30
|
Budget memory budget = valueBudget();
|
|
29
31
|
|
|
30
32
|
while (input.i < input.len) {
|
package/peer/Settle.sol
CHANGED
|
@@ -20,8 +20,10 @@ abstract contract PeerSettle is PeerBase, DebitAccountHook, CreditAccountHook {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/// @notice Execute the peer-settle call.
|
|
23
|
+
/// @param request TRANSACTION block stream supplied by the trusted peer.
|
|
24
|
+
/// @return Empty response bytes.
|
|
23
25
|
function peerSettle(bytes calldata request) external onlyPeer returns (bytes memory) {
|
|
24
|
-
(Cur memory state, ) = Cursors.
|
|
26
|
+
(Cur memory state, , ) = Cursors.init(request, 0, 1);
|
|
25
27
|
|
|
26
28
|
while (state.i < state.len) {
|
|
27
29
|
(bytes32 from, bytes32 to, bytes32 asset, bytes32 meta, uint amount) = state.unpackTransaction();
|
package/queries/Assets.sol
CHANGED
|
@@ -33,7 +33,7 @@ abstract contract AssetStatus is QueryBase, AssetStatusHook {
|
|
|
33
33
|
/// @param request Block-stream request consisting of `#asset { bytes32 asset, bytes32 meta }` blocks.
|
|
34
34
|
/// @return Block-stream response containing one `#status { uint code }` per asset block.
|
|
35
35
|
function assetStatus(bytes calldata request) external view returns (bytes memory) {
|
|
36
|
-
(Cur memory query, uint groups) = Cursors.
|
|
36
|
+
(Cur memory query, uint groups, ) = Cursors.init(request, 0, 1);
|
|
37
37
|
Writer memory response = Writers.allocStatuses(groups);
|
|
38
38
|
|
|
39
39
|
while (query.i < query.len) {
|
package/queries/Balances.sol
CHANGED
|
@@ -33,7 +33,7 @@ abstract contract GetBalances is QueryBase, GetBalancesHook {
|
|
|
33
33
|
/// @param request Block-stream request consisting of `accountAsset(account, asset, meta)*`.
|
|
34
34
|
/// @return Block-stream response containing one `accountAmount(account, asset, meta, amount)` block per request block.
|
|
35
35
|
function getBalances(bytes calldata request) external view returns (bytes memory) {
|
|
36
|
-
(Cur memory query, uint groups) = Cursors.
|
|
36
|
+
(Cur memory query, uint groups, ) = Cursors.init(request, 0, 1);
|
|
37
37
|
Writer memory response = Writers.allocAccountAmounts(groups);
|
|
38
38
|
|
|
39
39
|
while (query.i < query.len) {
|
package/queries/Positions.sol
CHANGED
|
@@ -42,7 +42,7 @@ abstract contract GetPosition is QueryBase, GetPositionHook {
|
|
|
42
42
|
/// @param request Block-stream request consisting of `accountAsset(account, asset, meta)*`.
|
|
43
43
|
/// @return Block-stream response containing one output-schema block per position block.
|
|
44
44
|
function getPosition(bytes calldata request) external view returns (bytes memory) {
|
|
45
|
-
(Cur memory query, uint groups) = Cursors.
|
|
45
|
+
(Cur memory query, uint groups, ) = Cursors.init(request, 0, 1);
|
|
46
46
|
Writer memory response = Writers.allocAny(groups);
|
|
47
47
|
|
|
48
48
|
while (query.i < query.len) {
|
package/utils/Accounts.sol
CHANGED
|
@@ -23,8 +23,6 @@ library Accounts {
|
|
|
23
23
|
uint32 constant Guardian = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Account) << 8) | uint32(Layout.Guardian);
|
|
24
24
|
/// @dev Full 4-byte type prefix for user accounts (chain-agnostic EVM address).
|
|
25
25
|
uint32 constant User = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Account) << 8) | uint32(Layout.User);
|
|
26
|
-
/// @dev Full 4-byte type prefix for keccak accounts (opaque 28-byte hash).
|
|
27
|
-
uint32 constant Keccak = (uint32(Layout.Opaque32) << 16) | (uint32(Layout.Account) << 8) | uint32(Layout.Keccak);
|
|
28
26
|
|
|
29
27
|
/// @notice Extract the 4-byte type prefix from an account ID.
|
|
30
28
|
/// @param account Account identifier.
|
|
@@ -53,14 +51,10 @@ library Accounts {
|
|
|
53
51
|
return prefix(account) == User;
|
|
54
52
|
}
|
|
55
53
|
|
|
56
|
-
function isKeccak(bytes32 account) internal pure returns (bool) {
|
|
57
|
-
return prefix(account) == Keccak;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
54
|
/// @notice Assert that `input` is an account and return it unchanged.
|
|
61
55
|
/// @param input Account identifier to validate.
|
|
62
56
|
/// @return account The same `input` if it is an account.
|
|
63
|
-
function
|
|
57
|
+
function ensure(bytes32 input) internal pure returns (bytes32 account) {
|
|
64
58
|
if (!isAccount(input)) revert InvalidAccount();
|
|
65
59
|
return input;
|
|
66
60
|
}
|
|
@@ -89,14 +83,6 @@ library Accounts {
|
|
|
89
83
|
return input;
|
|
90
84
|
}
|
|
91
85
|
|
|
92
|
-
/// @notice Assert that `input` is a keccak account and return it unchanged.
|
|
93
|
-
/// @param input Account identifier to validate.
|
|
94
|
-
/// @return account The same `input` if it is a keccak account.
|
|
95
|
-
function keccak(bytes32 input) internal pure returns (bytes32 account) {
|
|
96
|
-
if (!isKeccak(input)) revert InvalidAccount();
|
|
97
|
-
return input;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
86
|
/// @notice Encode an EVM address as a chain-local admin account ID.
|
|
101
87
|
/// @param addr EVM address to embed.
|
|
102
88
|
/// @return Admin account ID bound to the current chain.
|
|
@@ -118,25 +104,6 @@ library Accounts {
|
|
|
118
104
|
return bytes32(toUnspecifiedBase(User) | (uint(uint160(addr)) << 32));
|
|
119
105
|
}
|
|
120
106
|
|
|
121
|
-
function toKeccak(bytes32 head, bytes32 meta) internal pure returns (bytes32) {
|
|
122
|
-
return bytes32(toUnspecifiedBase(Keccak) | uint224(uint256(keccak256(bytes.concat(head, meta)))));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function matchesKeccak(bytes32 account, bytes32 head, bytes32 meta) internal pure returns (bool) {
|
|
126
|
-
return account == toKeccak(head, meta);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/// @notice Assert that `account` uses the Account layout tag and return it unchanged.
|
|
130
|
-
/// Ignores width, chain binding, and subtype details.
|
|
131
|
-
/// @param account Account ID to validate.
|
|
132
|
-
/// @return The same `account` value if valid.
|
|
133
|
-
function ensure(bytes32 account) internal pure returns (bytes32) {
|
|
134
|
-
if (uint8(uint(account) >> 232) != Layout.Account) {
|
|
135
|
-
revert InvalidAccount();
|
|
136
|
-
}
|
|
137
|
-
return account;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
107
|
/// @notice Assert that `account` belongs to the EVM account family and return it unchanged.
|
|
141
108
|
/// @param account Account ID to validate.
|
|
142
109
|
/// @return The same `account` value if valid.
|
package/utils/Assets.sol
CHANGED
|
@@ -8,10 +8,10 @@ import {matchesBase, toLocalBase} from "./Utils.sol";
|
|
|
8
8
|
/// @notice Encoding and decoding helpers for 256-bit asset identifiers.
|
|
9
9
|
///
|
|
10
10
|
/// Asset IDs embed a 4-byte type tag in bits [255:224]:
|
|
11
|
-
/// - `
|
|
12
|
-
/// - `Erc20`
|
|
13
|
-
/// - `Erc721`
|
|
14
|
-
/// - `Erc1155`
|
|
11
|
+
/// - `Native` - native chain coin/token; no address payload
|
|
12
|
+
/// - `Erc20` - ERC-20 token; contract address in bits [191:32]
|
|
13
|
+
/// - `Erc721` - ERC-721 collection; collection address in bits [191:32]
|
|
14
|
+
/// - `Erc1155` - ERC-1155 collection; collection address in bits [191:32]
|
|
15
15
|
///
|
|
16
16
|
/// All asset IDs are chain-local (include `block.chainid` in bits [223:192]).
|
|
17
17
|
library Assets {
|
|
@@ -20,8 +20,8 @@ library Assets {
|
|
|
20
20
|
/// @dev Thrown when an asset is not authorized for the requested operation.
|
|
21
21
|
error UnauthorizedAsset();
|
|
22
22
|
|
|
23
|
-
/// @dev Full 4-byte type prefix for the native
|
|
24
|
-
uint32 constant
|
|
23
|
+
/// @dev Full 4-byte type prefix for the native chain coin/token asset.
|
|
24
|
+
uint32 constant Native = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Asset) << 8) | uint32(Layout.Native);
|
|
25
25
|
/// @dev Full 4-byte type prefix for ERC-20 assets.
|
|
26
26
|
uint32 constant Erc20 = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Asset) << 8) | uint32(Layout.Erc20);
|
|
27
27
|
/// @dev Full 4-byte type prefix for ERC-721 assets.
|
|
@@ -34,19 +34,19 @@ library Assets {
|
|
|
34
34
|
return uint8(uint(asset) >> 232) == Layout.Asset;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/// @notice Return true if `asset` uses
|
|
37
|
+
/// @notice Return true if `asset` uses a 32-byte asset layout with no metadata identity.
|
|
38
38
|
function is32(bytes32 asset) internal pure returns (bool) {
|
|
39
|
-
return isAsset(asset) &&
|
|
39
|
+
return isAsset(asset) && uint8(uint(asset) >> 240) == Layout.Width32;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
/// @notice Return true if `asset` uses
|
|
42
|
+
/// @notice Return true if `asset` uses a 64-byte asset layout with metadata-backed identity.
|
|
43
43
|
function is64(bytes32 asset) internal pure returns (bool) {
|
|
44
|
-
return isAsset(asset) &&
|
|
44
|
+
return isAsset(asset) && uint8(uint(asset) >> 240) == Layout.Width64;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
/// @notice Return true if `asset` is the local native
|
|
48
|
-
function
|
|
49
|
-
return asset ==
|
|
47
|
+
/// @notice Return true if `asset` is the local native chain coin/token asset.
|
|
48
|
+
function isNative(bytes32 asset) internal view returns (bool) {
|
|
49
|
+
return asset == toNative();
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/// @notice Return true if `asset` is a local ERC-20 asset.
|
|
@@ -64,11 +64,11 @@ library Assets {
|
|
|
64
64
|
return matchesBase(asset, toLocalBase(Erc1155));
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
/// @notice Assert that `input` is the local native
|
|
67
|
+
/// @notice Assert that `input` is the local native chain coin/token asset and return it unchanged.
|
|
68
68
|
/// @param input Asset identifier to validate.
|
|
69
|
-
/// @return asset The same `input` if it is the local native
|
|
70
|
-
function
|
|
71
|
-
if (!
|
|
69
|
+
/// @return asset The same `input` if it is the local native asset.
|
|
70
|
+
function native(bytes32 input) internal view returns (bytes32 asset) {
|
|
71
|
+
if (!isNative(input)) revert InvalidAsset();
|
|
72
72
|
return input;
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -96,10 +96,10 @@ library Assets {
|
|
|
96
96
|
return input;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
/// @notice Create a chain-local native
|
|
99
|
+
/// @notice Create a chain-local native coin/token asset ID.
|
|
100
100
|
/// @return Asset ID for the native token on the current chain.
|
|
101
|
-
function
|
|
102
|
-
return bytes32(toLocalBase(
|
|
101
|
+
function toNative() internal view returns (bytes32) {
|
|
102
|
+
return bytes32(toLocalBase(Native));
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
/// @notice Create a chain-local ERC-20 asset ID for `addr`.
|
|
@@ -178,7 +178,7 @@ library Assets {
|
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
/// @notice Derive a storage slot for an (asset, meta) pair.
|
|
181
|
-
/// For 32-byte
|
|
181
|
+
/// For 32-byte assets (no meta), the slot is the asset ID itself.
|
|
182
182
|
/// For assets with metadata (e.g. ERC-721 or ERC-1155 token IDs), the slot is
|
|
183
183
|
/// `keccak256(asset ++ meta)`.
|
|
184
184
|
/// Reverts only if `asset` is zero.
|
package/utils/Ids.sol
CHANGED
|
@@ -18,6 +18,8 @@ library Ids {
|
|
|
18
18
|
|
|
19
19
|
/// @dev 24-bit family tag shared by all node types (Evm32 + Node category).
|
|
20
20
|
uint24 constant Node = (uint24(Layout.Evm32) << 8) | uint24(Layout.Node);
|
|
21
|
+
/// @dev Full 4-byte type prefix for chain/domain nodes.
|
|
22
|
+
uint32 constant Chain = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Chain);
|
|
21
23
|
/// @dev Full 4-byte type prefix for host nodes.
|
|
22
24
|
uint32 constant Host = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Host);
|
|
23
25
|
/// @dev Full 4-byte type prefix for command nodes.
|
|
@@ -56,7 +58,7 @@ library Ids {
|
|
|
56
58
|
|
|
57
59
|
/// @notice Return true if `id` is a local node ID for this contract.
|
|
58
60
|
function isLocalNode(uint id) internal view returns (bool) {
|
|
59
|
-
return isLocalFamily(id, Node) && address(uint160(id)) == address(this);
|
|
61
|
+
return uint32(id >> 224) != Chain && isLocalFamily(id, Node) && address(uint160(id)) == address(this);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
/// @notice Assert that `id` is a command ID and return it unchanged.
|
|
@@ -128,6 +130,14 @@ library Ids {
|
|
|
128
130
|
return id;
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
/// @notice Build the chain node ID for the current chain.
|
|
134
|
+
/// @return Chain node ID with the Chain prefix and `block.chainid` payload.
|
|
135
|
+
function localChain() internal view returns (uint) {
|
|
136
|
+
uint id = block.chainid;
|
|
137
|
+
if (id >> 224 != 0) revert InvalidId();
|
|
138
|
+
return (uint(Chain) << 224) | id;
|
|
139
|
+
}
|
|
140
|
+
|
|
131
141
|
/// @notice Build a chain-local host ID for `target`.
|
|
132
142
|
/// @param target Host contract address.
|
|
133
143
|
/// @return Host node ID on the current chain.
|
|
@@ -180,7 +190,7 @@ library Ids {
|
|
|
180
190
|
/// @param id Node ID (host, command, or peer).
|
|
181
191
|
/// @return Contract address in the lower 160 bits of `id`.
|
|
182
192
|
function nodeAddr(uint id) internal view returns (address) {
|
|
183
|
-
if (!isLocalFamily(id, Node)) revert InvalidId();
|
|
193
|
+
if (uint32(id >> 224) == Chain || !isLocalFamily(id, Node)) revert InvalidId();
|
|
184
194
|
return address(uint160(id));
|
|
185
195
|
}
|
|
186
196
|
|