@rootzero/contracts 1.22.0 → 1.24.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 +107 -0
- package/Codec.sol +1 -1
- package/Commands.sol +1 -1
- package/Core.sol +2 -2
- package/Endpoints.sol +10 -4
- package/Events.sol +1 -1
- package/README.md +40 -32
- package/Utils.sol +1 -1
- package/annotations/Action.sol +1 -1
- package/annotations/Label.sol +1 -1
- package/annotations/Schema.sol +2 -8
- package/codec/Blocks.sol +113 -33
- package/codec/Decoders.sol +18 -1
- package/codec/Descriptors.sol +3 -1
- package/codec/Keys.sol +2 -0
- package/codec/Readers.sol +12 -0
- package/codec/Schema.sol +5 -4
- package/codec/Specs.sol +3 -0
- package/codec/Writers.sol +12 -1
- package/commands/Allocate.sol +5 -8
- package/commands/Base.sol +29 -13
- package/commands/Burn.sol +5 -7
- package/commands/Credit.sol +5 -7
- package/commands/Debit.sol +5 -7
- package/commands/Deposit.sol +10 -14
- package/commands/Payout.sol +5 -8
- package/commands/Provision.sol +10 -14
- package/commands/Recover.sol +4 -6
- package/commands/Relay.sol +14 -21
- package/commands/Repay.sol +120 -24
- package/commands/Settle.sol +10 -14
- package/commands/Withdraw.sol +5 -7
- package/commands/admin/AllowAssets.sol +5 -7
- package/commands/admin/Allowance.sol +5 -7
- package/commands/admin/Annotate.sol +5 -7
- package/commands/admin/Appoint.sol +5 -7
- package/commands/admin/Authorize.sol +5 -7
- package/commands/admin/Base.sol +12 -3
- package/commands/admin/DenyAssets.sol +5 -7
- package/commands/admin/Dismiss.sol +5 -7
- package/commands/admin/Execute.sol +5 -7
- package/commands/admin/Unauthorize.sol +5 -7
- package/core/Access.sol +8 -0
- package/core/Calls.sol +72 -3
- package/core/Portal.sol +2 -2
- package/core/Types.sol +8 -0
- package/events/Positioned.sol +22 -0
- package/execution/Execution.sol +66 -1
- package/package.json +1 -1
- package/ports/Allowance.sol +22 -12
- package/ports/Assets.sol +99 -0
- package/utils/Cursors.sol +3 -3
- package/utils/Nodes.sol +1 -1
- package/utils/Utils.sol +41 -31
- package/events/Commander.sol +0 -19
- package/ports/AllowAssets.sol +0 -34
- package/ports/DenyAssets.sol +0 -34
|
@@ -16,21 +16,19 @@ abstract contract Annotate is AdminBase {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/// @notice Publish each ANNOTATION block in the admin input.
|
|
19
|
-
/// @param
|
|
19
|
+
/// @param context Admin command context carrying the ANNOTATION input stream.
|
|
20
20
|
/// @return Empty output state.
|
|
21
21
|
/// @return Empty transaction stream.
|
|
22
22
|
function annotate(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
27
|
-
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
23
|
+
bytes calldata context
|
|
24
|
+
) external returns (bytes memory, bytes memory) {
|
|
25
|
+
Execution memory exec = openAdminCommand(context, descriptor, 0);
|
|
28
26
|
|
|
29
27
|
while (exec.more()) {
|
|
30
28
|
(uint entity, bytes calldata data) = exec.unpackAnnotation(Lanes.Input);
|
|
31
29
|
emit Annotation(entity, data);
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
return
|
|
32
|
+
return closeCommand(exec);
|
|
35
33
|
}
|
|
36
34
|
}
|
|
@@ -17,21 +17,19 @@ abstract contract Appoint is GuardianAccess, AdminBase {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/// @notice Appoint each user ACCOUNT block in the admin input as a guardian.
|
|
20
|
-
/// @param
|
|
20
|
+
/// @param context Admin command context carrying the ACCOUNT input stream.
|
|
21
21
|
/// @return Empty output state.
|
|
22
22
|
/// @return Empty transaction stream.
|
|
23
23
|
function appoint(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
28
|
-
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
24
|
+
bytes calldata context
|
|
25
|
+
) external returns (bytes memory, bytes memory) {
|
|
26
|
+
Execution memory exec = openAdminCommand(context, descriptor, 0);
|
|
29
27
|
|
|
30
28
|
while (exec.more()) {
|
|
31
29
|
bytes32 guardian = exec.unpackAccount(Lanes.Input);
|
|
32
30
|
setGuardian(guardian, true);
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
return
|
|
33
|
+
return closeCommand(exec);
|
|
36
34
|
}
|
|
37
35
|
}
|
|
@@ -22,21 +22,19 @@ abstract contract Authorize is AdminBase {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/// @notice Authorize each NODE block in the admin input.
|
|
25
|
-
/// @param
|
|
25
|
+
/// @param context Admin command context carrying the NODE input stream.
|
|
26
26
|
/// @return Empty output state.
|
|
27
27
|
/// @return Empty transaction stream.
|
|
28
28
|
function authorize(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
33
|
-
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
29
|
+
bytes calldata context
|
|
30
|
+
) external returns (bytes memory, bytes memory) {
|
|
31
|
+
Execution memory exec = openAdminCommand(context, descriptor, 0);
|
|
34
32
|
|
|
35
33
|
while (exec.more()) {
|
|
36
34
|
uint node = exec.unpackNode(Lanes.Input);
|
|
37
35
|
setNode(node, true);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
return
|
|
38
|
+
return closeCommand(exec);
|
|
41
39
|
}
|
|
42
40
|
}
|
package/commands/admin/Base.sol
CHANGED
|
@@ -7,9 +7,18 @@ import {NodeAccess} from "../../core/Access.sol";
|
|
|
7
7
|
/// @title AdminBase
|
|
8
8
|
/// @notice Shared base for admin commands.
|
|
9
9
|
abstract contract AdminBase is NodeAccess, CommandBase {
|
|
10
|
-
/// @
|
|
11
|
-
|
|
10
|
+
/// @notice Decode, authorize, and open one admin command context.
|
|
11
|
+
function openAdminCommand(
|
|
12
|
+
bytes calldata context,
|
|
13
|
+
uint descriptor,
|
|
14
|
+
uint batches
|
|
15
|
+
) internal view returns (Execution memory exec) {
|
|
16
|
+
bytes32 account;
|
|
17
|
+
bytes calldata state;
|
|
18
|
+
bytes calldata input;
|
|
19
|
+
(account, state, input) = unpackCommandContext(context);
|
|
12
20
|
enforceAdmin(account, msg.sender);
|
|
13
|
-
|
|
21
|
+
exec = Executions.open(state, input, descriptor, batches);
|
|
22
|
+
exec.account = account;
|
|
14
23
|
}
|
|
15
24
|
}
|
|
@@ -23,21 +23,19 @@ abstract contract DenyAssets is AdminBase, DenyAssetsHook {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/// @notice Deny each ASSET block in the admin input.
|
|
26
|
-
/// @param
|
|
26
|
+
/// @param context Admin command context carrying the ASSET input stream.
|
|
27
27
|
/// @return Empty output state.
|
|
28
28
|
/// @return Empty transaction stream.
|
|
29
29
|
function denyAssets(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
34
|
-
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
30
|
+
bytes calldata context
|
|
31
|
+
) external returns (bytes memory, bytes memory) {
|
|
32
|
+
Execution memory exec = openAdminCommand(context, descriptor, 0);
|
|
35
33
|
|
|
36
34
|
while (exec.more()) {
|
|
37
35
|
bytes32 asset = exec.unpackAsset(Lanes.Input);
|
|
38
36
|
denyAsset(asset);
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
return
|
|
39
|
+
return closeCommand(exec);
|
|
42
40
|
}
|
|
43
41
|
}
|
|
@@ -17,21 +17,19 @@ abstract contract Dismiss is GuardianAccess, AdminBase {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/// @notice Dismiss each user ACCOUNT block in the admin input from guardian status.
|
|
20
|
-
/// @param
|
|
20
|
+
/// @param context Admin command context carrying the ACCOUNT input stream.
|
|
21
21
|
/// @return Empty output state.
|
|
22
22
|
/// @return Empty transaction stream.
|
|
23
23
|
function dismiss(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
28
|
-
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
24
|
+
bytes calldata context
|
|
25
|
+
) external returns (bytes memory, bytes memory) {
|
|
26
|
+
Execution memory exec = openAdminCommand(context, descriptor, 0);
|
|
29
27
|
|
|
30
28
|
while (exec.more()) {
|
|
31
29
|
bytes32 guardian = exec.unpackAccount(Lanes.Input);
|
|
32
30
|
setGuardian(guardian, false);
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
return
|
|
33
|
+
return closeCommand(exec);
|
|
36
34
|
}
|
|
37
35
|
}
|
|
@@ -19,21 +19,19 @@ abstract contract ExecutePayable is RawNodeCalls, AdminBase {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/// @notice Execute each CALL block in the admin input.
|
|
22
|
-
/// @param
|
|
22
|
+
/// @param context Admin command context carrying the CALL input stream.
|
|
23
23
|
/// @return Empty output state.
|
|
24
24
|
/// @return Remaining native value as a refund transaction stream.
|
|
25
25
|
function executePayable(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
) external payable onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
30
|
-
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
26
|
+
bytes calldata context
|
|
27
|
+
) external payable returns (bytes memory, bytes memory) {
|
|
28
|
+
Execution memory exec = openAdminCommand(context, descriptor, 0);
|
|
31
29
|
|
|
32
30
|
while (exec.more()) {
|
|
33
31
|
(uint target, uint resources, bytes calldata data) = exec.unpackCall(Lanes.Input);
|
|
34
32
|
rawCall(target, exec.useResourceValue(resources), data);
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
return
|
|
35
|
+
return closeCommand(exec);
|
|
38
36
|
}
|
|
39
37
|
}
|
|
@@ -22,21 +22,19 @@ abstract contract Unauthorize is AdminBase {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/// @notice Unauthorize each NODE block in the admin input.
|
|
25
|
-
/// @param
|
|
25
|
+
/// @param context Admin command context carrying the NODE input stream.
|
|
26
26
|
/// @return Empty output state.
|
|
27
27
|
/// @return Empty transaction stream.
|
|
28
28
|
function unauthorize(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
) external onlyAdmin(account) returns (bytes memory, bytes memory) {
|
|
33
|
-
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
29
|
+
bytes calldata context
|
|
30
|
+
) external returns (bytes memory, bytes memory) {
|
|
31
|
+
Execution memory exec = openAdminCommand(context, descriptor, 0);
|
|
34
32
|
|
|
35
33
|
while (exec.more()) {
|
|
36
34
|
uint node = exec.unpackNode(Lanes.Input);
|
|
37
35
|
setNode(node, false);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
return
|
|
38
|
+
return closeCommand(exec);
|
|
41
39
|
}
|
|
42
40
|
}
|
package/core/Access.sol
CHANGED
|
@@ -12,6 +12,14 @@ import {addrOr} from "../utils/Utils.sol";
|
|
|
12
12
|
error AccessDenied();
|
|
13
13
|
error CommanderNotAllowed();
|
|
14
14
|
|
|
15
|
+
/// @notice Assert that `msg.sender` equals `expected` and return it.
|
|
16
|
+
/// @param expected Address required to be the current message sender.
|
|
17
|
+
/// @return The validated sender address.
|
|
18
|
+
function enforceSender(address expected) view returns (address) {
|
|
19
|
+
if (msg.sender != expected) revert AccessDenied();
|
|
20
|
+
return expected;
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
/// @title CallerAccess
|
|
16
24
|
/// @notice Authorization capability required by command entrypoints.
|
|
17
25
|
abstract contract CallerAccess is Runtime {
|
package/core/Calls.sol
CHANGED
|
@@ -3,6 +3,9 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import {TrustAccess} from "./Access.sol";
|
|
5
5
|
import {Nodes} from "../utils/Nodes.sol";
|
|
6
|
+
import {Keys} from "../codec/Keys.sol";
|
|
7
|
+
import {Sizes} from "../codec/Specs.sol";
|
|
8
|
+
import {max32} from "../utils/Utils.sol";
|
|
6
9
|
|
|
7
10
|
/// @dev Emitted when a trusted inter-node call fails.
|
|
8
11
|
/// @param addr Contract address that was called.
|
|
@@ -81,6 +84,50 @@ abstract contract NodeCalls is RawNodeCalls, TrustAccess {
|
|
|
81
84
|
/// @title CommandCalls
|
|
82
85
|
/// @notice Trusted command-call helpers for contracts that route command nodes.
|
|
83
86
|
abstract contract CommandCalls is NodeCalls {
|
|
87
|
+
/// @dev Build `command(bytes)` calldata and its nested CONTEXT block in one allocation.
|
|
88
|
+
/// Threaded state is copied from memory and step input directly from calldata.
|
|
89
|
+
function encodeCommandCall(
|
|
90
|
+
bytes4 selector,
|
|
91
|
+
bytes32 account,
|
|
92
|
+
bytes memory state,
|
|
93
|
+
bytes calldata input
|
|
94
|
+
) internal pure returns (bytes memory data) {
|
|
95
|
+
uint contextLen = max32(Sizes.B32 + 2 * Sizes.Header + state.length + input.length);
|
|
96
|
+
uint paddedContextLen = (contextLen + 31) & ~uint(31);
|
|
97
|
+
uint dataLen = 4 + 64 + paddedContextLen;
|
|
98
|
+
|
|
99
|
+
// Reserve one scratch word because the final eight-byte block header is
|
|
100
|
+
// written with mstore. Exclude that word from the returned calldata.
|
|
101
|
+
data = new bytes(dataLen + 32);
|
|
102
|
+
|
|
103
|
+
uint contextKey = uint32(Keys.Context);
|
|
104
|
+
uint bytesKey = uint32(Keys.Bytes);
|
|
105
|
+
assembly ("memory-safe") {
|
|
106
|
+
mstore(data, dataLen)
|
|
107
|
+
let out := add(data, 0x20)
|
|
108
|
+
|
|
109
|
+
// ABI envelope for command(bytes).
|
|
110
|
+
mstore(out, selector)
|
|
111
|
+
mstore(add(out, 0x04), 0x20)
|
|
112
|
+
mstore(add(out, 0x24), contextLen)
|
|
113
|
+
|
|
114
|
+
// CONTEXT(account, BYTES(state), BYTES(input)).
|
|
115
|
+
let context := add(out, 0x44)
|
|
116
|
+
mstore(context, or(shl(224, contextKey), shl(192, sub(contextLen, 8))))
|
|
117
|
+
mstore(add(context, 0x08), account)
|
|
118
|
+
|
|
119
|
+
let stateBlock := add(context, 0x28)
|
|
120
|
+
let stateLen := mload(state)
|
|
121
|
+
mstore(stateBlock, or(shl(224, bytesKey), shl(192, stateLen)))
|
|
122
|
+
mcopy(add(stateBlock, 0x08), add(state, 0x20), stateLen)
|
|
123
|
+
|
|
124
|
+
let inputBlock := add(add(stateBlock, 0x08), stateLen)
|
|
125
|
+
let inputLen := input.length
|
|
126
|
+
mstore(inputBlock, or(shl(224, bytesKey), shl(192, inputLen)))
|
|
127
|
+
calldatacopy(add(inputBlock, 0x08), input.offset, inputLen)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
84
131
|
/// @notice Encode and call a trusted command node.
|
|
85
132
|
/// @param command Command node ID embedding the target selector.
|
|
86
133
|
/// @param value Native value to forward in wei.
|
|
@@ -97,7 +144,7 @@ abstract contract CommandCalls is NodeCalls {
|
|
|
97
144
|
bytes calldata input
|
|
98
145
|
) internal returns (bytes memory nextState, bytes memory transactions) {
|
|
99
146
|
bytes4 selector = Nodes.commandSelector(command);
|
|
100
|
-
bytes memory data =
|
|
147
|
+
bytes memory data = encodeCommandCall(selector, account, state, input);
|
|
101
148
|
return abi.decode(trustedCall(command, value, data), (bytes, bytes));
|
|
102
149
|
}
|
|
103
150
|
}
|
|
@@ -110,7 +157,18 @@ abstract contract PortCalls is NodeCalls {
|
|
|
110
157
|
/// @param value Native value to forward in wei.
|
|
111
158
|
/// @param input Port input block stream.
|
|
112
159
|
/// @return success True if the low-level port call succeeded.
|
|
113
|
-
function tryCallPort(uint port, uint128 value, bytes
|
|
160
|
+
function tryCallPort(uint port, uint128 value, bytes memory input) internal returns (bool success) {
|
|
161
|
+
bytes4 selector = Nodes.portSelector(port);
|
|
162
|
+
bytes memory data = abi.encodeWithSelector(selector, input);
|
|
163
|
+
return tryTrustedCall(port, value, data);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// @notice Try to encode and call a trusted port node by copying input from calldata.
|
|
167
|
+
/// @param port Port node ID embedding the target selector.
|
|
168
|
+
/// @param value Native value to forward in wei.
|
|
169
|
+
/// @param input Port input block stream.
|
|
170
|
+
/// @return success True if the low-level port call succeeded.
|
|
171
|
+
function tryCallPortCopy(uint port, uint128 value, bytes calldata input) internal returns (bool success) {
|
|
114
172
|
bytes4 selector = Nodes.portSelector(port);
|
|
115
173
|
bytes memory data = abi.encodeWithSelector(selector, input);
|
|
116
174
|
return tryTrustedCall(port, value, data);
|
|
@@ -121,7 +179,18 @@ abstract contract PortCalls is NodeCalls {
|
|
|
121
179
|
/// @param value Native value to forward in wei.
|
|
122
180
|
/// @param input Port input block stream.
|
|
123
181
|
/// @return Decoded port output block stream.
|
|
124
|
-
function callPort(uint port, uint128 value, bytes
|
|
182
|
+
function callPort(uint port, uint128 value, bytes memory input) internal returns (bytes memory) {
|
|
183
|
+
bytes4 selector = Nodes.portSelector(port);
|
|
184
|
+
bytes memory data = abi.encodeWithSelector(selector, input);
|
|
185
|
+
return abi.decode(trustedCall(port, value, data), (bytes));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/// @notice Encode and call a trusted port node by copying input from calldata.
|
|
189
|
+
/// @param port Port node ID embedding the target selector.
|
|
190
|
+
/// @param value Native value to forward in wei.
|
|
191
|
+
/// @param input Port input block stream.
|
|
192
|
+
/// @return Decoded port output block stream.
|
|
193
|
+
function callPortCopy(uint port, uint128 value, bytes calldata input) internal returns (bytes memory) {
|
|
125
194
|
bytes4 selector = Nodes.portSelector(port);
|
|
126
195
|
bytes memory data = abi.encodeWithSelector(selector, input);
|
|
127
196
|
return abi.decode(trustedCall(port, value, data), (bytes));
|
package/core/Portal.sol
CHANGED
|
@@ -21,7 +21,7 @@ abstract contract Portal is PortCalls, NodeAccess, UnresolvedEvent, ResolvedEven
|
|
|
21
21
|
/// @param value Native EVM value assigned to the forwarding attempt.
|
|
22
22
|
/// @return miss Message digest recorded for recovery when forwarding fails; zero on success.
|
|
23
23
|
function forward(uint port, bytes32 key, bytes calldata message, uint128 value) internal returns (bytes32 miss) {
|
|
24
|
-
if (
|
|
24
|
+
if (tryCallPortCopy(port, value, message)) return bytes32(0);
|
|
25
25
|
|
|
26
26
|
miss = keccak256(message);
|
|
27
27
|
unresolved[key] = miss;
|
|
@@ -37,6 +37,6 @@ abstract contract Portal is PortCalls, NodeAccess, UnresolvedEvent, ResolvedEven
|
|
|
37
37
|
if (unresolved[key] != keccak256(witness)) revert BadWitness();
|
|
38
38
|
|
|
39
39
|
delete unresolved[key];
|
|
40
|
-
|
|
40
|
+
callPortCopy(port, value, witness);
|
|
41
41
|
}
|
|
42
42
|
}
|
package/core/Types.sol
CHANGED
|
@@ -67,6 +67,14 @@ struct HostAccountAmount {
|
|
|
67
67
|
uint amount;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/// @notice Liability and debt pair threaded as live pipeline state.
|
|
71
|
+
struct Debt {
|
|
72
|
+
/// @dev Identifier for the liability side.
|
|
73
|
+
bytes32 liability;
|
|
74
|
+
/// @dev Quantity owed on the liability side.
|
|
75
|
+
uint debt;
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
/// @notice Asset and liability pair threaded as live pipeline state.
|
|
71
79
|
struct Position {
|
|
72
80
|
/// @dev Identifier for the asset side.
|
|
@@ -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 action produces an account position.
|
|
7
|
+
abstract contract PositionedEvent is EventEmitter {
|
|
8
|
+
string private constant ABI =
|
|
9
|
+
"event Positioned(bytes32 indexed account, bytes32 asset, uint amount, bytes32 liability, uint debt, uint32 action)";
|
|
10
|
+
|
|
11
|
+
/// @param account Account associated with the position.
|
|
12
|
+
/// @param asset Identifier for the asset side.
|
|
13
|
+
/// @param amount Quantity on the asset side.
|
|
14
|
+
/// @param liability Identifier for the liability side.
|
|
15
|
+
/// @param debt Quantity owed on the liability side.
|
|
16
|
+
/// @param action Primary operation hint from `Actions` that produced the position.
|
|
17
|
+
event Positioned(bytes32 indexed account, bytes32 asset, uint amount, bytes32 liability, uint debt, uint32 action);
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
emit EventAbi(ABI);
|
|
21
|
+
}
|
|
22
|
+
}
|
package/execution/Execution.sol
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAccountAsset, Position, Tx} from "../core/Types.sol";
|
|
4
|
+
import {AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAccountAsset, Debt, Position, Tx} from "../core/Types.sol";
|
|
5
5
|
import {Blocks} from "../codec/Blocks.sol";
|
|
6
6
|
import {Buffers} from "../codec/Buffers.sol";
|
|
7
7
|
import {Sizes, Specs} from "../codec/Specs.sol";
|
|
@@ -15,6 +15,7 @@ import {max16} from "../utils/Utils.sol";
|
|
|
15
15
|
/// @dev `decoders` contains tagged input and state cursor lanes. Cursor operations
|
|
16
16
|
/// select one logical lane by swapping it into the lower 128 bits.
|
|
17
17
|
struct Execution {
|
|
18
|
+
bytes32 account;
|
|
18
19
|
uint budget;
|
|
19
20
|
uint decoders;
|
|
20
21
|
uint writers;
|
|
@@ -195,6 +196,33 @@ library Executions {
|
|
|
195
196
|
return exec.decoders.select(lane).absolute();
|
|
196
197
|
}
|
|
197
198
|
|
|
199
|
+
/// @dev Return the complete validated calldata source for a decoder lane.
|
|
200
|
+
/// @dev Does not consume or depend on the lane's current position. A lane
|
|
201
|
+
/// absent because its descriptor is EMPTY returns an empty calldata slice.
|
|
202
|
+
/// @param exec Execution whose input or state source is requested.
|
|
203
|
+
/// @param lane Input or state decoder lane.
|
|
204
|
+
/// @return data Complete calldata region represented by the lane.
|
|
205
|
+
function raw(Execution memory exec, uint8 lane) private pure returns (bytes calldata data) {
|
|
206
|
+
if (!exec.decoders.contains(lane)) return msg.data[0:0];
|
|
207
|
+
|
|
208
|
+
uint cur = exec.decoders.select(lane);
|
|
209
|
+
(, uint offset, uint len) = cur.decode();
|
|
210
|
+
if (len > msg.data.length || offset > msg.data.length - len) revert Blocks.MalformedBlocks();
|
|
211
|
+
return msg.data[offset:offset + len];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/// @notice Return the complete validated command state without consuming it.
|
|
215
|
+
/// @dev Remains the complete original state after the state cursor advances.
|
|
216
|
+
function rawState(Execution memory exec) internal pure returns (bytes calldata) {
|
|
217
|
+
return raw(exec, Lanes.State);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/// @notice Return the complete validated endpoint input without consuming it.
|
|
221
|
+
/// @dev Remains the complete original input after the input cursor advances.
|
|
222
|
+
function rawInput(Execution memory exec) internal pure returns (bytes calldata) {
|
|
223
|
+
return raw(exec, Lanes.Input);
|
|
224
|
+
}
|
|
225
|
+
|
|
198
226
|
/// @notice Return whether the next block on `lane` has `key` and an empty payload.
|
|
199
227
|
/// @param exec Execution whose decoder is inspected without advancing.
|
|
200
228
|
/// @param lane Decoder lane to inspect.
|
|
@@ -218,6 +246,20 @@ library Executions {
|
|
|
218
246
|
exec.decoders = cur.seekAbs(end);
|
|
219
247
|
}
|
|
220
248
|
|
|
249
|
+
/// @notice Validate and consume one block from a decoder lane, returning its complete encoding.
|
|
250
|
+
/// @param exec Execution whose selected decoder cursor is advanced past the block.
|
|
251
|
+
/// @param lane Execution decoder lane to select.
|
|
252
|
+
/// @param key Expected block key.
|
|
253
|
+
/// @return data Calldata view of the complete block, including its header.
|
|
254
|
+
function takeBlock(
|
|
255
|
+
Execution memory exec,
|
|
256
|
+
uint8 lane,
|
|
257
|
+
bytes4 key
|
|
258
|
+
) internal pure returns (bytes calldata data) {
|
|
259
|
+
(uint abs, uint end) = consume(exec, lane, Specs.create(key, 0, 0, 0));
|
|
260
|
+
data = msg.data[abs - Sizes.Header:end];
|
|
261
|
+
}
|
|
262
|
+
|
|
221
263
|
/// @notice Consume a matching empty block from an execution decoder lane when present.
|
|
222
264
|
/// @param exec Execution whose selected decoder advances only for a matching empty block.
|
|
223
265
|
/// @param lane Decoder lane to consume.
|
|
@@ -486,6 +528,18 @@ library Executions {
|
|
|
486
528
|
(value.asset, value.amount) = unpackBalance(exec, lane);
|
|
487
529
|
}
|
|
488
530
|
|
|
531
|
+
/// @notice Decode and consume one DEBT block from `lane`.
|
|
532
|
+
function unpackDebt(Execution memory exec, uint8 lane) internal pure returns (bytes32 liability, uint debt) {
|
|
533
|
+
uint abs;
|
|
534
|
+
(exec.decoders, abs) = exec.decoders.consume(lane, Sizes.Debt);
|
|
535
|
+
(liability, debt) = Blocks.unpackDebt(abs);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/// @notice Decode one DEBT block into its structured value.
|
|
539
|
+
function unpackDebtValue(Execution memory exec, uint8 lane) internal pure returns (Debt memory value) {
|
|
540
|
+
(value.liability, value.debt) = unpackDebt(exec, lane);
|
|
541
|
+
}
|
|
542
|
+
|
|
489
543
|
/// @notice Decode and consume one POSITION block from `lane`.
|
|
490
544
|
function unpackPosition(
|
|
491
545
|
Execution memory exec,
|
|
@@ -948,6 +1002,17 @@ library Executions {
|
|
|
948
1002
|
outputBalance(exec, value.asset, value.amount);
|
|
949
1003
|
}
|
|
950
1004
|
|
|
1005
|
+
/// @notice Append a DEBT block to execution output.
|
|
1006
|
+
function outputDebt(Execution memory exec, bytes32 liability, uint debt) internal pure {
|
|
1007
|
+
uint i = reserve(exec, Sizes.Debt);
|
|
1008
|
+
Blocks.writeDebt(exec.output, i, liability, debt);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/// @notice Append a structured DEBT value to execution output.
|
|
1012
|
+
function outputDebt(Execution memory exec, Debt memory value) internal pure {
|
|
1013
|
+
outputDebt(exec, value.liability, value.debt);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
951
1016
|
/// @notice Append a POSITION block to execution output.
|
|
952
1017
|
function outputPosition(
|
|
953
1018
|
Execution memory exec,
|
package/package.json
CHANGED
package/ports/Allowance.sol
CHANGED
|
@@ -2,35 +2,45 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import {PortBase} from "./Base.sol";
|
|
5
|
-
import {AllowanceHook} from "../commands/admin/Allowance.sol";
|
|
6
5
|
import {Specs} from "../Codec.sol";
|
|
7
6
|
import {Execution, Executions, Lanes} from "../execution/Execution.sol";
|
|
8
7
|
|
|
9
8
|
using Executions for Execution;
|
|
10
9
|
|
|
11
|
-
/// @
|
|
12
|
-
|
|
13
|
-
///
|
|
14
|
-
///
|
|
15
|
-
|
|
10
|
+
/// @notice Hook implemented by hosts that handle allowance requests from peers.
|
|
11
|
+
abstract contract RequestAllowanceHook {
|
|
12
|
+
/// @notice Override to handle one allowance request from a peer host.
|
|
13
|
+
/// @dev The implementation is responsible for validating the request and
|
|
14
|
+
/// deciding what allowance, if any, to grant.
|
|
15
|
+
/// @param peer Peer host node ID requesting the allowance.
|
|
16
|
+
/// @param asset Asset identifier supplied by the peer.
|
|
17
|
+
/// @param amount Allowance amount requested in the asset's native units.
|
|
18
|
+
function requestAllowance(uint peer, bytes32 asset, uint amount) internal virtual;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @title RequestAllowancePort
|
|
22
|
+
/// @notice Port that lets trusted peers request their own asset allowances.
|
|
23
|
+
/// Each AMOUNT block is scoped to the caller and passed unchanged to
|
|
24
|
+
/// `requestAllowance(peer, asset, amount)`.
|
|
25
|
+
abstract contract RequestAllowancePort is PortBase, RequestAllowanceHook {
|
|
16
26
|
uint private immutable descriptor;
|
|
17
27
|
|
|
18
28
|
constructor() {
|
|
19
|
-
(, descriptor) = port("
|
|
29
|
+
(, descriptor) = port("portRequestAllowance", Specs.Amount, Specs.Empty, 0);
|
|
20
30
|
}
|
|
21
31
|
|
|
22
|
-
/// @notice
|
|
23
|
-
/// @param data AMOUNT block stream
|
|
32
|
+
/// @notice Request asset allowances for the calling peer.
|
|
33
|
+
/// @param data AMOUNT block stream supplied by the trusted peer.
|
|
24
34
|
/// @return Empty response bytes.
|
|
25
|
-
function
|
|
35
|
+
function portRequestAllowance(bytes calldata data) external onlyPeer returns (bytes memory) {
|
|
26
36
|
Execution memory exec = openInput(data, descriptor, 0);
|
|
27
37
|
uint peer = caller();
|
|
28
38
|
|
|
29
39
|
while (exec.more()) {
|
|
30
40
|
(bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
|
|
31
|
-
|
|
41
|
+
requestAllowance(peer, asset, amount);
|
|
32
42
|
}
|
|
33
|
-
|
|
43
|
+
|
|
34
44
|
return "";
|
|
35
45
|
}
|
|
36
46
|
}
|