@rootzero/contracts 1.12.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 +31 -5
- package/Core.sol +2 -1
- package/Cursors.sol +2 -2
- package/Endpoints.sol +4 -2
- package/README.md +37 -14
- package/blocks/Cursors.sol +129 -0
- package/blocks/Keys.sol +0 -12
- package/blocks/Writers.sol +17 -9
- package/commands/Allocate.sol +49 -0
- package/commands/Burn.sol +3 -2
- package/commands/Credit.sol +4 -11
- package/commands/Debit.sol +4 -11
- 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 +3 -2
- 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 +3 -2
- package/commands/admin/Unauthorize.sol +3 -2
- package/core/Calls.sol +4 -3
- package/core/Endpoint.sol +25 -23
- package/core/Host.sol +10 -2
- package/core/Payable.sol +19 -19
- package/core/Pipeline.sol +17 -14
- package/core/Settlement.sol +39 -0
- package/docs/Schema.md +8 -8
- 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/CHANGELOG.md
CHANGED
|
@@ -3,21 +3,47 @@
|
|
|
3
3
|
Until the protocol reaches integration-stable status, minor versions may include
|
|
4
4
|
breaking API changes. Breaking changes are called out explicitly.
|
|
5
5
|
|
|
6
|
+
## 1.13.0
|
|
7
|
+
|
|
8
|
+
### Breaking Changes
|
|
9
|
+
|
|
10
|
+
- Replaced the virtual `Pipeline.settle(bytes transactions)` stream hook with
|
|
11
|
+
decoded settlement through `Settlement`. Pipeline implementations now provide
|
|
12
|
+
`debitAccount` and `creditAccount` hooks, while the pipeline decodes each
|
|
13
|
+
returned TRANSACTION block and settles it before dispatching the next step.
|
|
14
|
+
- Moved `DebitAccountHook` and `CreditAccountHook` from their command modules to
|
|
15
|
+
`core/Settlement.sol`. They remain available from the `Core.sol` and
|
|
16
|
+
`Endpoints.sol` package entry points.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Added the memory-backed `Reader` and `Readers` block-stream API with balance
|
|
21
|
+
and transaction unpackers, bounds and block validation, and positive
|
|
22
|
+
iteration through `more()`.
|
|
23
|
+
- Added the shared `Settlement` core mixin used by pipelines and `PortSettle` to
|
|
24
|
+
debit transaction sources and credit destinations.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Unified pipeline and port transaction handling through `Settlement`,
|
|
29
|
+
including zero-account handling and zero-amount no-op settlement.
|
|
30
|
+
|
|
6
31
|
## 1.12.0
|
|
7
32
|
|
|
8
33
|
### Breaking Changes
|
|
9
34
|
|
|
10
|
-
- Removed
|
|
11
|
-
`
|
|
12
|
-
|
|
35
|
+
- Removed `Keys.Local` and replaced `EndpointBase.localSchema(...)` with the
|
|
36
|
+
explicit `EndpointBase.schema(uint32 key, string body)` helper for
|
|
37
|
+
context-local endpoint schemas.
|
|
38
|
+
- Changed `Introduction` to emit the receiving `host` and introduced `peer`:
|
|
39
|
+
`Introduction(uint indexed host, uint peer, uint blocknum)`.
|
|
13
40
|
- Replaced `isDebitAccount`, `isCreditAccount`, `isAuthorize`, and
|
|
14
41
|
`isUnauthorize` helper predicates with internal command ID fields:
|
|
15
42
|
`debitAccountId`, `creditAccountId`, `authorizeId`, and `unauthorizeId`.
|
|
16
43
|
|
|
17
44
|
### Added
|
|
18
45
|
|
|
19
|
-
- Added `
|
|
20
|
-
`EndpointBase.localSchema(...)` helpers for publishing local endpoint
|
|
46
|
+
- Added the `EndpointBase.schema(...)` helper for publishing local endpoint
|
|
21
47
|
schemas.
|
|
22
48
|
- Added the standard `#schema` block, `unpackSchema`, and an opt-in
|
|
23
49
|
`publishSchema` admin command for emitting schema claims from `#schema`
|
package/Core.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
|
-
// Aggregator: re-exports the core host, runtime, access, ledger, node-call, and validation layer.
|
|
4
|
+
// Aggregator: re-exports the core host, runtime, access, ledger, settlement, pipeline, node-call, and validation layer.
|
|
5
5
|
// Import this file to bring the full rootzero host base layer into scope.
|
|
6
6
|
|
|
7
7
|
import { AccessControl } from "./core/Access.sol";
|
|
@@ -13,6 +13,7 @@ import { CommandCalls, FailedCall, NodeCalls, PortCalls } from "./core/Calls.sol
|
|
|
13
13
|
import { EndpointBase, Lane } from "./core/Endpoint.sol";
|
|
14
14
|
import { Payable } from "./core/Payable.sol";
|
|
15
15
|
import { Pipeline } from "./core/Pipeline.sol";
|
|
16
|
+
import { CreditAccountHook, DebitAccountHook, Settlement } from "./core/Settlement.sol";
|
|
16
17
|
import { Portal } from "./core/Portal.sol";
|
|
17
18
|
import { RecoverHook } from "./commands/Recover.sol";
|
|
18
19
|
import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
|
package/Cursors.sol
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
// Aggregator: re-exports all block stream primitives (Cursors, Writers, Schema, Keys, Sizes).
|
|
4
|
+
// Aggregator: re-exports all block stream primitives (Cursors, Readers, Writers, Schema, Keys, Sizes).
|
|
5
5
|
// Import this file to get access to the full block encoding/decoding surface in one import.
|
|
6
6
|
|
|
7
7
|
import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
|
|
8
8
|
import { Forms, Sizes } from "./blocks/Schema.sol";
|
|
9
9
|
import { Keys } from "./blocks/Keys.sol";
|
|
10
10
|
import { Schemas } from "./blocks/Schema.sol";
|
|
11
|
-
import { Cursors, Cur } from "./blocks/Cursors.sol";
|
|
11
|
+
import { Cursors, Cur, Readers, Reader } from "./blocks/Cursors.sol";
|
|
12
12
|
import { Writer, Writers, Hints } from "./blocks/Writers.sol";
|
|
13
13
|
|
|
14
14
|
|
package/Endpoints.sol
CHANGED
|
@@ -9,11 +9,13 @@ import { Keys } from "./blocks/Keys.sol";
|
|
|
9
9
|
import { CommandBase, CommandContext } from "./commands/Base.sol";
|
|
10
10
|
import { EndpointBase, Lane } from "./core/Endpoint.sol";
|
|
11
11
|
import { Payable } from "./core/Payable.sol";
|
|
12
|
+
import { CreditAccountHook, DebitAccountHook } from "./core/Settlement.sol";
|
|
12
13
|
|
|
13
14
|
// Commands
|
|
15
|
+
import { Allocate, AllocateHook } from "./commands/Allocate.sol";
|
|
14
16
|
import { Burn, BurnHook } from "./commands/Burn.sol";
|
|
15
|
-
import { CreditAccount
|
|
16
|
-
import { DebitAccount
|
|
17
|
+
import { CreditAccount } from "./commands/Credit.sol";
|
|
18
|
+
import { DebitAccount } from "./commands/Debit.sol";
|
|
17
19
|
import { Deposit, DepositHook, DepositPayable, DepositPayableHook } from "./commands/Deposit.sol";
|
|
18
20
|
import { Payout, PayoutHook } from "./commands/Payout.sol";
|
|
19
21
|
import { Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook } from "./commands/Provision.sol";
|
package/README.md
CHANGED
|
@@ -121,7 +121,8 @@ const request = concat([
|
|
|
121
121
|
encodeAmountBlock(usdc, 250_000_000n),
|
|
122
122
|
encodeAmountBlock(dai, 250n * 10n ** 18n),
|
|
123
123
|
]);
|
|
124
|
-
// deposit(request) returns two #balance blocks
|
|
124
|
+
// deposit(request) returns two #balance blocks in its state output and an
|
|
125
|
+
// empty transaction output
|
|
125
126
|
```
|
|
126
127
|
|
|
127
128
|
Everything downstream keeps this shape: commands loop over request blocks,
|
|
@@ -216,6 +217,11 @@ struct CommandContext {
|
|
|
216
217
|
}
|
|
217
218
|
```
|
|
218
219
|
|
|
220
|
+
Every command returns two block streams: `state`, which is threaded into the
|
|
221
|
+
next pipeline step, and `transactions`, which contains `#transaction` blocks
|
|
222
|
+
for the pipeline host to settle outside the state lane. Either stream may be
|
|
223
|
+
empty.
|
|
224
|
+
|
|
219
225
|
The input carries instructions; the state carries live value. While a
|
|
220
226
|
sequence of commands executes, `#balance` and `#custody` blocks in the state
|
|
221
227
|
are the funds being moved — produced by one command, consumed by the next.
|
|
@@ -224,7 +230,9 @@ The standard `Deposit` mixin shows the canonical shape — open the input,
|
|
|
224
230
|
loop the batch, call the hook, write the output run:
|
|
225
231
|
|
|
226
232
|
```solidity
|
|
227
|
-
function deposit(
|
|
233
|
+
function deposit(
|
|
234
|
+
CommandContext calldata c
|
|
235
|
+
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
228
236
|
(Cur memory input, uint outputs) = openInput(c.input, descriptor);
|
|
229
237
|
Writer memory output = Writers.allocBalances(outputs);
|
|
230
238
|
|
|
@@ -234,7 +242,7 @@ function deposit(CommandContext calldata c) external onlyCommand returns (bytes
|
|
|
234
242
|
output.appendBalance(asset, amount);
|
|
235
243
|
}
|
|
236
244
|
|
|
237
|
-
return output.finish();
|
|
245
|
+
return (output.finish(), "");
|
|
238
246
|
}
|
|
239
247
|
```
|
|
240
248
|
|
|
@@ -250,8 +258,10 @@ abstract contract MyCommand is CommandBase {
|
|
|
250
258
|
(, descriptor) = command("myCommand", Keys.Empty, Keys.Amount, Keys.Balance, 0, false, false);
|
|
251
259
|
}
|
|
252
260
|
|
|
253
|
-
function myCommand(
|
|
254
|
-
|
|
261
|
+
function myCommand(
|
|
262
|
+
CommandContext calldata c
|
|
263
|
+
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
264
|
+
// parse c.input, loop, return the output state run and any transactions
|
|
255
265
|
}
|
|
256
266
|
}
|
|
257
267
|
```
|
|
@@ -259,8 +269,9 @@ abstract contract MyCommand is CommandBase {
|
|
|
259
269
|
The standard commands cover the common ledger movements: `deposit` and
|
|
260
270
|
`depositPayable` (external funds in), `withdraw` and `burn` (funds out),
|
|
261
271
|
`debitAccount` and `creditAccount` (internal movements), `payout` (deliver
|
|
262
|
-
state to other accounts), `
|
|
263
|
-
`
|
|
272
|
+
state to other accounts), `allocate` (turn balance state into custody),
|
|
273
|
+
`provision` (provision custody from an external allocation), and `relayPayable`
|
|
274
|
+
(hand a pipeline to another portal).
|
|
264
275
|
|
|
265
276
|
## Pipelines
|
|
266
277
|
|
|
@@ -272,14 +283,26 @@ step { uint target, uint resources, #bytes as request }
|
|
|
272
283
|
```
|
|
273
284
|
|
|
274
285
|
Each step names a target command, the resources it may spend, and its request.
|
|
275
|
-
The state threads
|
|
276
|
-
|
|
277
|
-
|
|
286
|
+
The returned state threads into the next command and the final state must be
|
|
287
|
+
empty. Returned transactions do not enter the state lane; the pipeline passes
|
|
288
|
+
each decoded transaction to the shared settlement implementation before
|
|
289
|
+
running the next step. This is the core of `Pipeline.pipe`:
|
|
278
290
|
|
|
279
291
|
```solidity
|
|
280
292
|
while (input.i < input.len) {
|
|
281
293
|
(uint target, uint resources, bytes calldata request) = input.unpackStep();
|
|
282
|
-
|
|
294
|
+
Reader memory transactions;
|
|
295
|
+
(state, transactions.source) = dispatch(
|
|
296
|
+
target,
|
|
297
|
+
account,
|
|
298
|
+
state,
|
|
299
|
+
request,
|
|
300
|
+
useValue(budget, resources)
|
|
301
|
+
);
|
|
302
|
+
while (transactions.more()) {
|
|
303
|
+
(bytes32 from, bytes32 to, bytes32 asset, uint amount) = transactions.unpackTransaction();
|
|
304
|
+
settle(from, to, asset, amount);
|
|
305
|
+
}
|
|
283
306
|
}
|
|
284
307
|
if (state.length != 0) revert UnexpectedState();
|
|
285
308
|
```
|
|
@@ -353,11 +376,11 @@ names, access sets, balances — from logs alone, with no artifact files.
|
|
|
353
376
|
Import from the package entry points rather than deep paths:
|
|
354
377
|
|
|
355
378
|
- `@rootzero/contracts/Core.sol` — `Host`, access control, `Balances`,
|
|
356
|
-
`Pipeline`, `Portal`, validator
|
|
379
|
+
`Settlement`, `Pipeline`, `Portal`, validator
|
|
357
380
|
- `@rootzero/contracts/Endpoints.sol` — command, admin, port, guard, and query
|
|
358
381
|
mixins and their hooks
|
|
359
|
-
- `@rootzero/contracts/Cursors.sol` — `Cur
|
|
360
|
-
`Keys`
|
|
382
|
+
- `@rootzero/contracts/Cursors.sol` — calldata `Cur`/`Cursors`, memory
|
|
383
|
+
`Reader`/`Readers`, `Writers`, `Schemas`, `Keys`
|
|
361
384
|
- `@rootzero/contracts/Utils.sol` — `Ids`, `Nodes`, `Assets`, `Accounts`,
|
|
362
385
|
layout and value helpers
|
|
363
386
|
- `@rootzero/contracts/Events.sol` — protocol event contracts
|
package/blocks/Cursors.sol
CHANGED
|
@@ -17,7 +17,109 @@ struct Cur {
|
|
|
17
17
|
uint len;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/// @notice Mutable reader over a block stream stored in memory.
|
|
21
|
+
/// All positions (`i`) are byte offsets relative to the start of `source`.
|
|
22
|
+
struct Reader {
|
|
23
|
+
/// @dev Current read position, relative to the source start.
|
|
24
|
+
uint i;
|
|
25
|
+
/// @dev Memory bytes containing the complete source region.
|
|
26
|
+
bytes source;
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
using Cursors for Cur;
|
|
30
|
+
using Readers for Reader;
|
|
31
|
+
|
|
32
|
+
/// @title Readers
|
|
33
|
+
/// @notice Memory block stream parser for the rootzero protocol.
|
|
34
|
+
/// A `Reader` advances through an existing `bytes memory` source without copying its contents.
|
|
35
|
+
/// Blocks are encoded as `[bytes4 key][bytes4 payloadLen][payload]`.
|
|
36
|
+
library Readers {
|
|
37
|
+
/// @dev The current block has a truncated header or payload, an unexpected key,
|
|
38
|
+
/// or a payload size outside the accepted range.
|
|
39
|
+
error InvalidBlock();
|
|
40
|
+
|
|
41
|
+
/// @notice Create a reader backed by a memory byte array.
|
|
42
|
+
/// @param source Memory bytes containing the block stream.
|
|
43
|
+
/// @return cur Reader positioned at the beginning of `source`.
|
|
44
|
+
function open(bytes memory source) internal pure returns (Reader memory cur) {
|
|
45
|
+
cur.source = source;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// @notice Return whether the reader has consumed its entire source.
|
|
49
|
+
/// @param cur Reader whose position should be checked.
|
|
50
|
+
/// @return Whether `cur.i` equals the source length.
|
|
51
|
+
function done(Reader memory cur) internal pure returns (bool) {
|
|
52
|
+
return cur.i == cur.source.length;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// @notice Return whether the reader has bytes left to consume.
|
|
56
|
+
/// @param cur Reader whose position should be checked.
|
|
57
|
+
/// @return Whether `cur.i` differs from the source length.
|
|
58
|
+
function more(Reader memory cur) internal pure returns (bool) {
|
|
59
|
+
return cur.i != cur.source.length;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// @notice Validate and consume the current block, advancing `cur.i` past it.
|
|
63
|
+
/// @param cur Reader to advance.
|
|
64
|
+
/// @param key Expected block key.
|
|
65
|
+
/// @param min Minimum payload length.
|
|
66
|
+
/// @param max Maximum payload length; zero means unbounded.
|
|
67
|
+
/// @return abs Absolute memory address of the payload start.
|
|
68
|
+
function consume(
|
|
69
|
+
Reader memory cur,
|
|
70
|
+
bytes4 key,
|
|
71
|
+
uint min,
|
|
72
|
+
uint max
|
|
73
|
+
) internal pure returns (uint abs) {
|
|
74
|
+
bytes memory source = cur.source;
|
|
75
|
+
uint i = cur.i;
|
|
76
|
+
|
|
77
|
+
if (i > source.length || source.length - i < Sizes.Header) revert InvalidBlock();
|
|
78
|
+
|
|
79
|
+
bytes4 current;
|
|
80
|
+
uint len;
|
|
81
|
+
assembly ("memory-safe") {
|
|
82
|
+
let header := mload(add(add(source, 0x20), i))
|
|
83
|
+
current := header
|
|
84
|
+
len := and(shr(192, header), 0xffffffff)
|
|
85
|
+
abs := add(add(source, 0x28), i)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (current != key || len < min || (max != 0 && len > max)) revert InvalidBlock();
|
|
89
|
+
if (len > source.length - i - Sizes.Header) revert InvalidBlock();
|
|
90
|
+
cur.i = i + Sizes.Header + len;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// @notice Consume a BALANCE block and return its fields.
|
|
94
|
+
/// @param cur Reader; advanced past the block.
|
|
95
|
+
/// @return asset Asset identifier.
|
|
96
|
+
/// @return amount Token amount.
|
|
97
|
+
function unpackBalance(Reader memory cur) internal pure returns (bytes32 asset, uint amount) {
|
|
98
|
+
uint abs = consume(cur, Keys.Balance, 64, 64);
|
|
99
|
+
assembly ("memory-safe") {
|
|
100
|
+
asset := mload(abs)
|
|
101
|
+
amount := mload(add(abs, 0x20))
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// @notice Consume a TRANSACTION block and return its fields.
|
|
106
|
+
/// @param cur Reader; advanced past the block.
|
|
107
|
+
/// @return from Source account identifier.
|
|
108
|
+
/// @return to Destination account identifier.
|
|
109
|
+
/// @return asset Asset identifier.
|
|
110
|
+
/// @return amount Token amount.
|
|
111
|
+
function unpackTransaction(
|
|
112
|
+
Reader memory cur
|
|
113
|
+
) internal pure returns (bytes32 from, bytes32 to, bytes32 asset, uint amount) {
|
|
114
|
+
uint abs = consume(cur, Keys.Transaction, 128, 128);
|
|
115
|
+
assembly ("memory-safe") {
|
|
116
|
+
from := mload(abs)
|
|
117
|
+
to := mload(add(abs, 0x20))
|
|
118
|
+
asset := mload(add(abs, 0x40))
|
|
119
|
+
amount := mload(add(abs, 0x60))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
21
123
|
|
|
22
124
|
/// @title Cursors
|
|
23
125
|
/// @notice Calldata block stream parser for the rootzero protocol.
|
|
@@ -493,6 +595,21 @@ library Cursors {
|
|
|
493
595
|
return createBlock96(Keys.Custody, bytes32(host), asset, bytes32(amount));
|
|
494
596
|
}
|
|
495
597
|
|
|
598
|
+
/// @notice Encode a TRANSACTION block.
|
|
599
|
+
/// @param from Source account identifier.
|
|
600
|
+
/// @param to Destination account identifier.
|
|
601
|
+
/// @param asset Asset identifier.
|
|
602
|
+
/// @param amount Transfer amount.
|
|
603
|
+
/// @return Encoded TRANSACTION block bytes.
|
|
604
|
+
function toTransactionBlock(
|
|
605
|
+
bytes32 from,
|
|
606
|
+
bytes32 to,
|
|
607
|
+
bytes32 asset,
|
|
608
|
+
uint amount
|
|
609
|
+
) internal pure returns (bytes memory) {
|
|
610
|
+
return createBlock128(Keys.Transaction, from, to, asset, bytes32(amount));
|
|
611
|
+
}
|
|
612
|
+
|
|
496
613
|
/// @notice Encode a STEP block.
|
|
497
614
|
/// @param target Command target identifier.
|
|
498
615
|
/// @param resources Packed resources assigned to the step.
|
|
@@ -1339,6 +1456,18 @@ library Cursors {
|
|
|
1339
1456
|
// Transform helpers
|
|
1340
1457
|
// -------------------------------------------------------------------------
|
|
1341
1458
|
|
|
1459
|
+
/// @notice Consume a BALANCE block and scope its amount to a host.
|
|
1460
|
+
/// @param cur Cursor; advanced past the BALANCE block.
|
|
1461
|
+
/// @param host Host node ID to attach to the decoded balance.
|
|
1462
|
+
/// @return value Host-scoped balance amount.
|
|
1463
|
+
function unpackBalanceForHost(
|
|
1464
|
+
Cur memory cur,
|
|
1465
|
+
uint host
|
|
1466
|
+
) internal pure returns (HostAmount memory value) {
|
|
1467
|
+
value.host = host;
|
|
1468
|
+
(value.asset, value.amount) = cur.unpackBalance();
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1342
1471
|
/// @notice Consume a RELAY block and encode its destination context payload.
|
|
1343
1472
|
/// @param cur Cursor; advanced past the RELAY block.
|
|
1344
1473
|
/// @param account Account identifier to embed in the destination context.
|
package/blocks/Keys.sol
CHANGED
|
@@ -7,22 +7,10 @@ pragma solidity ^0.8.33;
|
|
|
7
7
|
/// Custom block keys only need to be unique in the context where they are used;
|
|
8
8
|
/// hosts may publish custom key meanings with the `Schema` event.
|
|
9
9
|
library Keys {
|
|
10
|
-
/// @notice Create a context-local block key.
|
|
11
|
-
/// @dev Local keys are opaque tags for host- or endpoint-specific schemas.
|
|
12
|
-
/// The caller is responsible for choosing values that are unique in the
|
|
13
|
-
/// context where they are used and publishing their meaning with `Schema`.
|
|
14
|
-
/// @param value Opaque local key value.
|
|
15
|
-
/// @return Context-local block key.
|
|
16
|
-
function local(uint32 value) internal pure returns (bytes4) {
|
|
17
|
-
return bytes4(value);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
10
|
/// @dev Empty / unset key.
|
|
21
11
|
bytes4 constant Empty = bytes4(0);
|
|
22
12
|
/// @dev Wildcard key used in discovery when any block stream is accepted.
|
|
23
13
|
bytes4 constant Any = 0xffffffff;
|
|
24
|
-
/// @dev Default context-local block key for hosts/endpoints that need one custom schema.
|
|
25
|
-
bytes4 constant Local = bytes4(uint32(1));
|
|
26
14
|
/// @dev Input amount - (bytes32 asset, uint amount)
|
|
27
15
|
bytes4 constant Amount = bytes4(keccak256("#amount"));
|
|
28
16
|
/// @dev Ledger balance - (bytes32 asset, uint amount)
|
package/blocks/Writers.sol
CHANGED
|
@@ -993,19 +993,27 @@ library Writers {
|
|
|
993
993
|
appendCustody(writer, value.host, value.asset, value.amount);
|
|
994
994
|
}
|
|
995
995
|
|
|
996
|
+
/// @notice Append a TRANSACTION block using separate field values.
|
|
997
|
+
/// @param writer Destination writer; `i` is advanced by `Sizes.Transaction`.
|
|
998
|
+
/// @param from Source account identifier.
|
|
999
|
+
/// @param to Destination account identifier.
|
|
1000
|
+
/// @param asset Asset identifier.
|
|
1001
|
+
/// @param amount Transfer amount.
|
|
1002
|
+
function appendTransaction(
|
|
1003
|
+
Writer memory writer,
|
|
1004
|
+
bytes32 from,
|
|
1005
|
+
bytes32 to,
|
|
1006
|
+
bytes32 asset,
|
|
1007
|
+
uint amount
|
|
1008
|
+
) internal pure {
|
|
1009
|
+
appendBlock128(writer, Keys.Transaction, from, to, asset, bytes32(amount), 32);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
996
1012
|
/// @notice Append a TRANSACTION block from a struct.
|
|
997
1013
|
/// @param writer Destination writer; `i` is advanced by `Sizes.Transaction`.
|
|
998
1014
|
/// @param value Transfer record fields to encode.
|
|
999
1015
|
function appendTransaction(Writer memory writer, Tx memory value) internal pure {
|
|
1000
|
-
|
|
1001
|
-
writer,
|
|
1002
|
-
Keys.Transaction,
|
|
1003
|
-
bytes32(value.from),
|
|
1004
|
-
bytes32(value.to),
|
|
1005
|
-
value.asset,
|
|
1006
|
-
bytes32(value.amount),
|
|
1007
|
-
32
|
|
1008
|
-
);
|
|
1016
|
+
appendTransaction(writer, value.from, value.to, value.asset, value.amount);
|
|
1009
1017
|
}
|
|
1010
1018
|
|
|
1011
1019
|
// -------------------------------------------------------------------------
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
|
+
pragma solidity ^0.8.33;
|
|
3
|
+
|
|
4
|
+
import {CommandContext, CommandBase, Keys} from "./Base.sol";
|
|
5
|
+
import {HostAmount, Cursors, Cur, Writer, Writers} from "../Cursors.sol";
|
|
6
|
+
|
|
7
|
+
using Cursors for Cur;
|
|
8
|
+
using Writers for Writer;
|
|
9
|
+
|
|
10
|
+
/// @notice Shared allocation hook used by `Allocate`.
|
|
11
|
+
abstract contract AllocateHook {
|
|
12
|
+
/// @notice Override to allocate a live balance into custody on a host.
|
|
13
|
+
/// Called once per paired BALANCE state block and NODE request block.
|
|
14
|
+
/// Implementations should perform only the custody side effect; output
|
|
15
|
+
/// blocks are written by the caller.
|
|
16
|
+
/// @param account Caller's account identifier.
|
|
17
|
+
/// @param custody Host-scoped amount to allocate into custody.
|
|
18
|
+
function allocate(bytes32 account, HostAmount memory custody) internal virtual;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @title Allocate
|
|
22
|
+
/// @notice Command that allocates BALANCE state to custody on requested hosts.
|
|
23
|
+
/// Each BALANCE state block is paired with one NODE request block at the same
|
|
24
|
+
/// position; the output is a matching CUSTODY state stream.
|
|
25
|
+
abstract contract Allocate is CommandBase, AllocateHook {
|
|
26
|
+
bytes32 private immutable descriptor;
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
(, descriptor) = command("allocate", Keys.Balance, Keys.Node, Keys.Custody, 0, false, false);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// @notice Allocate BALANCE state blocks to matching NODE request blocks.
|
|
33
|
+
/// @param c Command context; `c.state` must contain BALANCE blocks and
|
|
34
|
+
/// `c.input` must contain the same number of NODE blocks.
|
|
35
|
+
/// @return CUSTODY block stream matching the allocated balances.
|
|
36
|
+
/// @return Empty transaction stream.
|
|
37
|
+
function allocate(CommandContext calldata c) external onlyCommand returns (bytes memory, bytes memory) {
|
|
38
|
+
(Cur memory input, Cur memory state, uint outputs) = openCommand(c, descriptor);
|
|
39
|
+
Writer memory output = Writers.allocCustodies(outputs);
|
|
40
|
+
|
|
41
|
+
while (state.i < state.len) {
|
|
42
|
+
HostAmount memory custody = state.unpackBalanceForHost(input.unpackNode());
|
|
43
|
+
allocate(c.account, custody);
|
|
44
|
+
output.appendCustody(custody);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return (output.finish(), "");
|
|
48
|
+
}
|
|
49
|
+
}
|
package/commands/Burn.sol
CHANGED
|
@@ -28,14 +28,15 @@ abstract contract Burn is CommandBase, BurnHook {
|
|
|
28
28
|
/// @notice Burn each BALANCE block from the command state.
|
|
29
29
|
/// @param c Command context; `c.state` must contain BALANCE blocks.
|
|
30
30
|
/// @return Empty output state.
|
|
31
|
-
|
|
31
|
+
/// @return Empty transaction stream.
|
|
32
|
+
function burn(CommandContext calldata c) external onlyCommand returns (bytes memory, bytes memory) {
|
|
32
33
|
(Cur memory state, ) = openState(c.state, descriptor);
|
|
33
34
|
|
|
34
35
|
while (state.i < state.len) {
|
|
35
36
|
(bytes32 asset, uint amount) = state.unpackBalance();
|
|
36
37
|
burn(c.account, asset, amount);
|
|
37
38
|
}
|
|
38
|
-
return "";
|
|
39
|
+
return ("", "");
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
|
package/commands/Credit.sol
CHANGED
|
@@ -3,18 +3,10 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import { CommandBase, CommandContext, Keys } from "./Base.sol";
|
|
5
5
|
import { Cursors, Cur } from "../Cursors.sol";
|
|
6
|
+
import { CreditAccountHook } from "../core/Settlement.sol";
|
|
6
7
|
|
|
7
8
|
using Cursors for Cur;
|
|
8
9
|
|
|
9
|
-
abstract contract CreditAccountHook {
|
|
10
|
-
/// @notice Override to credit externally managed funds to `account`.
|
|
11
|
-
/// Called once per BALANCE block in state.
|
|
12
|
-
/// @param account Destination account identifier.
|
|
13
|
-
/// @param asset Asset identifier.
|
|
14
|
-
/// @param amount Amount to credit.
|
|
15
|
-
function creditAccount(bytes32 account, bytes32 asset, uint amount) internal virtual;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
10
|
/// @title CreditAccount
|
|
19
11
|
/// @notice Command that delivers BALANCE state blocks to an account via a virtual hook.
|
|
20
12
|
/// Use for internally recording credits that have already been settled externally.
|
|
@@ -29,16 +21,17 @@ abstract contract CreditAccount is CommandBase, CreditAccountHook {
|
|
|
29
21
|
/// @notice Credit each BALANCE block from the command state to the command account.
|
|
30
22
|
/// @param c Command context; `c.state` must contain BALANCE blocks.
|
|
31
23
|
/// @return Empty output state.
|
|
24
|
+
/// @return Empty transaction stream.
|
|
32
25
|
function creditAccount(
|
|
33
26
|
CommandContext calldata c
|
|
34
|
-
) external onlyCommand returns (bytes memory) {
|
|
27
|
+
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
35
28
|
(Cur memory state, ) = openState(c.state, descriptor);
|
|
36
29
|
|
|
37
30
|
while (state.i < state.len) {
|
|
38
31
|
(bytes32 asset, uint amount) = state.unpackBalance();
|
|
39
32
|
creditAccount(c.account, asset, amount);
|
|
40
33
|
}
|
|
41
|
-
return "";
|
|
34
|
+
return ("", "");
|
|
42
35
|
}
|
|
43
36
|
}
|
|
44
37
|
|
package/commands/Debit.sol
CHANGED
|
@@ -3,19 +3,11 @@ pragma solidity ^0.8.33;
|
|
|
3
3
|
|
|
4
4
|
import { CommandContext, CommandBase, Keys } from "./Base.sol";
|
|
5
5
|
import { Cursors, Cur, Writer, Writers } from "../Cursors.sol";
|
|
6
|
+
import { DebitAccountHook } from "../core/Settlement.sol";
|
|
6
7
|
|
|
7
8
|
using Cursors for Cur;
|
|
8
9
|
using Writers for Writer;
|
|
9
10
|
|
|
10
|
-
abstract contract DebitAccountHook {
|
|
11
|
-
/// @notice Override to debit externally managed funds from `account`.
|
|
12
|
-
/// Called once per AMOUNT block before a matching BALANCE is emitted.
|
|
13
|
-
/// @param account Source account identifier.
|
|
14
|
-
/// @param asset Asset identifier.
|
|
15
|
-
/// @param amount Amount to debit.
|
|
16
|
-
function debitAccount(bytes32 account, bytes32 asset, uint amount) internal virtual;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
/// @title DebitAccount
|
|
20
12
|
/// @notice Command that deducts AMOUNT blocks from an account and emits matching BALANCE state.
|
|
21
13
|
/// Use for internally recording debits. The virtual `debitAccount` hook is called once per
|
|
@@ -47,10 +39,11 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
|
|
|
47
39
|
/// @notice Debit AMOUNT request blocks from the command account and output matching BALANCE blocks.
|
|
48
40
|
/// @param c Command context; `c.input` must contain AMOUNT blocks.
|
|
49
41
|
/// @return BALANCE block stream matching the debited amounts.
|
|
42
|
+
/// @return Empty transaction stream.
|
|
50
43
|
function debitAccount(
|
|
51
44
|
CommandContext calldata c
|
|
52
|
-
) external onlyCommand returns (bytes memory) {
|
|
53
|
-
return debitAccount(c.account, c.input);
|
|
45
|
+
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
46
|
+
return (debitAccount(c.account, c.input), "");
|
|
54
47
|
}
|
|
55
48
|
}
|
|
56
49
|
|
package/commands/Deposit.sol
CHANGED
|
@@ -44,9 +44,10 @@ abstract contract Deposit is CommandBase, DepositHook {
|
|
|
44
44
|
/// @notice Deposit AMOUNT request blocks into the command account and output matching BALANCE blocks.
|
|
45
45
|
/// @param c Command context; `c.input` must contain AMOUNT blocks.
|
|
46
46
|
/// @return BALANCE block stream matching the deposited amounts.
|
|
47
|
+
/// @return Empty transaction stream.
|
|
47
48
|
function deposit(
|
|
48
49
|
CommandContext calldata c
|
|
49
|
-
) external onlyCommand returns (bytes memory) {
|
|
50
|
+
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
50
51
|
(Cur memory input, uint outputs) = openInput(c.input, descriptor);
|
|
51
52
|
Writer memory output = Writers.allocBalances(outputs);
|
|
52
53
|
|
|
@@ -56,7 +57,7 @@ abstract contract Deposit is CommandBase, DepositHook {
|
|
|
56
57
|
output.appendBalance(asset, amount);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
return output.finish();
|
|
60
|
+
return (output.finish(), "");
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -73,9 +74,10 @@ abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
|
|
|
73
74
|
/// @notice Deposit AMOUNT request blocks with access to a mutable native-value budget.
|
|
74
75
|
/// @param c Command context; `c.input` must contain AMOUNT blocks.
|
|
75
76
|
/// @return BALANCE block stream matching the deposited amounts.
|
|
77
|
+
/// @return Remaining native value as a refund transaction stream.
|
|
76
78
|
function depositPayable(
|
|
77
79
|
CommandContext calldata c
|
|
78
|
-
) external payable onlyCommand returns (bytes memory) {
|
|
80
|
+
) external payable onlyCommand returns (bytes memory, bytes memory) {
|
|
79
81
|
(Cur memory input, uint outputs) = openInput(c.input, descriptor);
|
|
80
82
|
Writer memory output = Writers.allocBalances(outputs);
|
|
81
83
|
Budget memory budget = openValue();
|
|
@@ -86,8 +88,7 @@ abstract contract DepositPayable is CommandBase, Payable, DepositPayableHook {
|
|
|
86
88
|
output.appendBalance(asset, amount);
|
|
87
89
|
}
|
|
88
90
|
|
|
89
|
-
closeValue(c.account
|
|
90
|
-
return output.finish();
|
|
91
|
+
return (output.finish(), closeValue(budget, c.account));
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
|
package/commands/Payout.sol
CHANGED
|
@@ -29,13 +29,14 @@ abstract contract Payout is CommandBase, PayoutHook {
|
|
|
29
29
|
/// @notice Pay out BALANCE state blocks to matching ACCOUNT request blocks.
|
|
30
30
|
/// @param c Command context; `c.state` must contain BALANCE blocks and `c.input` matching ACCOUNT blocks.
|
|
31
31
|
/// @return Empty output state.
|
|
32
|
-
|
|
32
|
+
/// @return Empty transaction stream.
|
|
33
|
+
function payout(CommandContext calldata c) external onlyCommand returns (bytes memory, bytes memory) {
|
|
33
34
|
(Cur memory input, Cur memory state, ) = openCommand(c, descriptor);
|
|
34
35
|
|
|
35
36
|
while (state.i < state.len) {
|
|
36
37
|
(bytes32 asset, uint amount) = state.unpackBalance();
|
|
37
38
|
payout(c.account, input.unpackAccount(), asset, amount);
|
|
38
39
|
}
|
|
39
|
-
return "";
|
|
40
|
+
return ("", "");
|
|
40
41
|
}
|
|
41
42
|
}
|