@rootzero/contracts 1.15.0 → 1.16.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 +58 -0
- package/Codec.sol +1 -1
- package/Commands.sol +1 -1
- package/Core.sol +2 -2
- package/Endpoints.sol +5 -4
- package/Events.sol +0 -1
- package/README.md +82 -28
- package/codec/Blocks.sol +79 -21
- package/codec/Buffers.sol +3 -3
- package/codec/Decoders.sol +31 -10
- package/codec/Descriptors.sol +0 -1
- package/codec/Keys.sol +2 -2
- package/codec/Readers.sol +13 -0
- package/codec/Schema.sol +5 -1
- package/codec/Specs.sol +4 -2
- package/codec/Writers.sol +19 -2
- package/commands/Base.sol +6 -15
- package/commands/Burn.sol +2 -2
- package/commands/Credit.sol +35 -3
- package/commands/Debit.sol +46 -13
- 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 +77 -0
- package/commands/Withdraw.sol +2 -2
- package/commands/admin/AllowAssets.sol +2 -2
- package/commands/admin/Allowance.sol +2 -2
- 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 +13 -1
- package/docs/Schema.md +52 -2
- package/execution/Budget.sol +12 -4
- package/execution/Execution.sol +85 -11
- package/guards/Base.sol +2 -2
- 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/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,64 @@
|
|
|
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.16.0
|
|
7
|
+
|
|
8
|
+
### Breaking Changes
|
|
9
|
+
|
|
10
|
+
- Removed the unused generic `Position` event and `PositionEvent` base contract.
|
|
11
|
+
- Renamed transaction handling from settlement to posting: the transaction
|
|
12
|
+
helper is now `post(...)`, and `portSettle(bytes)` is now `portPost(bytes)`.
|
|
13
|
+
The port selector and node ID change, and its action is now `Actions.Post`
|
|
14
|
+
(`14`) instead of `Actions.Settle` (`3`). The `Settlement` convenience base
|
|
15
|
+
implements both the transaction `PostHook` and position `SettleHook`.
|
|
16
|
+
- Removed `openInput` from `EndpointBase`. Port, query, and guard bases expose
|
|
17
|
+
`openInput` through the input-only `InputEndpointBase`, while custom commands
|
|
18
|
+
must pass both state and input through `openCommand`.
|
|
19
|
+
- Removed the wildcard `Specs.Any` state type. The stateful relay is now
|
|
20
|
+
`relayBalancePayable` and accepts `BALANCE` state blocks; `relayPayable`
|
|
21
|
+
explicitly accepts empty state.
|
|
22
|
+
- Renamed the numeric `Position` fields from `assets` and `liabilities` to
|
|
23
|
+
`amount` and `debt`.
|
|
24
|
+
- Renamed `Budget.use` to `useResourceValue` and split execution spending into
|
|
25
|
+
exact `useValue` and packed-resource `useResourceValue` helpers.
|
|
26
|
+
- Renamed `RoutePayableHook.route` to `RelayPayableHook.relayTo`. Recovery hooks
|
|
27
|
+
are now `RecoverPayableHook` implementations that receive the complete
|
|
28
|
+
resource word and mutable execution budget.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Added the hostless `#position` state block for threading asset-liability pairs
|
|
33
|
+
between pipeline commands.
|
|
34
|
+
- Added the `settle` command, the position `SettleHook`, and the transaction
|
|
35
|
+
`PostHook`. The `Settlement` convenience base provides default implementations
|
|
36
|
+
of both through the debit and credit account hooks.
|
|
37
|
+
- Added `relayBalancePayable` for relaying required `BALANCE` state while
|
|
38
|
+
`relayPayable` now explicitly relays with empty state.
|
|
39
|
+
- Added memory-backed `InternalDebitAccount`, `InternalCreditAccount`, and
|
|
40
|
+
`InternalSettle` adapters for hosts that execute canonical commands directly
|
|
41
|
+
from their pipeline dispatcher.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- Documented the command state-safety invariant: every command must handle the
|
|
46
|
+
complete supplied state stream or revert, and commands with empty state lanes
|
|
47
|
+
must reject non-empty state.
|
|
48
|
+
- Endpoint decoder opening now requires the complete supplied lane to be one
|
|
49
|
+
homogeneous run of the descriptor's declared key; trailing block types are
|
|
50
|
+
rejected instead of silently left outside the decoder cursor.
|
|
51
|
+
- Block runs and cursors now retain raw block counts only. Descriptor stride
|
|
52
|
+
conversion and state/input group reconciliation happen once in execution
|
|
53
|
+
opening rather than in `Blocks` or `Cursors`.
|
|
54
|
+
- Pipeline transaction streams are posted before the next step, and position
|
|
55
|
+
state is settled separately through the scalar asset, amount, liability, and
|
|
56
|
+
debt hook.
|
|
57
|
+
|
|
58
|
+
### Upgrade Compatibility
|
|
59
|
+
|
|
60
|
+
- Command and port selectors, block schemas, and hook signatures changed in
|
|
61
|
+
this release. Deploy fresh hosts and update pipeline builders and peer
|
|
62
|
+
integrations together.
|
|
63
|
+
|
|
6
64
|
## 1.15.0
|
|
7
65
|
|
|
8
66
|
### Breaking Changes
|
package/Codec.sol
CHANGED
|
@@ -4,7 +4,7 @@ pragma solidity ^0.8.33;
|
|
|
4
4
|
// Aggregator: re-exports the complete block encoding and decoding surface.
|
|
5
5
|
// Import this file for low-level codec extensions and direct stream processing.
|
|
6
6
|
|
|
7
|
-
import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
|
|
7
|
+
import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Position, Tx } from "./core/Types.sol";
|
|
8
8
|
import { Keys } from "./codec/Keys.sol";
|
|
9
9
|
import { Sizes, Specs } from "./codec/Specs.sol";
|
|
10
10
|
import { Descriptors } from "./codec/Descriptors.sol";
|
package/Commands.sol
CHANGED
|
@@ -11,4 +11,4 @@ import {Blocks} from "./codec/Blocks.sol";
|
|
|
11
11
|
import {Sizes, Specs} from "./codec/Specs.sol";
|
|
12
12
|
import {Decoders} from "./codec/Decoders.sol";
|
|
13
13
|
import {Cursors, Cur} from "./utils/Cursors.sol";
|
|
14
|
-
import {AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx} from "./core/Types.sol";
|
|
14
|
+
import {AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Position, Tx} from "./core/Types.sol";
|
package/Core.sol
CHANGED
|
@@ -16,9 +16,9 @@ import { CommandCalls, FailedCall, NodeCalls, PortCalls, RawNodeCalls } from "./
|
|
|
16
16
|
import { EndpointBase } from "./core/Endpoint.sol";
|
|
17
17
|
import { Pipeline } from "./core/Pipeline.sol";
|
|
18
18
|
import { Budget, Budgets } from "./execution/Budget.sol";
|
|
19
|
-
import { CreditAccountHook, DebitAccountHook, Settlement } from "./core/Settlement.sol";
|
|
19
|
+
import { CreditAccountHook, DebitAccountHook, PostHook, SettleHook, Settlement } from "./core/Settlement.sol";
|
|
20
20
|
import { Portal } from "./core/Portal.sol";
|
|
21
|
-
import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Tx } from "./core/Types.sol";
|
|
21
|
+
import { AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Position, Tx } from "./core/Types.sol";
|
|
22
22
|
import { Validator } from "./core/Validator.sol";
|
|
23
23
|
|
|
24
24
|
|
package/Endpoints.sol
CHANGED
|
@@ -5,7 +5,7 @@ pragma solidity ^0.8.33;
|
|
|
5
5
|
// Import this file to inherit from the full rootzero callable host surface without managing individual paths.
|
|
6
6
|
|
|
7
7
|
// Shared endpoint hooks
|
|
8
|
-
import { CreditAccountHook, DebitAccountHook } from "./core/Settlement.sol";
|
|
8
|
+
import { CreditAccountHook, DebitAccountHook, PostHook, SettleHook } from "./core/Settlement.sol";
|
|
9
9
|
|
|
10
10
|
// Commands
|
|
11
11
|
import { Allocate, AllocateHook } from "./commands/Allocate.sol";
|
|
@@ -15,8 +15,9 @@ import { DebitAccount } from "./commands/Debit.sol";
|
|
|
15
15
|
import { Deposit, DepositHook, DepositPayable, DepositPayableHook } from "./commands/Deposit.sol";
|
|
16
16
|
import { Payout, PayoutHook } from "./commands/Payout.sol";
|
|
17
17
|
import { Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook } from "./commands/Provision.sol";
|
|
18
|
-
import {
|
|
19
|
-
import { RelayPayable,
|
|
18
|
+
import { RecoverPayable, RecoverPayableHook } from "./commands/Recover.sol";
|
|
19
|
+
import { RelayPayable, RelayBalancePayable, RelayPayableHook } from "./commands/Relay.sol";
|
|
20
|
+
import { Settle } from "./commands/Settle.sol";
|
|
20
21
|
import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
|
|
21
22
|
|
|
22
23
|
// Admin commands
|
|
@@ -41,7 +42,7 @@ import { PortDebitAccount } from "./ports/Debit.sol";
|
|
|
41
42
|
import { PortDenyAssets } from "./ports/DenyAssets.sol";
|
|
42
43
|
import { PortPipePayable } from "./ports/Pipe.sol";
|
|
43
44
|
import { PortDispatchPayable } from "./ports/Dispatch.sol";
|
|
44
|
-
import {
|
|
45
|
+
import { PortPost } from "./ports/Post.sol";
|
|
45
46
|
|
|
46
47
|
// Guard endpoints
|
|
47
48
|
import { GuardBase } from "./guards/Base.sol";
|
package/Events.sol
CHANGED
|
@@ -11,7 +11,6 @@ import { BalanceEvent } from "./events/Balance.sol";
|
|
|
11
11
|
import { CommanderEvent } from "./events/Commander.sol";
|
|
12
12
|
import { DispatchEvent } from "./events/Dispatch.sol";
|
|
13
13
|
import { EndpointEvent } from "./events/Endpoint.sol";
|
|
14
|
-
import { PositionEvent } from "./events/Position.sol";
|
|
15
14
|
import { ReceivedEvent } from "./events/Received.sol";
|
|
16
15
|
import { RecoveredEvent } from "./events/Recovered.sol";
|
|
17
16
|
import { EventEmitter } from "./events/Emitter.sol";
|
package/README.md
CHANGED
|
@@ -149,7 +149,7 @@ const input = concat([
|
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
Everything downstream keeps this shape: commands loop over input blocks,
|
|
152
|
-
|
|
152
|
+
posting loops over transactions, pipelines loop over steps. Batching is
|
|
153
153
|
never a special case.
|
|
154
154
|
|
|
155
155
|
## IDs, Accounts, Assets, and Nodes
|
|
@@ -248,30 +248,51 @@ struct CommandContext {
|
|
|
248
248
|
|
|
249
249
|
Every command returns two block streams: `state`, which is threaded into the
|
|
250
250
|
next pipeline step, and `transactions`, which contains `#transaction` blocks
|
|
251
|
-
for the pipeline host to
|
|
251
|
+
for the pipeline host to post outside the state lane. Either stream may be
|
|
252
252
|
empty.
|
|
253
253
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
State is linear, not optional ambient context. A command is responsible for
|
|
255
|
+
the entire state stream it receives: it must validate and consume it, transform
|
|
256
|
+
and return it, forward it intact, or revert. A command must never succeed while
|
|
257
|
+
silently ignoring or dropping supplied state. Commands that declare
|
|
258
|
+
`Specs.Empty` state therefore reject any non-empty state, while commands that
|
|
259
|
+
accept state validate the complete stream against their declared state schema.
|
|
260
|
+
This is especially important for `#position`, because dropping a position could
|
|
261
|
+
silently discard both live value and an outstanding debt requirement.
|
|
257
262
|
|
|
258
|
-
The
|
|
259
|
-
|
|
263
|
+
The input carries instructions; the state carries live value. While a
|
|
264
|
+
sequence of commands executes, `#balance`, `#custody`, and `#position` blocks
|
|
265
|
+
in the state are the value being moved — produced by one command, consumed by
|
|
266
|
+
the next. A position carries an asset-liability pair as
|
|
267
|
+
`{ asset, amount, liability, debt }`.
|
|
268
|
+
|
|
269
|
+
`#position` is general live state rather than a lending-specific debt record.
|
|
270
|
+
It pairs value acquired or controlled with value owed or required. A command
|
|
271
|
+
may preserve or replace either side and return the resulting position for the
|
|
272
|
+
next step; `settle` terminally consumes the pair. This supports swaps,
|
|
273
|
+
borrowing, refinancing, collateral changes, callback obligations, cross-host
|
|
274
|
+
claims, fees, netting, and other multi-step operations. A position is a
|
|
275
|
+
transient representation and does not itself create or erase an obligation
|
|
276
|
+
recorded by an external system.
|
|
277
|
+
|
|
278
|
+
The standard `Deposit` mixin shows the canonical shape: open and validate both
|
|
279
|
+
command lanes, loop the batch, call the hook, and write the output run:
|
|
260
280
|
|
|
261
281
|
```solidity
|
|
262
282
|
function deposit(
|
|
263
|
-
|
|
283
|
+
bytes32 account,
|
|
284
|
+
bytes calldata state,
|
|
285
|
+
bytes calldata input
|
|
264
286
|
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
265
|
-
|
|
266
|
-
Writer memory output = Writers.allocBalances(outputs);
|
|
287
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
267
288
|
|
|
268
|
-
while (
|
|
269
|
-
(bytes32 asset, uint amount) =
|
|
270
|
-
deposit(
|
|
271
|
-
|
|
289
|
+
while (exec.more()) {
|
|
290
|
+
(bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
|
|
291
|
+
deposit(account, asset, amount); // host policy hook
|
|
292
|
+
exec.outputBalance(asset, amount);
|
|
272
293
|
}
|
|
273
294
|
|
|
274
|
-
return (
|
|
295
|
+
return close(exec, account);
|
|
275
296
|
}
|
|
276
297
|
```
|
|
277
298
|
|
|
@@ -292,7 +313,13 @@ abstract contract MyCommand is CommandBase {
|
|
|
292
313
|
bytes calldata state,
|
|
293
314
|
bytes calldata input
|
|
294
315
|
) external onlyCommand returns (bytes memory, bytes memory) {
|
|
295
|
-
|
|
316
|
+
Execution memory exec = openCommand(state, input, descriptor, 0);
|
|
317
|
+
while (exec.more()) {
|
|
318
|
+
(bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
|
|
319
|
+
// Apply command-specific behavior for this group.
|
|
320
|
+
exec.outputBalance(asset, amount);
|
|
321
|
+
}
|
|
322
|
+
return close(exec, account);
|
|
296
323
|
}
|
|
297
324
|
}
|
|
298
325
|
```
|
|
@@ -301,8 +328,10 @@ The standard commands cover the common ledger movements: `deposit` and
|
|
|
301
328
|
`depositPayable` (external funds in), `withdraw` and `burn` (funds out),
|
|
302
329
|
`debitAccount` and `creditAccount` (internal movements), `payout` (deliver
|
|
303
330
|
state to other accounts), `allocate` (turn balance state into custody),
|
|
304
|
-
`provision` (provision custody from an external allocation),
|
|
305
|
-
(
|
|
331
|
+
`provision` (provision custody from an external allocation), `settle` (consume
|
|
332
|
+
asset-liability position state), `relayPayable` (relay a pipeline without
|
|
333
|
+
state), and `relayBalancePayable` (relay balance state and a pipeline to another
|
|
334
|
+
portal).
|
|
306
335
|
|
|
307
336
|
## Pipelines
|
|
308
337
|
|
|
@@ -316,7 +345,7 @@ step { uint cmd, uint resources, #bytes as input }
|
|
|
316
345
|
Each step names a command, the resources it may spend, and its input.
|
|
317
346
|
The returned state threads into the next command and the final state must be
|
|
318
347
|
empty. Returned transactions do not enter the state lane; the pipeline passes
|
|
319
|
-
each decoded transaction to the shared
|
|
348
|
+
each decoded transaction to the shared posting implementation before
|
|
320
349
|
running the next step. This is the core of `Pipeline.pipe`:
|
|
321
350
|
|
|
322
351
|
```solidity
|
|
@@ -328,11 +357,11 @@ while (cur.more()) {
|
|
|
328
357
|
account,
|
|
329
358
|
state,
|
|
330
359
|
input,
|
|
331
|
-
budget.
|
|
360
|
+
budget.useResourceValue(resources)
|
|
332
361
|
);
|
|
333
362
|
while (transactions.more()) {
|
|
334
363
|
(bytes32 from, bytes32 to, bytes32 asset, uint amount) = transactions.unpackTransaction();
|
|
335
|
-
|
|
364
|
+
post(from, to, asset, amount);
|
|
336
365
|
}
|
|
337
366
|
}
|
|
338
367
|
if (state.length != 0) revert UnexpectedState();
|
|
@@ -345,6 +374,31 @@ command batching — and `resources` is a chain-specific word interpreted by the
|
|
|
345
374
|
portal adapter (on EVM, the low 128 bits are native value in wei, drawn from a
|
|
346
375
|
shared budget), so the same pipeline bytes are meaningful to every port.
|
|
347
376
|
|
|
377
|
+
Hosts that implement a pipeline locally can inherit `InternalDebitAccount`,
|
|
378
|
+
`InternalCreditAccount`, and `InternalSettle` to advertise the canonical command
|
|
379
|
+
endpoints while routing their local command IDs through `executeDebitAccount`,
|
|
380
|
+
`executeCreditAccount`, and `executeSettle`. These adapters consume the
|
|
381
|
+
memory-backed pipeline state directly and avoid an external self-call. The host
|
|
382
|
+
dispatcher must reject nonzero step value before invoking them because all three
|
|
383
|
+
commands are non-funded.
|
|
384
|
+
|
|
385
|
+
Positions also support backward-composed pipelines. In an exact-output route,
|
|
386
|
+
the asset side can represent the desired result while the liability side
|
|
387
|
+
represents the value currently required upstream. Each hop consumes one
|
|
388
|
+
position, fulfills or transforms its current requirement, and returns the next
|
|
389
|
+
position:
|
|
390
|
+
|
|
391
|
+
```txt
|
|
392
|
+
position(C, 100, C, 100)
|
|
393
|
+
→ position(C, 100, B, 50)
|
|
394
|
+
→ position(C, 100, A, 25)
|
|
395
|
+
→ settle
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
This is backward composition, not backward execution: `#step` blocks still
|
|
399
|
+
execute forward in their encoded order. Exact-output routing is only one use;
|
|
400
|
+
other commands may transform the asset side, the liability side, or both.
|
|
401
|
+
|
|
348
402
|
## Queries
|
|
349
403
|
|
|
350
404
|
Queries are the read endpoints: view functions that take a block-stream input
|
|
@@ -365,15 +419,15 @@ the descriptor's lanes through the published block schemas.
|
|
|
365
419
|
Ports are the host-to-host surfaces, callable only by trusted peer hosts. The two
|
|
366
420
|
central ones are batches all the way down:
|
|
367
421
|
|
|
368
|
-
- `
|
|
422
|
+
- `portPost` consumes `transaction { bytes32 from, bytes32 to, bytes32 asset,
|
|
369
423
|
uint amount }` blocks, debiting `from` and crediting `to` per
|
|
370
|
-
block — how two hosts
|
|
424
|
+
block — how two hosts post transactions between their ledgers.
|
|
371
425
|
- `portPipePayable` consumes `context` blocks, each carrying an account, an
|
|
372
426
|
initial state, and a run of steps — a complete pipeline delivered by another
|
|
373
427
|
host, executed locally against the port call's shared value budget.
|
|
374
428
|
|
|
375
|
-
This is also the cross-portal mechanism. `relayPayable
|
|
376
|
-
wraps a pipe and addresses it to a portal, commonly the destination host ID;
|
|
429
|
+
This is also the cross-portal mechanism. `relayPayable`, `relayBalancePayable`,
|
|
430
|
+
or `portDispatchPayable` wraps a pipe and addresses it to a portal, commonly the destination host ID;
|
|
377
431
|
a bridge adapter moves the **raw
|
|
378
432
|
bytes**; the destination host parses them with the same cursor rules and runs
|
|
379
433
|
the same pipeline loop. Nothing in the payload is EVM-specific — step commands
|
|
@@ -386,9 +440,9 @@ bytes and produce the same output bytes for every endpoint.
|
|
|
386
440
|
|
|
387
441
|
Admin commands use the regular command shape but are gated to the host's admin
|
|
388
442
|
account: trust management (`authorize`, `unauthorize`), guardian management
|
|
389
|
-
(`appoint`, `dismiss`), metadata (`
|
|
390
|
-
`
|
|
391
|
-
|
|
443
|
+
(`appoint`, `dismiss`), metadata (`annotate`), optional asset gating
|
|
444
|
+
(`allowAssets`, `denyAssets`, `allowance`), and raw calls (`executePayable`).
|
|
445
|
+
Guards go the other way: direct actions guardians can take
|
|
392
446
|
without any command context — the default is `revoke`, which lets a guardian
|
|
393
447
|
drop a trusted node immediately.
|
|
394
448
|
|
package/codec/Blocks.sol
CHANGED
|
@@ -35,10 +35,6 @@ library Blocks {
|
|
|
35
35
|
error UnexpectedValue();
|
|
36
36
|
/// @dev A scoped block run contained no blocks.
|
|
37
37
|
error EmptyRun();
|
|
38
|
-
/// @dev A block run was scoped with a zero stride.
|
|
39
|
-
error ZeroStride();
|
|
40
|
-
/// @dev A block count is not divisible by its declared stride.
|
|
41
|
-
error BadRatio();
|
|
42
38
|
|
|
43
39
|
// -------------------------------------------------------------------------
|
|
44
40
|
// Calldata inspection and navigation
|
|
@@ -147,25 +143,16 @@ library Blocks {
|
|
|
147
143
|
}
|
|
148
144
|
}
|
|
149
145
|
|
|
150
|
-
/// @notice
|
|
146
|
+
/// @notice Count a run that must consume the complete region.
|
|
147
|
+
/// @dev Reverts when any well-formed trailing block has a different key.
|
|
151
148
|
/// @param abs Absolute start position.
|
|
152
149
|
/// @param limit Absolute region boundary.
|
|
153
|
-
/// @param key
|
|
154
|
-
/// @
|
|
155
|
-
/// @return
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
uint limit,
|
|
160
|
-
bytes4 key,
|
|
161
|
-
uint stride
|
|
162
|
-
) internal pure returns (uint groups, uint end) {
|
|
163
|
-
if (stride == 0) revert ZeroStride();
|
|
164
|
-
uint count;
|
|
165
|
-
(count, end) = run(abs, limit, key);
|
|
166
|
-
if (count == 0) revert EmptyRun();
|
|
167
|
-
if (count % stride != 0) revert BadRatio();
|
|
168
|
-
groups = count / stride;
|
|
150
|
+
/// @param key Required block key for the complete region.
|
|
151
|
+
/// @return total Number of matching blocks.
|
|
152
|
+
/// @return end Absolute position equal to `limit`.
|
|
153
|
+
function runExact(uint abs, uint limit, bytes4 key) internal pure returns (uint total, uint end) {
|
|
154
|
+
(total, end) = run(abs, limit, key);
|
|
155
|
+
if (end != limit) revert InvalidBlock();
|
|
169
156
|
}
|
|
170
157
|
|
|
171
158
|
// Generic block writes
|
|
@@ -460,6 +447,33 @@ library Blocks {
|
|
|
460
447
|
|
|
461
448
|
// Four-word payloads
|
|
462
449
|
|
|
450
|
+
/// @notice Write a POSITION block at `i`.
|
|
451
|
+
/// @dev DANGER: Unchecked memory write. Reserve `Sizes.B128` bytes first.
|
|
452
|
+
/// @param dst Destination buffer.
|
|
453
|
+
/// @param i Relative write position.
|
|
454
|
+
/// @param asset Identifier for the asset side.
|
|
455
|
+
/// @param amount Quantity on the asset side.
|
|
456
|
+
/// @param liability Identifier for the liability side.
|
|
457
|
+
/// @param debt Quantity owed on the liability side.
|
|
458
|
+
function writePosition(
|
|
459
|
+
bytes memory dst,
|
|
460
|
+
uint i,
|
|
461
|
+
bytes32 asset,
|
|
462
|
+
uint amount,
|
|
463
|
+
bytes32 liability,
|
|
464
|
+
uint debt
|
|
465
|
+
) internal pure {
|
|
466
|
+
uint spec = Specs.Position;
|
|
467
|
+
assembly ("memory-safe") {
|
|
468
|
+
let p := add(add(dst, 0x20), i)
|
|
469
|
+
mstore(p, spec)
|
|
470
|
+
mstore(add(p, 0x08), asset)
|
|
471
|
+
mstore(add(p, 0x28), amount)
|
|
472
|
+
mstore(add(p, 0x48), liability)
|
|
473
|
+
mstore(add(p, 0x68), debt)
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
463
477
|
/// @notice Write a TRANSACTION block at `i`.
|
|
464
478
|
/// @dev DANGER: Unchecked memory write. Reserve `Sizes.B128` bytes first.
|
|
465
479
|
/// @param dst Destination buffer.
|
|
@@ -1249,6 +1263,28 @@ library Blocks {
|
|
|
1249
1263
|
|
|
1250
1264
|
// Four-word payloads
|
|
1251
1265
|
|
|
1266
|
+
/// @notice Decode a low-level fixed-width POSITION block at `abs`.
|
|
1267
|
+
/// @param abs Absolute block position.
|
|
1268
|
+
/// @return asset Decoded asset-side identifier.
|
|
1269
|
+
/// @return amount Decoded asset-side quantity.
|
|
1270
|
+
/// @return liability Decoded liability-side identifier.
|
|
1271
|
+
/// @return debt Decoded liability-side debt.
|
|
1272
|
+
function unpackPosition(
|
|
1273
|
+
uint abs
|
|
1274
|
+
) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
|
|
1275
|
+
uint head;
|
|
1276
|
+
assembly ("memory-safe") {
|
|
1277
|
+
head := calldataload(abs)
|
|
1278
|
+
}
|
|
1279
|
+
if (head >> 192 != Specs.Position >> 192) revert InvalidBlock();
|
|
1280
|
+
assembly ("memory-safe") {
|
|
1281
|
+
asset := calldataload(add(abs, 0x08))
|
|
1282
|
+
amount := calldataload(add(abs, 0x28))
|
|
1283
|
+
liability := calldataload(add(abs, 0x48))
|
|
1284
|
+
debt := calldataload(add(abs, 0x68))
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1252
1288
|
/// @notice Decode a low-level fixed-width TRANSACTION block at `abs`.
|
|
1253
1289
|
/// @param abs Absolute block position.
|
|
1254
1290
|
/// @return from Decoded debit account.
|
|
@@ -1577,6 +1613,28 @@ library Blocks {
|
|
|
1577
1613
|
return bytes.concat(Keys.Balance, bytes4(uint32(64)), asset, bytes32(amount));
|
|
1578
1614
|
}
|
|
1579
1615
|
|
|
1616
|
+
/// @notice Encode a POSITION block.
|
|
1617
|
+
/// @param asset Identifier for the asset side.
|
|
1618
|
+
/// @param amount Quantity on the asset side.
|
|
1619
|
+
/// @param liability Identifier for the liability side.
|
|
1620
|
+
/// @param debt Quantity owed on the liability side.
|
|
1621
|
+
/// @return Encoded POSITION block bytes.
|
|
1622
|
+
function position(
|
|
1623
|
+
bytes32 asset,
|
|
1624
|
+
uint amount,
|
|
1625
|
+
bytes32 liability,
|
|
1626
|
+
uint debt
|
|
1627
|
+
) internal pure returns (bytes memory) {
|
|
1628
|
+
return bytes.concat(
|
|
1629
|
+
Keys.Position,
|
|
1630
|
+
bytes4(uint32(128)),
|
|
1631
|
+
asset,
|
|
1632
|
+
bytes32(amount),
|
|
1633
|
+
liability,
|
|
1634
|
+
bytes32(debt)
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1580
1638
|
/// @notice Encode a CUSTODY block.
|
|
1581
1639
|
/// @param host Host node ID holding the custody.
|
|
1582
1640
|
/// @param asset Asset identifier.
|
package/codec/Buffers.sol
CHANGED
|
@@ -18,12 +18,12 @@ library Buffers {
|
|
|
18
18
|
|
|
19
19
|
/// @notice Create a packed buffer cursor at write position zero.
|
|
20
20
|
/// @param len Initial logical byte capacity.
|
|
21
|
-
/// @param
|
|
21
|
+
/// @param count Number of logical items represented by the buffer.
|
|
22
22
|
/// @param growable Whether writes may expand the logical capacity.
|
|
23
23
|
/// @param tag Cursor identity tag.
|
|
24
24
|
/// @return cur Packed buffer cursor.
|
|
25
|
-
function cursor(uint len, uint
|
|
26
|
-
cur = Cursors.create(0, len,
|
|
25
|
+
function cursor(uint len, uint count, bool growable, uint8 tag) internal pure returns (uint cur) {
|
|
26
|
+
cur = Cursors.create(0, len, count, growable ? Growable : 0, tag);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/// @notice Reserve relative write space and return the updated packed buffer cursor.
|
package/codec/Decoders.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, AccountAmount, HostAmount, HostAccountAsset, Tx} from "../core/Types.sol";
|
|
4
|
+
import {AssetAmount, AccountAsset, AccountAmount, HostAmount, HostAccountAsset, Position, Tx} from "../core/Types.sol";
|
|
5
5
|
import {Blocks} from "./Blocks.sol";
|
|
6
6
|
import {Sizes, Specs} from "./Specs.sol";
|
|
7
7
|
import {Cursors, Cur} from "../utils/Cursors.sol";
|
|
@@ -32,20 +32,17 @@ library Decoders {
|
|
|
32
32
|
cur.state = Cursors.wrap(source[i:], 0, 0);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
/// @notice Open the first homogeneous run in `source
|
|
35
|
+
/// @notice Open the first homogeneous run in `source`.
|
|
36
36
|
/// @param source Calldata block stream to open.
|
|
37
|
-
/// @param stride Number of blocks per group, or zero for an ungrouped stream.
|
|
38
37
|
/// @return cur Cursor spanning the first homogeneous run.
|
|
39
|
-
function open(
|
|
40
|
-
bytes calldata source,
|
|
41
|
-
uint stride
|
|
42
|
-
) internal pure returns (Cur memory cur) {
|
|
38
|
+
function open(bytes calldata source) internal pure returns (Cur memory cur) {
|
|
43
39
|
(uint abs, uint limit) = Cursors.bounds(source);
|
|
44
|
-
if (
|
|
40
|
+
if (abs == limit) revert Blocks.EmptyRun();
|
|
45
41
|
|
|
46
42
|
bytes4 key = bytes4(source);
|
|
47
|
-
(uint
|
|
48
|
-
|
|
43
|
+
(uint count, uint end) = Blocks.run(abs, limit, key);
|
|
44
|
+
if (count == 0) revert Blocks.EmptyRun();
|
|
45
|
+
cur.state = Cursors.create(abs, end - abs, count, 0, 0);
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
/// @notice Return whether `cur` has unread bytes.
|
|
@@ -163,6 +160,16 @@ library Decoders {
|
|
|
163
160
|
return Blocks.find(offset + i, offset + end, key) - offset;
|
|
164
161
|
}
|
|
165
162
|
|
|
163
|
+
/// @notice Count consecutive blocks with `key` from the current cursor position.
|
|
164
|
+
/// @dev Does not advance the cursor.
|
|
165
|
+
/// @param cur Cursor to inspect.
|
|
166
|
+
/// @param key Block key forming the run.
|
|
167
|
+
/// @return count Number of consecutive matching blocks.
|
|
168
|
+
function run(Cur memory cur, bytes4 key) internal pure returns (uint count) {
|
|
169
|
+
(uint i, uint offset, uint len) = cur.state.decode();
|
|
170
|
+
(count, ) = Blocks.run(offset + i, offset + len, key);
|
|
171
|
+
}
|
|
172
|
+
|
|
166
173
|
/// @notice Consume one LIST block and return a cursor over its items.
|
|
167
174
|
/// @param cur Cursor advanced past the list.
|
|
168
175
|
/// @return items Cursor spanning the list payload.
|
|
@@ -532,6 +539,20 @@ library Decoders {
|
|
|
532
539
|
(value.host, value.asset, value.amount) = unpackCustody(cur);
|
|
533
540
|
}
|
|
534
541
|
|
|
542
|
+
/// @notice Decode and consume one POSITION block.
|
|
543
|
+
function unpackPosition(
|
|
544
|
+
Cur memory cur
|
|
545
|
+
) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
|
|
546
|
+
uint abs;
|
|
547
|
+
(cur.state, abs) = cur.state.consume(Sizes.Position);
|
|
548
|
+
(asset, amount, liability, debt) = Blocks.unpackPosition(abs);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/// @notice Decode one POSITION block into its structured value.
|
|
552
|
+
function unpackPositionValue(Cur memory cur) internal pure returns (Position memory value) {
|
|
553
|
+
(value.asset, value.amount, value.liability, value.debt) = unpackPosition(cur);
|
|
554
|
+
}
|
|
555
|
+
|
|
535
556
|
/// @notice Decode one TRANSACTION block into its structured value.
|
|
536
557
|
/// @param cur Cursor advanced past the block.
|
|
537
558
|
/// @return value Structured transaction.
|
package/codec/Descriptors.sol
CHANGED
package/codec/Keys.sol
CHANGED
|
@@ -9,8 +9,6 @@ pragma solidity ^0.8.33;
|
|
|
9
9
|
library Keys {
|
|
10
10
|
/// @dev Empty / unset key.
|
|
11
11
|
bytes4 constant Empty = bytes4(0);
|
|
12
|
-
/// @dev Wildcard key used in discovery when any block stream is accepted.
|
|
13
|
-
bytes4 constant Any = 0xffffffff;
|
|
14
12
|
/// @dev Input amount - (bytes32 asset, uint amount)
|
|
15
13
|
bytes4 constant Amount = bytes4(keccak256("#amount"));
|
|
16
14
|
/// @dev Ledger balance - (bytes32 asset, uint amount)
|
|
@@ -21,6 +19,8 @@ library Keys {
|
|
|
21
19
|
bytes4 constant Allowance = bytes4(keccak256("#allowance"));
|
|
22
20
|
/// @dev Cross-host custody state - (uint host, bytes32 asset, uint amount)
|
|
23
21
|
bytes4 constant Custody = bytes4(keccak256("#custody"));
|
|
22
|
+
/// @dev Asset-liability position state - (bytes32 asset, uint amount, bytes32 liability, uint debt)
|
|
23
|
+
bytes4 constant Position = bytes4(keccak256("#position"));
|
|
24
24
|
/// @dev List wrapper; payload is an embedded repeated block stream
|
|
25
25
|
bytes4 constant List = bytes4(keccak256("#list"));
|
|
26
26
|
/// @dev EVM-encoded payload field; layout follows standard ABI tuple encoding
|
package/codec/Readers.sol
CHANGED
|
@@ -94,6 +94,19 @@ library Readers {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/// @notice Consume a POSITION block and return its fields.
|
|
98
|
+
function unpackPosition(
|
|
99
|
+
Reader memory cur
|
|
100
|
+
) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
|
|
101
|
+
uint abs = consume(cur, Keys.Position, 128, 128);
|
|
102
|
+
assembly ("memory-safe") {
|
|
103
|
+
asset := mload(abs)
|
|
104
|
+
amount := mload(add(abs, 0x20))
|
|
105
|
+
liability := mload(add(abs, 0x40))
|
|
106
|
+
debt := mload(add(abs, 0x60))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
97
110
|
/// @notice Consume a TRANSACTION block and return its fields.
|
|
98
111
|
/// @param cur Reader; advanced past the block.
|
|
99
112
|
/// @return from Source account identifier.
|
package/codec/Schema.sol
CHANGED
|
@@ -43,10 +43,13 @@ pragma solidity ^0.8.33;
|
|
|
43
43
|
// - command input and state streams are each a single run of blocks under the
|
|
44
44
|
// current protocol convention; the block format may support other shapes in
|
|
45
45
|
// future protocol surfaces
|
|
46
|
-
// - `balance(...)` and `
|
|
46
|
+
// - `balance(...)`, `custody(...)`, and `position(...)` are live, linear state in the active command pipeline
|
|
47
47
|
// - pipeline state belongs to the active account while the pipeline is executing
|
|
48
48
|
// - while a balance or custody is in-flight as pipeline state, it is not simultaneously persisted
|
|
49
49
|
// in another ledger/store by this protocol
|
|
50
|
+
// - a position pairs live asset and liability sides; commands may transform either side
|
|
51
|
+
// - position state is transient and does not itself create or erase an externally persisted obligation
|
|
52
|
+
// - positions support backward composition, but pipeline steps always execute in encoded order
|
|
50
53
|
// - commands must preserve, transform, settle, or intentionally consume pipeline state
|
|
51
54
|
// - input blocks such as `amount(...)`, `allocation(...)`, and `allowance(...)`
|
|
52
55
|
// express intent, constraints, or references
|
|
@@ -90,6 +93,7 @@ library Schemas {
|
|
|
90
93
|
|
|
91
94
|
// Four-word payloads
|
|
92
95
|
|
|
96
|
+
string constant Position = "{ bytes32 asset, uint amount, bytes32 liability, uint debt }";
|
|
93
97
|
string constant Transaction = "{ bytes32 from, bytes32 to, bytes32 asset, uint amount }";
|
|
94
98
|
string constant HostAccountAmount = "{ uint host, bytes32 account, bytes32 asset, uint amount }";
|
|
95
99
|
|