@rootzero/contracts 1.15.0 → 1.17.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 +90 -0
- package/Codec.sol +1 -1
- package/Commands.sol +1 -1
- package/Core.sol +4 -4
- package/Endpoints.sol +9 -7
- package/Events.sol +0 -1
- package/README.md +88 -30
- package/Utils.sol +1 -1
- package/codec/Blocks.sol +111 -21
- package/codec/Buffers.sol +3 -3
- package/codec/Decoders.sol +48 -10
- package/codec/Descriptors.sol +0 -1
- package/codec/Keys.sol +4 -2
- package/codec/Readers.sol +25 -0
- package/codec/Schema.sol +6 -1
- package/codec/Specs.sol +7 -2
- package/codec/Writers.sol +28 -2
- package/commands/Base.sol +8 -15
- package/commands/Burn.sol +2 -2
- package/commands/Credit.sol +38 -3
- package/commands/Debit.sol +50 -14
- package/commands/Deposit.sol +4 -4
- package/commands/Provision.sol +4 -4
- package/commands/Recover.sol +15 -8
- package/commands/Relay.sol +37 -12
- package/commands/Settle.sol +130 -0
- package/commands/Withdraw.sol +2 -2
- package/commands/admin/AllowAssets.sol +2 -2
- package/commands/admin/Allowance.sol +3 -3
- package/commands/admin/Annotate.sol +2 -2
- package/commands/admin/Appoint.sol +2 -2
- package/commands/admin/Authorize.sol +2 -2
- package/commands/admin/DenyAssets.sol +2 -2
- package/commands/admin/Dismiss.sol +2 -2
- package/commands/admin/Execute.sol +3 -3
- package/commands/admin/Unauthorize.sol +2 -2
- package/core/Endpoint.sol +15 -13
- package/core/Pipeline.sol +6 -6
- package/core/Settlement.sol +37 -8
- package/core/Types.sol +21 -1
- package/docs/Schema.md +52 -2
- package/execution/Budget.sol +12 -4
- package/execution/Execution.sol +119 -11
- package/guards/Base.sol +2 -2
- package/guards/Revoke.sol +21 -0
- package/package.json +1 -1
- package/ports/Base.sol +2 -2
- package/ports/Dispatch.sol +6 -6
- package/ports/{Settle.sol → Post.sol} +10 -10
- package/queries/Base.sol +2 -2
- package/utils/Actions.sol +1 -0
- package/utils/Cursors.sol +16 -30
- package/events/Position.sol +0 -22
package/commands/Relay.sol
CHANGED
|
@@ -5,28 +5,53 @@ import {Blocks, Execution, Executions, CommandBase, Lanes, Specs} from "./Base.s
|
|
|
5
5
|
|
|
6
6
|
using Executions for Execution;
|
|
7
7
|
|
|
8
|
-
/// @notice Hook implemented by hosts that
|
|
9
|
-
abstract contract
|
|
10
|
-
/// @notice Override to
|
|
8
|
+
/// @notice Hook implemented by hosts that forward funded relay payloads.
|
|
9
|
+
abstract contract RelayPayableHook {
|
|
10
|
+
/// @notice Override to relay an encoded payload to `portal`.
|
|
11
11
|
/// @param portal Destination portal identifier, often the destination host ID.
|
|
12
12
|
/// @param resources Chain-specific destination resources. EVM adapters
|
|
13
13
|
/// may interpret this as packed execution gas and destination value.
|
|
14
14
|
/// @param payload Encoded payload ready for the transport layer.
|
|
15
|
-
/// @param funds Execution used
|
|
16
|
-
///
|
|
17
|
-
function
|
|
15
|
+
/// @param funds Execution used for source value available for transport fees
|
|
16
|
+
/// and destination resource funding.
|
|
17
|
+
function relayTo(uint portal, uint resources, bytes memory payload, Execution memory funds) internal virtual;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/// @title RelayPayable
|
|
21
|
-
/// @notice Command that forwards one RELAY block
|
|
21
|
+
/// @notice Command that forwards one RELAY block without pipeline state.
|
|
22
|
+
abstract contract RelayPayable is CommandBase, RelayPayableHook {
|
|
23
|
+
uint private immutable descriptor;
|
|
24
|
+
|
|
25
|
+
constructor() {
|
|
26
|
+
(, descriptor) = command("relayPayable", Specs.Empty, Specs.Relay, Specs.Empty, 0, true, false);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// @notice Relay one RELAY input block with the command account and empty state.
|
|
30
|
+
function relayPayable(
|
|
31
|
+
bytes32 account,
|
|
32
|
+
bytes calldata state,
|
|
33
|
+
bytes calldata input
|
|
34
|
+
) external payable onlyCommand returns (bytes memory, bytes memory) {
|
|
35
|
+
Execution memory exec = openCommand(state, input, descriptor, 1);
|
|
36
|
+
(uint portal, uint resources, bytes calldata payload) = exec.unpackRelay(Lanes.Input);
|
|
37
|
+
bytes memory context = Blocks.context(account, bytes(state), bytes(payload));
|
|
38
|
+
|
|
39
|
+
relayTo(portal, resources, context, exec);
|
|
40
|
+
|
|
41
|
+
return close(exec, account);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// @title RelayBalancePayable
|
|
46
|
+
/// @notice Command that forwards required BALANCE state with one RELAY block.
|
|
22
47
|
/// Reverts unless the input contains exactly one RELAY block, preventing
|
|
23
48
|
/// the same state from being duplicated across multiple relays.
|
|
24
49
|
/// Produces no output state.
|
|
25
|
-
abstract contract
|
|
50
|
+
abstract contract RelayBalancePayable is CommandBase, RelayPayableHook {
|
|
26
51
|
uint private immutable descriptor;
|
|
27
52
|
|
|
28
53
|
constructor() {
|
|
29
|
-
(, descriptor) = command("
|
|
54
|
+
(, descriptor) = command("relayBalancePayable", Specs.Balance, Specs.Relay, Specs.Empty, 0, true, false);
|
|
30
55
|
}
|
|
31
56
|
|
|
32
57
|
/// @notice Relay one RELAY input block with the command account and current state.
|
|
@@ -34,16 +59,16 @@ abstract contract RelayPayable is CommandBase, RoutePayableHook {
|
|
|
34
59
|
/// @param input Exactly one RELAY block.
|
|
35
60
|
/// @return Empty output state.
|
|
36
61
|
/// @return Remaining native value as a refund transaction stream.
|
|
37
|
-
function
|
|
62
|
+
function relayBalancePayable(
|
|
38
63
|
bytes32 account,
|
|
39
64
|
bytes calldata state,
|
|
40
65
|
bytes calldata input
|
|
41
66
|
) external payable onlyCommand returns (bytes memory, bytes memory) {
|
|
42
|
-
Execution memory exec =
|
|
67
|
+
Execution memory exec = openCommand(state, input, descriptor, 1);
|
|
43
68
|
(uint portal, uint resources, bytes calldata payload) = exec.unpackRelay(Lanes.Input);
|
|
44
69
|
bytes memory context = Blocks.context(account, bytes(state), bytes(payload));
|
|
45
70
|
|
|
46
|
-
|
|
71
|
+
relayTo(portal, resources, context, exec);
|
|
47
72
|
|
|
48
73
|
return close(exec, account);
|
|
49
74
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {Execution, Executions, CommandBase, Lanes, Specs} from "./Base.sol";
|
|
5
|
+
import {SettleHook} from "../core/Settlement.sol";
|
|
6
|
+
import {Action} from "../annotations/Action.sol";
|
|
7
|
+
import {Actions} from "../utils/Actions.sol";
|
|
8
|
+
import {Blocks} from "../codec/Blocks.sol";
|
|
9
|
+
import {Reader, Readers} from "../codec/Readers.sol";
|
|
10
|
+
|
|
11
|
+
using Executions for Execution;
|
|
12
|
+
using Readers for Reader;
|
|
13
|
+
|
|
14
|
+
/// @notice Hook implemented by hosts that settle positions using native value.
|
|
15
|
+
abstract contract SettlePayableHook {
|
|
16
|
+
/// @notice Override to settle one position for `account` with a shared value budget.
|
|
17
|
+
/// @param account Account whose position is being settled.
|
|
18
|
+
/// @param asset Identifier for the asset side.
|
|
19
|
+
/// @param amount Quantity on the asset side.
|
|
20
|
+
/// @param liability Identifier for the liability side.
|
|
21
|
+
/// @param debt Quantity on the liability side.
|
|
22
|
+
/// @param funds Mutable execution used only for its remaining native-value budget.
|
|
23
|
+
function settle(
|
|
24
|
+
bytes32 account,
|
|
25
|
+
bytes32 asset,
|
|
26
|
+
uint amount,
|
|
27
|
+
bytes32 liability,
|
|
28
|
+
uint debt,
|
|
29
|
+
Execution memory funds
|
|
30
|
+
) internal virtual;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// @title Settle
|
|
34
|
+
/// @notice Command that consumes POSITION state blocks through a virtual hook.
|
|
35
|
+
abstract contract Settle is CommandBase, SettleHook, Action {
|
|
36
|
+
uint private immutable descriptor;
|
|
37
|
+
uint private immutable id;
|
|
38
|
+
|
|
39
|
+
constructor() {
|
|
40
|
+
(id, descriptor) = command("settle", Specs.Position, Specs.Empty, Specs.Empty, 0, false, false);
|
|
41
|
+
action(id, Actions.Settle);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// @notice Return the registered SETTLE command ID.
|
|
45
|
+
function settleId() internal view returns (uint) {
|
|
46
|
+
return id;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// @notice Settle each POSITION block from the command state.
|
|
50
|
+
/// @param state POSITION block stream.
|
|
51
|
+
/// @return Empty output state.
|
|
52
|
+
/// @return Empty transaction stream.
|
|
53
|
+
function settle(
|
|
54
|
+
bytes32 account,
|
|
55
|
+
bytes calldata state,
|
|
56
|
+
bytes calldata input
|
|
57
|
+
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
58
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
59
|
+
|
|
60
|
+
while (exec.more()) {
|
|
61
|
+
(bytes32 asset, uint amount, bytes32 liability, uint debt) = exec.unpackPosition(Lanes.State);
|
|
62
|
+
settle(account, asset, amount, liability, debt);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return close(exec, account);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// @title SettlePayable
|
|
70
|
+
/// @notice Funded command that consumes POSITION state blocks through a virtual hook.
|
|
71
|
+
abstract contract SettlePayable is CommandBase, SettlePayableHook, Action {
|
|
72
|
+
uint private immutable descriptor;
|
|
73
|
+
|
|
74
|
+
constructor() {
|
|
75
|
+
uint id;
|
|
76
|
+
(id, descriptor) = command("settlePayable", Specs.Position, Specs.Empty, Specs.Empty, 0, true, false);
|
|
77
|
+
action(id, Actions.Settle);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// @notice Settle each POSITION block with access to a shared native-value budget.
|
|
81
|
+
/// @param state POSITION block stream.
|
|
82
|
+
/// @return Empty output state.
|
|
83
|
+
/// @return Remaining native value as a refund transaction stream.
|
|
84
|
+
function settlePayable(
|
|
85
|
+
bytes32 account,
|
|
86
|
+
bytes calldata state,
|
|
87
|
+
bytes calldata input
|
|
88
|
+
) external payable onlyCommand returns (bytes memory, bytes memory) {
|
|
89
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
90
|
+
|
|
91
|
+
while (exec.more()) {
|
|
92
|
+
(bytes32 asset, uint amount, bytes32 liability, uint debt) = exec.unpackPosition(Lanes.State);
|
|
93
|
+
settle(account, asset, amount, liability, debt, exec);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return close(exec, account);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// @title InternalSettle
|
|
101
|
+
/// @notice Extends the advertised settle command with memory-state pipeline dispatch.
|
|
102
|
+
/// @dev This adapter is not a separate command. It uses the command ID and settlement hook
|
|
103
|
+
/// inherited from `Settle` while accepting the state location used by `Pipeline`.
|
|
104
|
+
abstract contract InternalSettle is Settle {
|
|
105
|
+
/// @notice Execute the inherited settle command from an internal pipeline.
|
|
106
|
+
/// @param account Account for which each position is settled.
|
|
107
|
+
/// @param state POSITION block stream held in pipeline memory.
|
|
108
|
+
/// @param input Empty input required by the command schema.
|
|
109
|
+
/// @param value Native value assigned to the command; must be zero.
|
|
110
|
+
/// @return output Empty output state.
|
|
111
|
+
/// @return transactions Empty transaction stream.
|
|
112
|
+
function executeSettle(
|
|
113
|
+
bytes32 account,
|
|
114
|
+
bytes memory state,
|
|
115
|
+
bytes calldata input,
|
|
116
|
+
uint128 value
|
|
117
|
+
) internal returns (bytes memory, bytes memory) {
|
|
118
|
+
if (value != 0) revert ValueNotAllowed();
|
|
119
|
+
if (input.length != 0) revert Executions.ZeroStride();
|
|
120
|
+
if (state.length == 0) revert Blocks.EmptyRun();
|
|
121
|
+
|
|
122
|
+
Reader memory reader = Readers.open(state);
|
|
123
|
+
while (reader.more()) {
|
|
124
|
+
(bytes32 asset, uint amount, bytes32 liability, uint debt) = reader.unpackPosition();
|
|
125
|
+
settle(account, asset, amount, liability, debt);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return ("", "");
|
|
129
|
+
}
|
|
130
|
+
}
|
package/commands/Withdraw.sol
CHANGED
|
@@ -36,9 +36,9 @@ abstract contract Withdraw is CommandBase, WithdrawHook, Action {
|
|
|
36
36
|
function withdraw(
|
|
37
37
|
bytes32 account,
|
|
38
38
|
bytes calldata state,
|
|
39
|
-
bytes calldata
|
|
39
|
+
bytes calldata input
|
|
40
40
|
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
41
|
-
Execution memory exec =
|
|
41
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
42
42
|
|
|
43
43
|
while (exec.more()) {
|
|
44
44
|
(bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
|
|
@@ -28,10 +28,10 @@ abstract contract AllowAssets is AdminBase, AllowAssetsHook {
|
|
|
28
28
|
/// @return Empty transaction stream.
|
|
29
29
|
function allowAssets(
|
|
30
30
|
bytes32 account,
|
|
31
|
-
bytes calldata,
|
|
31
|
+
bytes calldata state,
|
|
32
32
|
bytes calldata input
|
|
33
33
|
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
34
|
-
Execution memory exec =
|
|
34
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
35
35
|
|
|
36
36
|
while (exec.more()) {
|
|
37
37
|
bytes32 asset = exec.unpackAsset(Lanes.Input);
|
|
@@ -12,7 +12,7 @@ abstract contract AllowanceHook {
|
|
|
12
12
|
/// or another host-specific authorization record.
|
|
13
13
|
/// @param peer Host node receiving the allowed cap.
|
|
14
14
|
/// @param asset Asset identifier.
|
|
15
|
-
/// @param amount Allowed cap amount.
|
|
15
|
+
/// @param amount Allowed cap amount. A zero amount MUST revoke the allowance.
|
|
16
16
|
function allowance(uint peer, bytes32 asset, uint amount) internal virtual;
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -32,10 +32,10 @@ abstract contract Allowance is AdminBase, AllowanceHook {
|
|
|
32
32
|
/// @return Empty transaction stream.
|
|
33
33
|
function allowance(
|
|
34
34
|
bytes32 account,
|
|
35
|
-
bytes calldata,
|
|
35
|
+
bytes calldata state,
|
|
36
36
|
bytes calldata input
|
|
37
37
|
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
38
|
-
Execution memory exec =
|
|
38
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
39
39
|
|
|
40
40
|
while (exec.more()) {
|
|
41
41
|
(uint peer, bytes32 asset, uint amount) = exec.unpackAllowance(Lanes.Input);
|
|
@@ -21,10 +21,10 @@ abstract contract Annotate is AdminBase {
|
|
|
21
21
|
/// @return Empty transaction stream.
|
|
22
22
|
function annotate(
|
|
23
23
|
bytes32 account,
|
|
24
|
-
bytes calldata,
|
|
24
|
+
bytes calldata state,
|
|
25
25
|
bytes calldata input
|
|
26
26
|
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
27
|
-
Execution memory exec =
|
|
27
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
28
28
|
|
|
29
29
|
while (exec.more()) {
|
|
30
30
|
(uint entity, bytes calldata data) = exec.unpackAnnotation(Lanes.Input);
|
|
@@ -22,10 +22,10 @@ abstract contract Appoint is GuardianAccess, AdminBase {
|
|
|
22
22
|
/// @return Empty transaction stream.
|
|
23
23
|
function appoint(
|
|
24
24
|
bytes32 account,
|
|
25
|
-
bytes calldata,
|
|
25
|
+
bytes calldata state,
|
|
26
26
|
bytes calldata input
|
|
27
27
|
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
28
|
-
Execution memory exec =
|
|
28
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
29
29
|
|
|
30
30
|
while (exec.more()) {
|
|
31
31
|
bytes32 guardian = exec.unpackAccount(Lanes.Input);
|
|
@@ -27,10 +27,10 @@ abstract contract Authorize is AdminBase {
|
|
|
27
27
|
/// @return Empty transaction stream.
|
|
28
28
|
function authorize(
|
|
29
29
|
bytes32 account,
|
|
30
|
-
bytes calldata,
|
|
30
|
+
bytes calldata state,
|
|
31
31
|
bytes calldata input
|
|
32
32
|
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
33
|
-
Execution memory exec =
|
|
33
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
34
34
|
|
|
35
35
|
while (exec.more()) {
|
|
36
36
|
uint node = exec.unpackNode(Lanes.Input);
|
|
@@ -28,10 +28,10 @@ abstract contract DenyAssets is AdminBase, DenyAssetsHook {
|
|
|
28
28
|
/// @return Empty transaction stream.
|
|
29
29
|
function denyAssets(
|
|
30
30
|
bytes32 account,
|
|
31
|
-
bytes calldata,
|
|
31
|
+
bytes calldata state,
|
|
32
32
|
bytes calldata input
|
|
33
33
|
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
34
|
-
Execution memory exec =
|
|
34
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
35
35
|
|
|
36
36
|
while (exec.more()) {
|
|
37
37
|
bytes32 asset = exec.unpackAsset(Lanes.Input);
|
|
@@ -22,10 +22,10 @@ abstract contract Dismiss is GuardianAccess, AdminBase {
|
|
|
22
22
|
/// @return Empty transaction stream.
|
|
23
23
|
function dismiss(
|
|
24
24
|
bytes32 account,
|
|
25
|
-
bytes calldata,
|
|
25
|
+
bytes calldata state,
|
|
26
26
|
bytes calldata input
|
|
27
27
|
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
28
|
-
Execution memory exec =
|
|
28
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
29
29
|
|
|
30
30
|
while (exec.more()) {
|
|
31
31
|
bytes32 guardian = exec.unpackAccount(Lanes.Input);
|
|
@@ -24,14 +24,14 @@ abstract contract ExecutePayable is RawNodeCalls, AdminBase {
|
|
|
24
24
|
/// @return Remaining native value as a refund transaction stream.
|
|
25
25
|
function executePayable(
|
|
26
26
|
bytes32 account,
|
|
27
|
-
bytes calldata,
|
|
27
|
+
bytes calldata state,
|
|
28
28
|
bytes calldata input
|
|
29
29
|
) external payable onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
30
|
-
Execution memory exec =
|
|
30
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
31
31
|
|
|
32
32
|
while (exec.more()) {
|
|
33
33
|
(uint target, uint resources, bytes calldata data) = exec.unpackCall(Lanes.Input);
|
|
34
|
-
rawCall(target, exec.
|
|
34
|
+
rawCall(target, exec.useResourceValue(resources), data);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
return close(exec, account);
|
|
@@ -27,10 +27,10 @@ abstract contract Unauthorize is AdminBase {
|
|
|
27
27
|
/// @return Empty transaction stream.
|
|
28
28
|
function unauthorize(
|
|
29
29
|
bytes32 account,
|
|
30
|
-
bytes calldata,
|
|
30
|
+
bytes calldata state,
|
|
31
31
|
bytes calldata input
|
|
32
32
|
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
33
|
-
Execution memory exec =
|
|
33
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
34
34
|
|
|
35
35
|
while (exec.more()) {
|
|
36
36
|
uint node = exec.unpackNode(Lanes.Input);
|
package/core/Endpoint.sol
CHANGED
|
@@ -43,19 +43,6 @@ abstract contract EndpointBase is EndpointEvent, Label, Schema {
|
|
|
43
43
|
return descriptor;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/// @notice Open an endpoint input stream with an expected batch count.
|
|
47
|
-
/// @param source Input block stream to open.
|
|
48
|
-
/// @param descriptor Packed endpoint descriptor.
|
|
49
|
-
/// @param batches Required batch count, or zero to accept the input count.
|
|
50
|
-
/// @return exec Execution with its output buffer metadata initialized for the input batch count.
|
|
51
|
-
function openInput(
|
|
52
|
-
bytes calldata source,
|
|
53
|
-
uint descriptor,
|
|
54
|
-
uint batches
|
|
55
|
-
) internal view returns (Execution memory exec) {
|
|
56
|
-
return Executions.openInput(source, descriptor, batches);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
46
|
/// @notice Finalize an execution output and return its encoded block stream.
|
|
60
47
|
/// @param exec Completed endpoint execution.
|
|
61
48
|
/// @return Encoded output block stream.
|
|
@@ -63,3 +50,18 @@ abstract contract EndpointBase is EndpointEvent, Label, Schema {
|
|
|
63
50
|
return Executions.finish(exec);
|
|
64
51
|
}
|
|
65
52
|
}
|
|
53
|
+
|
|
54
|
+
/// @title InputEndpointBase
|
|
55
|
+
/// @notice Shared input opening for endpoint families that have only an input lane.
|
|
56
|
+
/// Commands intentionally do not inherit this base because they must open state
|
|
57
|
+
/// and input together through `openCommand`.
|
|
58
|
+
abstract contract InputEndpointBase is EndpointBase {
|
|
59
|
+
/// @notice Open an endpoint input stream with an expected batch count.
|
|
60
|
+
function openInput(
|
|
61
|
+
bytes calldata input,
|
|
62
|
+
uint descriptor,
|
|
63
|
+
uint batches
|
|
64
|
+
) internal view returns (Execution memory exec) {
|
|
65
|
+
return Executions.openInput(input, descriptor, batches);
|
|
66
|
+
}
|
|
67
|
+
}
|
package/core/Pipeline.sol
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import {Decoders, Cur, Readers, Reader} from "../Codec.sol";
|
|
5
|
-
import {
|
|
5
|
+
import {PostHook} from "./Settlement.sol";
|
|
6
6
|
import {Budget, Budgets} from "../execution/Budget.sol";
|
|
7
7
|
|
|
8
8
|
using Decoders for Cur;
|
|
@@ -11,14 +11,14 @@ using Budgets for Budget;
|
|
|
11
11
|
|
|
12
12
|
/// @title Pipeline
|
|
13
13
|
/// @notice Core pipeline functionality shared by higher-level surfaces.
|
|
14
|
-
abstract contract Pipeline is
|
|
14
|
+
abstract contract Pipeline is PostHook {
|
|
15
15
|
/// @dev Thrown when the pipeline finishes with non-empty threaded state.
|
|
16
16
|
error UnexpectedState();
|
|
17
17
|
|
|
18
18
|
/// @notice Override to dispatch one piped step.
|
|
19
19
|
/// Called once per STEP block. The returned state becomes the state passed to
|
|
20
20
|
/// the next step, and the final returned state must be empty. Returned
|
|
21
|
-
/// transactions are decoded and passed individually to `
|
|
21
|
+
/// transactions are decoded and passed individually to `post` before the next step runs.
|
|
22
22
|
/// @param cmd Command node ID to invoke or handle.
|
|
23
23
|
/// @param account Account identifier for the piped context.
|
|
24
24
|
/// @param state Current threaded state block stream.
|
|
@@ -42,16 +42,16 @@ abstract contract Pipeline is Settlement {
|
|
|
42
42
|
/// @param steps STEP block stream to execute.
|
|
43
43
|
/// @param budget Mutable native-value budget shared across all steps.
|
|
44
44
|
function pipe(bytes32 account, bytes memory state, bytes calldata steps, Budget memory budget) internal {
|
|
45
|
-
Cur memory cur = Decoders.open(steps
|
|
45
|
+
Cur memory cur = Decoders.open(steps);
|
|
46
46
|
|
|
47
47
|
while (cur.more()) {
|
|
48
48
|
(uint cmd, uint resources, bytes calldata input) = cur.unpackStep();
|
|
49
49
|
Reader memory txs;
|
|
50
|
-
(state, txs.source) = dispatch(cmd, account, state, input, budget.
|
|
50
|
+
(state, txs.source) = dispatch(cmd, account, state, input, budget.useResourceValue(resources));
|
|
51
51
|
|
|
52
52
|
while (txs.more()) {
|
|
53
53
|
(bytes32 from, bytes32 to, bytes32 asset, uint amount) = txs.unpackTransaction();
|
|
54
|
-
|
|
54
|
+
post(from, to, asset, amount);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
package/core/Settlement.sol
CHANGED
|
@@ -21,19 +21,48 @@ abstract contract CreditAccountHook {
|
|
|
21
21
|
function creditAccount(bytes32 account, bytes32 asset, uint amount) internal virtual;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/// @title PostHook
|
|
25
|
+
/// @notice Hook for posting one transaction between accounts.
|
|
26
|
+
abstract contract PostHook {
|
|
27
|
+
/// @notice Override to post one transaction.
|
|
28
|
+
function post(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal virtual;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// @title SettleHook
|
|
32
|
+
/// @notice Hook for settling one asset-liability position.
|
|
33
|
+
abstract contract SettleHook {
|
|
34
|
+
/// @notice Override to settle one position for `account`.
|
|
35
|
+
function settle(
|
|
36
|
+
bytes32 account,
|
|
37
|
+
bytes32 asset,
|
|
38
|
+
uint amount,
|
|
39
|
+
bytes32 liability,
|
|
40
|
+
uint debt
|
|
41
|
+
) internal virtual;
|
|
42
|
+
}
|
|
43
|
+
|
|
24
44
|
/// @title Settlement
|
|
25
|
-
/// @notice
|
|
26
|
-
abstract contract Settlement is DebitAccountHook, CreditAccountHook {
|
|
27
|
-
/// @notice
|
|
45
|
+
/// @notice Default account-hook implementation for transaction posting and position settlement.
|
|
46
|
+
abstract contract Settlement is PostHook, SettleHook, DebitAccountHook, CreditAccountHook {
|
|
47
|
+
/// @notice Post one transaction by debiting its source and crediting its destination.
|
|
28
48
|
/// Returns without calling either hook when `amount` is zero and skips either
|
|
29
49
|
/// operation when the corresponding account is zero.
|
|
30
|
-
|
|
31
|
-
/// @param to Destination account identifier.
|
|
32
|
-
/// @param asset Asset identifier.
|
|
33
|
-
/// @param amount Token amount.
|
|
34
|
-
function settle(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal {
|
|
50
|
+
function post(bytes32 from, bytes32 to, bytes32 asset, uint amount) internal virtual override {
|
|
35
51
|
if (amount == 0) return;
|
|
36
52
|
if (from != 0) debitAccount(from, asset, amount);
|
|
37
53
|
if (to != 0) creditAccount(to, asset, amount);
|
|
38
54
|
}
|
|
55
|
+
|
|
56
|
+
/// @notice Settle one position by crediting its asset and debiting its liability.
|
|
57
|
+
/// Skips either operation when its corresponding amount is zero.
|
|
58
|
+
function settle(
|
|
59
|
+
bytes32 account,
|
|
60
|
+
bytes32 asset,
|
|
61
|
+
uint amount,
|
|
62
|
+
bytes32 liability,
|
|
63
|
+
uint debt
|
|
64
|
+
) internal virtual override {
|
|
65
|
+
if (amount != 0) creditAccount(account, asset, amount);
|
|
66
|
+
if (debt != 0) debitAccount(account, liability, debt);
|
|
67
|
+
}
|
|
39
68
|
}
|
package/core/Types.sol
CHANGED
|
@@ -27,6 +27,14 @@ struct AccountAmount {
|
|
|
27
27
|
uint amount;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/// @notice Host-scoped asset shape.
|
|
31
|
+
struct HostAsset {
|
|
32
|
+
/// @dev Host node identifier.
|
|
33
|
+
uint host;
|
|
34
|
+
/// @dev Asset identifier.
|
|
35
|
+
bytes32 asset;
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
/// @notice Host-scoped asset and amount shape.
|
|
31
39
|
struct HostAmount {
|
|
32
40
|
/// @dev Host node identifier.
|
|
@@ -59,7 +67,19 @@ struct HostAccountAmount {
|
|
|
59
67
|
uint amount;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
|
-
/// @notice
|
|
70
|
+
/// @notice Asset and liability pair threaded as live pipeline state.
|
|
71
|
+
struct Position {
|
|
72
|
+
/// @dev Identifier for the asset side.
|
|
73
|
+
bytes32 asset;
|
|
74
|
+
/// @dev Quantity on the asset side.
|
|
75
|
+
uint amount;
|
|
76
|
+
/// @dev Identifier for the liability side.
|
|
77
|
+
bytes32 liability;
|
|
78
|
+
/// @dev Quantity owed on the liability side.
|
|
79
|
+
uint debt;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// @notice Transfer payload used by transaction blocks and peer posting.
|
|
63
83
|
struct Tx {
|
|
64
84
|
/// @dev Sender account identifier.
|
|
65
85
|
bytes32 from;
|
package/docs/Schema.md
CHANGED
|
@@ -161,8 +161,58 @@ with no payload, use a zero-payload block such as `#unit`.
|
|
|
161
161
|
|
|
162
162
|
Endpoint descriptors currently use a narrower convention than the full block
|
|
163
163
|
grammar: each state, input, or output lane is a single run of blocks, without
|
|
164
|
-
additional global items.
|
|
165
|
-
|
|
164
|
+
additional global items. Endpoint decoder opening requires that run to consume
|
|
165
|
+
the complete supplied lane; a trailing block with another key is invalid.
|
|
166
|
+
Lower-level cursor scanning may still intentionally open only a prefix run.
|
|
167
|
+
Those lower layers retain only the raw block count; descriptor strides are
|
|
168
|
+
applied and lane groups reconciled once when an endpoint execution opens.
|
|
169
|
+
Future protocol surfaces may use the more flexible top-level structure.
|
|
170
|
+
|
|
171
|
+
For commands, complete-lane validation is also a state-safety rule. State is a
|
|
172
|
+
linear value owned by the current pipeline step, not optional context that a
|
|
173
|
+
command may disregard. Every command must account for the complete supplied
|
|
174
|
+
state by consuming it, transforming and returning it, forwarding it intact, or
|
|
175
|
+
reverting. A command whose descriptor declares an empty state lane must reject
|
|
176
|
+
non-empty state. A command that accepts state must validate the complete stream
|
|
177
|
+
against its declared schema; accepting only a prefix and silently dropping the
|
|
178
|
+
remainder is invalid.
|
|
179
|
+
|
|
180
|
+
## Live Pipeline State
|
|
181
|
+
|
|
182
|
+
`#balance`, `#custody`, and `#position` are live state carried between command
|
|
183
|
+
steps for the active account. A position atomically pairs an asset side with a
|
|
184
|
+
liability side:
|
|
185
|
+
|
|
186
|
+
```txt
|
|
187
|
+
position { bytes32 asset, uint amount, bytes32 liability, uint debt }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The pair is deliberately general. The asset side represents value acquired or
|
|
191
|
+
controlled, and the liability side represents value owed or required. Commands
|
|
192
|
+
may preserve or replace either side and return a new position. The terminal
|
|
193
|
+
`settle` command consumes the pair. Position state is transient protocol state;
|
|
194
|
+
rewriting it does not by itself create, discharge, or replace an obligation
|
|
195
|
+
persisted by a host or external protocol. The responsible command hook must
|
|
196
|
+
perform or verify those effects. A command must not ignore a supplied position:
|
|
197
|
+
it must explicitly consume, transform, forward, or reject it, so neither its
|
|
198
|
+
asset nor its debt can disappear accidentally.
|
|
199
|
+
|
|
200
|
+
This representation supports ordinary forward transformations as well as
|
|
201
|
+
backward composition. For example, an exact-output route can carry its desired
|
|
202
|
+
asset while successive hops replace the upstream liability:
|
|
203
|
+
|
|
204
|
+
```txt
|
|
205
|
+
position(C, 100, C, 100)
|
|
206
|
+
→ position(C, 100, B, 50)
|
|
207
|
+
→ position(C, 100, A, 25)
|
|
208
|
+
→ settle
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
“Backward” describes how requirements are composed from the desired result
|
|
212
|
+
toward the source. Pipeline execution is not reversed: STEP blocks always run
|
|
213
|
+
forward in their encoded order. Exact-output routing is only an example;
|
|
214
|
+
borrowing, refinancing, collateral transformation, callback obligations,
|
|
215
|
+
cross-host claims, fees, and netting can use the same position state.
|
|
166
216
|
|
|
167
217
|
## Field Aliases
|
|
168
218
|
|
package/execution/Budget.sol
CHANGED
|
@@ -19,15 +19,23 @@ library Budgets {
|
|
|
19
19
|
budget.remaining = msg.value;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/// @notice Deduct an exact native value from `budget`.
|
|
23
|
+
/// @param budget Mutable budget to debit.
|
|
24
|
+
/// @param value Native value to consume in wei.
|
|
25
|
+
/// @return The consumed native value.
|
|
26
|
+
function useValue(Budget memory budget, uint value) internal pure returns (uint) {
|
|
27
|
+
if (value > budget.remaining) revert InsufficientValue();
|
|
28
|
+
budget.remaining -= value;
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
/// @notice Deduct the EVM value lane of `resources` from `budget`.
|
|
23
33
|
/// @dev EVM resources use the low 128 bits as native value/endowment.
|
|
24
34
|
/// @param budget Mutable budget to debit.
|
|
25
35
|
/// @param resources Packed resources whose low 128 bits contain native value.
|
|
26
36
|
/// @return value Native value to forward in wei.
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
if (value > budget.remaining) revert InsufficientValue();
|
|
30
|
-
budget.remaining -= value;
|
|
37
|
+
function useResourceValue(Budget memory budget, uint resources) internal pure returns (uint128) {
|
|
38
|
+
return uint128(useValue(budget, uint128(resources)));
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
/// @notice Remove and return all remaining value from `budget`.
|