@rootzero/contracts 1.11.0 → 1.13.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 +52 -0
- package/Core.sol +2 -1
- package/Cursors.sol +2 -2
- package/Endpoints.sol +5 -2
- package/README.md +40 -17
- package/blocks/Cursors.sol +142 -0
- package/blocks/Keys.sol +2 -10
- package/blocks/Schema.sol +4 -3
- package/blocks/Writers.sol +17 -9
- package/commands/Allocate.sol +49 -0
- package/commands/Burn.sol +3 -2
- package/commands/Credit.sol +6 -18
- package/commands/Debit.sol +6 -18
- package/commands/Deposit.sol +6 -5
- package/commands/Payout.sol +3 -2
- package/commands/Provision.sol +6 -5
- package/commands/Recover.sol +3 -3
- package/commands/Relay.sol +3 -3
- package/commands/Withdraw.sol +3 -2
- package/commands/admin/AllowAssets.sol +3 -2
- package/commands/admin/Allowance.sol +3 -2
- package/commands/admin/Appoint.sol +3 -2
- package/commands/admin/Authorize.sol +7 -12
- package/commands/admin/DenyAssets.sol +3 -2
- package/commands/admin/Dismiss.sol +3 -2
- package/commands/admin/Execute.sol +3 -2
- package/commands/admin/Label.sol +3 -2
- package/commands/admin/Schemas.sol +32 -0
- package/commands/admin/Unauthorize.sol +7 -12
- package/core/Calls.sol +4 -3
- package/core/Endpoint.sol +31 -22
- package/core/Host.sol +11 -3
- package/core/Payable.sol +19 -19
- package/core/Pipeline.sol +17 -14
- package/core/Settlement.sol +39 -0
- package/docs/Schema.md +17 -11
- package/events/Introduction.sol +4 -3
- package/package.json +1 -1
- package/ports/Credit.sol +1 -1
- package/ports/Debit.sol +1 -1
- package/ports/Settle.sol +3 -5
package/core/Payable.sol
CHANGED
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import {Budget, Values} from "../utils/Value.sol";
|
|
5
|
+
import {Cursors} from "../Cursors.sol";
|
|
6
|
+
import {ReceivedEvent} from "../events/Received.sol";
|
|
7
|
+
import {Actions} from "../utils/Actions.sol";
|
|
8
|
+
import {NativeAsset} from "./Runtime.sol";
|
|
5
9
|
import {max128} from "../utils/Utils.sol";
|
|
6
10
|
|
|
7
11
|
/// @title Payable
|
|
8
12
|
/// @notice Abstract mixin for entrypoints that accept native value (`msg.value`).
|
|
9
13
|
/// Provides shared helpers for mutable native-value budgets.
|
|
10
|
-
abstract contract Payable {
|
|
11
|
-
/// @dev Thrown when a payable entrypoint completes with unspent native value.
|
|
12
|
-
error UnusedValue(uint remaining);
|
|
13
|
-
|
|
14
|
+
abstract contract Payable is NativeAsset, ReceivedEvent {
|
|
14
15
|
/// @notice Open a native-value budget from the current call's `msg.value`.
|
|
15
16
|
/// @return Budget initialized with the full `msg.value`.
|
|
16
17
|
function openValue() internal view returns (Budget memory) {
|
|
@@ -33,21 +34,20 @@ abstract contract Payable {
|
|
|
33
34
|
Values.use(budget, value);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
/// @notice
|
|
37
|
-
/// @
|
|
38
|
-
/// @param budget Mutable
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
/// @notice Drain a native-value budget into a credit-only TRANSACTION block.
|
|
38
|
+
/// @dev Emits `Received` with `Actions.Refund` when a transaction is created.
|
|
39
|
+
/// @param budget Mutable budget whose remaining value is drained.
|
|
40
|
+
/// @param account Destination account to credit with the remaining native value.
|
|
41
|
+
/// @return transaction Encoded TRANSACTION block, or empty bytes when the budget is empty.
|
|
42
|
+
function closeValue(
|
|
43
|
+
Budget memory budget,
|
|
44
|
+
bytes32 account
|
|
45
|
+
) internal returns (bytes memory transaction) {
|
|
46
|
+
uint amount = Values.drain(budget);
|
|
47
|
+
if (amount == 0) return "";
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/// @param account Account identifier for the current invocation.
|
|
48
|
-
/// @param value Drained native value amount to settle, in wei.
|
|
49
|
-
function settleValue(bytes32 account, uint value) internal virtual {
|
|
50
|
-
account;
|
|
51
|
-
revert UnusedValue(value);
|
|
49
|
+
transaction = Cursors.toTransactionBlock(bytes32(0), account, nativeAsset, amount);
|
|
50
|
+
emit Received(account, nativeAsset, amount, Actions.Refund, 0);
|
|
52
51
|
}
|
|
52
|
+
|
|
53
53
|
}
|
package/core/Pipeline.sol
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {Cursors, Cur} from "../Cursors.sol";
|
|
4
|
+
import {Cursors, Cur, Readers, Reader} from "../Cursors.sol";
|
|
5
5
|
import {Payable} from "./Payable.sol";
|
|
6
|
+
import {Settlement} from "./Settlement.sol";
|
|
6
7
|
import {Budget} from "../utils/Value.sol";
|
|
7
8
|
|
|
8
9
|
using Cursors for Cur;
|
|
10
|
+
using Readers for Reader;
|
|
9
11
|
|
|
10
12
|
/// @title Pipeline
|
|
11
13
|
/// @notice Core pipeline functionality shared by higher-level surfaces.
|
|
12
|
-
abstract contract Pipeline is Payable {
|
|
14
|
+
abstract contract Pipeline is Payable, Settlement {
|
|
13
15
|
/// @dev Thrown when the pipeline finishes with non-empty threaded state.
|
|
14
16
|
error UnexpectedState();
|
|
15
17
|
|
|
16
18
|
/// @notice Override to dispatch one piped step.
|
|
17
|
-
/// Called once per STEP block. The returned
|
|
18
|
-
/// the next step, and the final returned state must be empty.
|
|
19
|
+
/// Called once per STEP block. The returned state becomes the state passed to
|
|
20
|
+
/// the next step, and the final returned state must be empty. Returned
|
|
21
|
+
/// transactions are decoded and passed individually to `settle` before the next step runs.
|
|
19
22
|
/// @param target Node ID to invoke or handle.
|
|
20
23
|
/// @param account Account identifier for the piped context.
|
|
21
24
|
/// @param state Current threaded state block stream.
|
|
22
25
|
/// @param request Step request block stream.
|
|
23
26
|
/// @param value Native EVM value assigned to this step.
|
|
24
|
-
/// @return Updated state block stream for the next step.
|
|
27
|
+
/// @return nextState Updated state block stream for the next step.
|
|
28
|
+
/// @return transactions Transaction block stream produced by the command.
|
|
25
29
|
function dispatch(
|
|
26
30
|
uint target,
|
|
27
31
|
bytes32 account,
|
|
28
32
|
bytes memory state,
|
|
29
33
|
bytes calldata request,
|
|
30
34
|
uint128 value
|
|
31
|
-
) internal virtual returns (bytes memory);
|
|
35
|
+
) internal virtual returns (bytes memory nextState, bytes memory transactions);
|
|
32
36
|
|
|
33
37
|
/// @notice Execute a STEP block stream through the pipeline.
|
|
34
38
|
/// @dev Reverts with `UnexpectedState` if the final threaded state is non-empty.
|
|
@@ -37,20 +41,19 @@ abstract contract Pipeline is Payable {
|
|
|
37
41
|
/// @param state Initial state block stream passed to the first step.
|
|
38
42
|
/// @param steps STEP block stream to execute.
|
|
39
43
|
/// @param budget Mutable native-value budget shared across all steps.
|
|
40
|
-
function pipe(
|
|
41
|
-
bytes32 account,
|
|
42
|
-
bytes memory state,
|
|
43
|
-
bytes calldata steps,
|
|
44
|
-
Budget memory budget
|
|
45
|
-
) internal {
|
|
44
|
+
function pipe(bytes32 account, bytes memory state, bytes calldata steps, Budget memory budget) internal {
|
|
46
45
|
(Cur memory input, ) = Cursors.init(steps, 1);
|
|
47
46
|
|
|
48
47
|
while (input.i < input.len) {
|
|
49
48
|
(uint target, uint resources, bytes calldata request) = input.unpackStep();
|
|
50
|
-
|
|
49
|
+
Reader memory txs;
|
|
50
|
+
(state, txs.source) = dispatch(target, account, state, request, useValue(budget, resources));
|
|
51
|
+
while (txs.more()) {
|
|
52
|
+
(bytes32 from, bytes32 to, bytes32 asset, uint amount) = txs.unpackTransaction();
|
|
53
|
+
settle(from, to, asset, amount);
|
|
54
|
+
}
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
if (state.length != 0) revert UnexpectedState();
|
|
54
|
-
input.complete();
|
|
55
58
|
}
|
|
56
59
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
/// @title DebitAccountHook
|
|
5
|
+
/// @notice Hook for debiting externally managed account funds.
|
|
6
|
+
abstract contract DebitAccountHook {
|
|
7
|
+
/// @notice Override to debit externally managed funds from `account`.
|
|
8
|
+
/// @param account Source account identifier.
|
|
9
|
+
/// @param asset Asset identifier.
|
|
10
|
+
/// @param amount Amount to debit.
|
|
11
|
+
function debitAccount(bytes32 account, bytes32 asset, uint amount) internal virtual;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/// @title CreditAccountHook
|
|
15
|
+
/// @notice Hook for crediting externally managed account funds.
|
|
16
|
+
abstract contract CreditAccountHook {
|
|
17
|
+
/// @notice Override to credit externally managed funds to `account`.
|
|
18
|
+
/// @param account Destination account identifier.
|
|
19
|
+
/// @param asset Asset identifier.
|
|
20
|
+
/// @param amount Amount to credit.
|
|
21
|
+
function creditAccount(bytes32 account, bytes32 asset, uint amount) internal virtual;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// @title Settlement
|
|
25
|
+
/// @notice Settles decoded transactions through debit and credit account hooks.
|
|
26
|
+
abstract contract Settlement is DebitAccountHook, CreditAccountHook {
|
|
27
|
+
/// @notice Settle one transaction by debiting its source and crediting its destination.
|
|
28
|
+
/// Returns without calling either hook when `amount` is zero and skips either
|
|
29
|
+
/// operation when the corresponding account is zero.
|
|
30
|
+
/// @param from Source account identifier.
|
|
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 {
|
|
35
|
+
if (amount == 0) return;
|
|
36
|
+
if (from != 0) debitAccount(from, asset, amount);
|
|
37
|
+
if (to != 0) creditAccount(to, asset, amount);
|
|
38
|
+
}
|
|
39
|
+
}
|
package/docs/Schema.md
CHANGED
|
@@ -33,7 +33,7 @@ used. A host can publish the meaning of a custom key with:
|
|
|
33
33
|
event Schema(uint indexed host, bytes4 key, string schema, bytes32 name);
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
For example, a host-specific payment block can use
|
|
36
|
+
For example, a host-specific payment block can use a small literal, the command
|
|
37
37
|
selector, or any other chosen `bytes4` value as long as that key is not
|
|
38
38
|
overloaded in the relevant host/schema context.
|
|
39
39
|
|
|
@@ -65,16 +65,19 @@ A schema body is a comma-separated list of items. Order is significant.
|
|
|
65
65
|
|
|
66
66
|
## Payload Layout
|
|
67
67
|
|
|
68
|
-
A block payload
|
|
69
|
-
|
|
68
|
+
A block payload encodes schema items in declaration order. Fixed fields are
|
|
69
|
+
packed inline, and zero or more child blocks are embedded directly at their
|
|
70
|
+
declared positions. Because every child block carries its own header and payload
|
|
71
|
+
length, fixed fields may appear before, after, or between child blocks.
|
|
70
72
|
|
|
71
73
|
```txt
|
|
72
74
|
{ uint target, uint resources, #bytes as payload }
|
|
73
75
|
{ bytes32 account, #bytes as state, #bytes as request }
|
|
76
|
+
{ bytes4 key, #string as body, bytes32 name }
|
|
77
|
+
{ #bytes as left, uint op, #bytes as right }
|
|
74
78
|
```
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
child-block tail.
|
|
80
|
+
There is no wrapper around embedded child blocks.
|
|
78
81
|
|
|
79
82
|
Raw dynamic bytes are represented with the reserved `#bytes` child block. Use an
|
|
80
83
|
alias to give those bytes a presentation name:
|
|
@@ -293,19 +296,21 @@ invalid in any path segment.
|
|
|
293
296
|
## Reserved Blocks
|
|
294
297
|
|
|
295
298
|
- `#bytes`: raw dynamic bytes, written without a body
|
|
299
|
+
- `#string`: UTF-8 string bytes, written without a body
|
|
296
300
|
- `#list`: generic list wrapper emitted by `many`
|
|
297
301
|
|
|
298
302
|
Custom input shapes should define their own context-local block key and publish
|
|
299
|
-
that key with a `Schema` event
|
|
303
|
+
that key with a `Schema` event. Endpoint contracts can use `schema(...)` for
|
|
304
|
+
that publication:
|
|
300
305
|
|
|
301
306
|
```solidity
|
|
302
|
-
bytes4
|
|
303
|
-
emit Schema(host, Input, "{ bytes32 asset, uint amount }", bytes32("payment"));
|
|
307
|
+
bytes4 input = schema(1, "{ bytes32 asset, uint amount }");
|
|
304
308
|
```
|
|
305
309
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
310
|
+
Use different numeric keys when a host needs more than one local block key. The
|
|
311
|
+
key can also be a selector or any other `bytes4` value that is unique in the
|
|
312
|
+
context where it is used. The alias names the block; the schema string describes
|
|
313
|
+
only the payload body.
|
|
309
314
|
|
|
310
315
|
## Standard Blocks
|
|
311
316
|
|
|
@@ -320,6 +325,7 @@ step { uint target, uint resources, #bytes as request }
|
|
|
320
325
|
context { bytes32 account, #bytes as state, #bytes as request }
|
|
321
326
|
recover { uint handler, uint resources, bytes32 key, #bytes as witness }
|
|
322
327
|
auth { uint cid, uint deadline, #bytes as proof }
|
|
328
|
+
schema { bytes4 key, #string as body, bytes32 name }
|
|
323
329
|
```
|
|
324
330
|
|
|
325
331
|
`Keys.sol` contains the corresponding standard runtime keys.
|
package/events/Introduction.sol
CHANGED
|
@@ -5,11 +5,12 @@ import { EventEmitter } from "./Emitter.sol";
|
|
|
5
5
|
|
|
6
6
|
/// @notice Emitted when a host introduces itself to another host.
|
|
7
7
|
abstract contract IntroductionEvent is EventEmitter {
|
|
8
|
-
string private constant ABI = "event Introduction(uint indexed host, uint blocknum)";
|
|
8
|
+
string private constant ABI = "event Introduction(uint indexed host, uint peer, uint blocknum)";
|
|
9
9
|
|
|
10
|
-
/// @param host Host node ID
|
|
10
|
+
/// @param host Host node ID receiving the introduction.
|
|
11
|
+
/// @param peer Host node ID of the introducing contract.
|
|
11
12
|
/// @param blocknum Block number at which the host was deployed.
|
|
12
|
-
event Introduction(uint indexed host, uint blocknum);
|
|
13
|
+
event Introduction(uint indexed host, uint peer, uint blocknum);
|
|
13
14
|
|
|
14
15
|
constructor() {
|
|
15
16
|
emit EventAbi(ABI);
|
package/package.json
CHANGED
package/ports/Credit.sol
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import { PortBase } from "./Base.sol";
|
|
5
|
-
import { CreditAccountHook } from "../
|
|
5
|
+
import { CreditAccountHook } from "../core/Settlement.sol";
|
|
6
6
|
import { Cursors, Cur, Keys } from "../Cursors.sol";
|
|
7
7
|
|
|
8
8
|
using Cursors for Cur;
|
package/ports/Debit.sol
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import { PortBase } from "./Base.sol";
|
|
5
|
-
import { DebitAccountHook } from "../
|
|
5
|
+
import { DebitAccountHook } from "../core/Settlement.sol";
|
|
6
6
|
import { Cursors, Cur, Keys } from "../Cursors.sol";
|
|
7
7
|
|
|
8
8
|
using Cursors for Cur;
|
package/ports/Settle.sol
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import { PortBase } from "./Base.sol";
|
|
5
|
-
import {
|
|
6
|
-
import { DebitAccountHook } from "../commands/Debit.sol";
|
|
5
|
+
import { Settlement } from "../core/Settlement.sol";
|
|
7
6
|
import { Cursors, Cur, Keys } from "../Cursors.sol";
|
|
8
7
|
|
|
9
8
|
using Cursors for Cur;
|
|
@@ -11,7 +10,7 @@ using Cursors for Cur;
|
|
|
11
10
|
/// @title PortSettle
|
|
12
11
|
/// @notice Port that consumes peer-supplied TRANSACTION blocks through debit and credit hooks.
|
|
13
12
|
/// Each TRANSACTION block calls `debitAccount` for `from` and `creditAccount` for `to`.
|
|
14
|
-
abstract contract PortSettle is PortBase,
|
|
13
|
+
abstract contract PortSettle is PortBase, Settlement {
|
|
15
14
|
bytes32 private immutable descriptor;
|
|
16
15
|
|
|
17
16
|
constructor() {
|
|
@@ -26,8 +25,7 @@ abstract contract PortSettle is PortBase, DebitAccountHook, CreditAccountHook {
|
|
|
26
25
|
|
|
27
26
|
while (input.i < input.len) {
|
|
28
27
|
(bytes32 from, bytes32 to, bytes32 asset, uint amount) = input.unpackTransaction();
|
|
29
|
-
|
|
30
|
-
if (to != 0) creditAccount(to, asset, amount);
|
|
28
|
+
settle(from, to, asset, amount);
|
|
31
29
|
}
|
|
32
30
|
return "";
|
|
33
31
|
}
|