@rootzero/contracts 1.15.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/Codec.sol +1 -1
  3. package/Commands.sol +1 -1
  4. package/Core.sol +4 -4
  5. package/Endpoints.sol +9 -7
  6. package/Events.sol +0 -1
  7. package/README.md +88 -30
  8. package/Utils.sol +1 -1
  9. package/codec/Blocks.sol +111 -21
  10. package/codec/Buffers.sol +3 -3
  11. package/codec/Decoders.sol +48 -10
  12. package/codec/Descriptors.sol +0 -1
  13. package/codec/Keys.sol +4 -2
  14. package/codec/Readers.sol +25 -0
  15. package/codec/Schema.sol +6 -1
  16. package/codec/Specs.sol +7 -2
  17. package/codec/Writers.sol +28 -2
  18. package/commands/Base.sol +8 -15
  19. package/commands/Burn.sol +2 -2
  20. package/commands/Credit.sol +38 -3
  21. package/commands/Debit.sol +50 -14
  22. package/commands/Deposit.sol +4 -4
  23. package/commands/Provision.sol +4 -4
  24. package/commands/Recover.sol +15 -8
  25. package/commands/Relay.sol +37 -12
  26. package/commands/Settle.sol +130 -0
  27. package/commands/Withdraw.sol +2 -2
  28. package/commands/admin/AllowAssets.sol +2 -2
  29. package/commands/admin/Allowance.sol +3 -3
  30. package/commands/admin/Annotate.sol +2 -2
  31. package/commands/admin/Appoint.sol +2 -2
  32. package/commands/admin/Authorize.sol +2 -2
  33. package/commands/admin/DenyAssets.sol +2 -2
  34. package/commands/admin/Dismiss.sol +2 -2
  35. package/commands/admin/Execute.sol +3 -3
  36. package/commands/admin/Unauthorize.sol +2 -2
  37. package/core/Endpoint.sol +15 -13
  38. package/core/Pipeline.sol +6 -6
  39. package/core/Settlement.sol +37 -8
  40. package/core/Types.sol +21 -1
  41. package/docs/Schema.md +52 -2
  42. package/execution/Budget.sol +12 -4
  43. package/execution/Execution.sol +119 -11
  44. package/guards/Base.sol +2 -2
  45. package/guards/Revoke.sol +21 -0
  46. package/package.json +1 -1
  47. package/ports/Base.sol +2 -2
  48. package/ports/Dispatch.sol +6 -6
  49. package/ports/{Settle.sol → Post.sol} +10 -10
  50. package/queries/Base.sol +2 -2
  51. package/utils/Actions.sol +1 -0
  52. package/utils/Cursors.sol +16 -30
  53. package/events/Position.sol +0 -22
package/CHANGELOG.md CHANGED
@@ -3,6 +3,96 @@
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.17.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - `executeDebitAccount`, `executeCreditAccount`, and `executeSettle` now require
11
+ the pipeline step's `uint128 value` argument and reject nonzero value inside
12
+ the internal adapter.
13
+ - `AllowanceHook` implementations must treat an amount of zero as revocation.
14
+
15
+ ### Added
16
+
17
+ - Added the `HostAsset` structural block and complete codec support for
18
+ host-scoped asset references.
19
+ - Added the opt-in `RevokeAllowance` guardian endpoint, which accepts
20
+ `HostAsset` entries and revokes each allowance through `AllowanceHook`.
21
+ - Added the funded `settlePayable` command and `SettlePayableHook` for settlement
22
+ implementations that require access to the command's native-value budget.
23
+
24
+ ### Changed
25
+
26
+ - Completed the endpoint barrel with `CommandBase` and exported the new command,
27
+ guard, hook, internal adapter, and structural type surfaces from their
28
+ corresponding package barrels.
29
+
30
+ ### Upgrade Compatibility
31
+
32
+ - Pipeline hosts using the internal debit, credit, or settle adapters must pass
33
+ each step's assigned value into the adapter. Existing non-funded steps should
34
+ continue to pass zero.
35
+
36
+ ## 1.16.0
37
+
38
+ ### Breaking Changes
39
+
40
+ - Removed the unused generic `Position` event and `PositionEvent` base contract.
41
+ - Renamed transaction handling from settlement to posting: the transaction
42
+ helper is now `post(...)`, and `portSettle(bytes)` is now `portPost(bytes)`.
43
+ The port selector and node ID change, and its action is now `Actions.Post`
44
+ (`14`) instead of `Actions.Settle` (`3`). The `Settlement` convenience base
45
+ implements both the transaction `PostHook` and position `SettleHook`.
46
+ - Removed `openInput` from `EndpointBase`. Port, query, and guard bases expose
47
+ `openInput` through the input-only `InputEndpointBase`, while custom commands
48
+ must pass both state and input through `openCommand`.
49
+ - Removed the wildcard `Specs.Any` state type. The stateful relay is now
50
+ `relayBalancePayable` and accepts `BALANCE` state blocks; `relayPayable`
51
+ explicitly accepts empty state.
52
+ - Renamed the numeric `Position` fields from `assets` and `liabilities` to
53
+ `amount` and `debt`.
54
+ - Renamed `Budget.use` to `useResourceValue` and split execution spending into
55
+ exact `useValue` and packed-resource `useResourceValue` helpers.
56
+ - Renamed `RoutePayableHook.route` to `RelayPayableHook.relayTo`. Recovery hooks
57
+ are now `RecoverPayableHook` implementations that receive the complete
58
+ resource word and mutable execution budget.
59
+
60
+ ### Added
61
+
62
+ - Added the hostless `#position` state block for threading asset-liability pairs
63
+ between pipeline commands.
64
+ - Added the `settle` command, the position `SettleHook`, and the transaction
65
+ `PostHook`. The `Settlement` convenience base provides default implementations
66
+ of both through the debit and credit account hooks.
67
+ - Added `relayBalancePayable` for relaying required `BALANCE` state while
68
+ `relayPayable` now explicitly relays with empty state.
69
+ - Added memory-backed `InternalDebitAccount`, `InternalCreditAccount`, and
70
+ `InternalSettle` adapters for hosts that execute canonical commands directly
71
+ from their pipeline dispatcher.
72
+
73
+ ### Changed
74
+
75
+ - Documented the command state-safety invariant: every command must handle the
76
+ complete supplied state stream or revert, and commands with empty state lanes
77
+ must reject non-empty state.
78
+ - Endpoint decoder opening now requires the complete supplied lane to be one
79
+ homogeneous run of the descriptor's declared key; trailing block types are
80
+ rejected instead of silently left outside the decoder cursor.
81
+ - Block runs and cursors now retain raw block counts only. Descriptor stride
82
+ conversion and state/input group reconciliation happen once in execution
83
+ opening rather than in `Blocks` or `Cursors`.
84
+ - Pipeline transaction streams are posted before the next step, and position
85
+ state is settled separately through the scalar asset, amount, liability, and
86
+ debt hook.
87
+ - Completed the public barrel exports for internal command adapters,
88
+ input-only endpoint bases, access errors, and low-level utility helpers.
89
+
90
+ ### Upgrade Compatibility
91
+
92
+ - Command and port selectors, block schemas, and hook signatures changed in
93
+ this release. Deploy fresh hosts and update pipeline builders and peer
94
+ integrations together.
95
+
6
96
  ## 1.15.0
7
97
 
8
98
  ### 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, HostAsset, 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, HostAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Position, Tx} from "./core/Types.sol";
package/Core.sol CHANGED
@@ -7,18 +7,18 @@ pragma solidity ^0.8.33;
7
7
  import { Action } from "./annotations/Action.sol";
8
8
  import { Label } from "./annotations/Label.sol";
9
9
  import { Schema } from "./annotations/Schema.sol";
10
- import { AdminAccess, CallerAccess, CommanderAccess, GuardianAccess, NodeAccess, TrustAccess } from "./core/Access.sol";
10
+ import { AccessDenied, AdminAccess, CallerAccess, CommanderAccess, CommanderNotAllowed, GuardianAccess, NodeAccess, TrustAccess } from "./core/Access.sol";
11
11
  import { Balances, InsufficientFunds } from "./core/Balances.sol";
12
12
  import { Escrows, InsufficientEscrow } from "./core/Escrows.sol";
13
13
  import { NativeAsset, Runtime } from "./core/Runtime.sol";
14
14
  import { Admins, CommandHost, Guardians, Host, HostIntroduction, IHostIntroduction } from "./core/Host.sol";
15
15
  import { CommandCalls, FailedCall, NodeCalls, PortCalls, RawNodeCalls } from "./core/Calls.sol";
16
- import { EndpointBase } from "./core/Endpoint.sol";
16
+ import { EndpointBase, InputEndpointBase } 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, HostAsset, 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,18 +5,20 @@ 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
+ import { CommandBase } from "./commands/Base.sol";
11
12
  import { Allocate, AllocateHook } from "./commands/Allocate.sol";
12
13
  import { Burn, BurnHook } from "./commands/Burn.sol";
13
- import { CreditAccount } from "./commands/Credit.sol";
14
- import { DebitAccount } from "./commands/Debit.sol";
14
+ import { CreditAccount, InternalCreditAccount } from "./commands/Credit.sol";
15
+ import { DebitAccount, InternalDebitAccount } from "./commands/Debit.sol";
15
16
  import { Deposit, DepositHook, DepositPayable, DepositPayableHook } from "./commands/Deposit.sol";
16
17
  import { Payout, PayoutHook } from "./commands/Payout.sol";
17
18
  import { Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook } from "./commands/Provision.sol";
18
- import { RecoverHook, RecoverPayable } from "./commands/Recover.sol";
19
- import { RelayPayable, RoutePayableHook } from "./commands/Relay.sol";
19
+ import { RecoverPayable, RecoverPayableHook } from "./commands/Recover.sol";
20
+ import { RelayPayable, RelayBalancePayable, RelayPayableHook } from "./commands/Relay.sol";
21
+ import { InternalSettle, Settle, SettlePayable, SettlePayableHook } from "./commands/Settle.sol";
20
22
  import { Withdraw, WithdrawHook } from "./commands/Withdraw.sol";
21
23
 
22
24
  // Admin commands
@@ -41,11 +43,11 @@ import { PortDebitAccount } from "./ports/Debit.sol";
41
43
  import { PortDenyAssets } from "./ports/DenyAssets.sol";
42
44
  import { PortPipePayable } from "./ports/Pipe.sol";
43
45
  import { PortDispatchPayable } from "./ports/Dispatch.sol";
44
- import { PortSettle } from "./ports/Settle.sol";
46
+ import { PortPost } from "./ports/Post.sol";
45
47
 
46
48
  // Guard endpoints
47
49
  import { GuardBase } from "./guards/Base.sol";
48
- import { Revoke } from "./guards/Revoke.sol";
50
+ import { Revoke, RevokeAllowance } from "./guards/Revoke.sol";
49
51
 
50
52
  // Query endpoints
51
53
  import { QueryBase } from "./queries/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
- settlement loops over transactions, pipelines loop over steps. Batching is
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
@@ -219,7 +219,10 @@ pipeline.
219
219
 
220
220
  The built-in surface is also available as two independent feature bundles:
221
221
  `Admins` provides annotate, authorize, unauthorize, and executePayable;
222
- `Guardians` provides appoint, dismiss, and revoke. The full `Host` composes
222
+ `Guardians` provides appoint, dismiss, and node revocation. Hosts that implement
223
+ the allowance hook can additionally inherit the opt-in `RevokeAllowance` guard,
224
+ which accepts `hostAsset { uint host, bytes32 asset }` entries and always applies
225
+ a zero allowance. The full `Host` composes
223
226
  both, while smaller hosts can inherit either bundle separately.
224
227
 
225
228
  Trust is explicit and minimal. Each host has an immutable **commander**
@@ -248,30 +251,51 @@ struct CommandContext {
248
251
 
249
252
  Every command returns two block streams: `state`, which is threaded into the
250
253
  next pipeline step, and `transactions`, which contains `#transaction` blocks
251
- for the pipeline host to settle outside the state lane. Either stream may be
254
+ for the pipeline host to post outside the state lane. Either stream may be
252
255
  empty.
253
256
 
254
- The input carries instructions; the state carries live value. While a
255
- sequence of commands executes, `#balance` and `#custody` blocks in the state
256
- are the funds being moved produced by one command, consumed by the next.
257
+ State is linear, not optional ambient context. A command is responsible for
258
+ the entire state stream it receives: it must validate and consume it, transform
259
+ and return it, forward it intact, or revert. A command must never succeed while
260
+ silently ignoring or dropping supplied state. Commands that declare
261
+ `Specs.Empty` state therefore reject any non-empty state, while commands that
262
+ accept state validate the complete stream against their declared state schema.
263
+ This is especially important for `#position`, because dropping a position could
264
+ silently discard both live value and an outstanding debt requirement.
257
265
 
258
- The standard `Deposit` mixin shows the canonical shape open the input,
259
- loop the batch, call the hook, write the output run:
266
+ The input carries instructions; the state carries live value. While a
267
+ sequence of commands executes, `#balance`, `#custody`, and `#position` blocks
268
+ in the state are the value being moved — produced by one command, consumed by
269
+ the next. A position carries an asset-liability pair as
270
+ `{ asset, amount, liability, debt }`.
271
+
272
+ `#position` is general live state rather than a lending-specific debt record.
273
+ It pairs value acquired or controlled with value owed or required. A command
274
+ may preserve or replace either side and return the resulting position for the
275
+ next step; `settle` terminally consumes the pair. This supports swaps,
276
+ borrowing, refinancing, collateral changes, callback obligations, cross-host
277
+ claims, fees, netting, and other multi-step operations. A position is a
278
+ transient representation and does not itself create or erase an obligation
279
+ recorded by an external system.
280
+
281
+ The standard `Deposit` mixin shows the canonical shape: open and validate both
282
+ command lanes, loop the batch, call the hook, and write the output run:
260
283
 
261
284
  ```solidity
262
285
  function deposit(
263
- CommandContext calldata c
286
+ bytes32 account,
287
+ bytes calldata state,
288
+ bytes calldata input
264
289
  ) external onlyCommand returns (bytes memory, bytes memory) {
265
- (Cur memory input, uint outputs) = openInput(c.input, descriptor);
266
- Writer memory output = Writers.allocBalances(outputs);
290
+ Execution memory exec = openCommand(state, input, descriptor, 0);
267
291
 
268
- while (input.i < input.len) {
269
- (bytes32 asset, uint amount) = input.unpackAmount();
270
- deposit(c.account, asset, amount); // host policy hook
271
- output.appendBalance(asset, amount);
292
+ while (exec.more()) {
293
+ (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
294
+ deposit(account, asset, amount); // host policy hook
295
+ exec.outputBalance(asset, amount);
272
296
  }
273
297
 
274
- return (end(output), "");
298
+ return close(exec, account);
275
299
  }
276
300
  ```
277
301
 
@@ -292,17 +316,26 @@ abstract contract MyCommand is CommandBase {
292
316
  bytes calldata state,
293
317
  bytes calldata input
294
318
  ) external onlyCommand returns (bytes memory, bytes memory) {
295
- // parse input, loop, return the output state run and any transactions
319
+ Execution memory exec = openCommand(state, input, descriptor, 0);
320
+ while (exec.more()) {
321
+ (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
322
+ // Apply command-specific behavior for this group.
323
+ exec.outputBalance(asset, amount);
324
+ }
325
+ return close(exec, account);
296
326
  }
297
327
  }
298
328
  ```
299
329
 
300
330
  The standard commands cover the common ledger movements: `deposit` and
301
- `depositPayable` (external funds in), `withdraw` and `burn` (funds out),
331
+ `depositPayable` (external funds in), `settlePayable` (funded settlement),
332
+ `withdraw` and `burn` (funds out),
302
333
  `debitAccount` and `creditAccount` (internal movements), `payout` (deliver
303
334
  state to other accounts), `allocate` (turn balance state into custody),
304
- `provision` (provision custody from an external allocation), and `relayPayable`
305
- (hand a pipeline to another portal).
335
+ `provision` (provision custody from an external allocation), `settle` (consume
336
+ asset-liability position state), `relayPayable` (relay a pipeline without
337
+ state), and `relayBalancePayable` (relay balance state and a pipeline to another
338
+ portal).
306
339
 
307
340
  ## Pipelines
308
341
 
@@ -316,7 +349,7 @@ step { uint cmd, uint resources, #bytes as input }
316
349
  Each step names a command, the resources it may spend, and its input.
317
350
  The returned state threads into the next command and the final state must be
318
351
  empty. Returned transactions do not enter the state lane; the pipeline passes
319
- each decoded transaction to the shared settlement implementation before
352
+ each decoded transaction to the shared posting implementation before
320
353
  running the next step. This is the core of `Pipeline.pipe`:
321
354
 
322
355
  ```solidity
@@ -328,11 +361,11 @@ while (cur.more()) {
328
361
  account,
329
362
  state,
330
363
  input,
331
- budget.use(resources)
364
+ budget.useResourceValue(resources)
332
365
  );
333
366
  while (transactions.more()) {
334
367
  (bytes32 from, bytes32 to, bytes32 asset, uint amount) = transactions.unpackTransaction();
335
- settle(from, to, asset, amount);
368
+ post(from, to, asset, amount);
336
369
  }
337
370
  }
338
371
  if (state.length != 0) revert UnexpectedState();
@@ -345,6 +378,31 @@ command batching — and `resources` is a chain-specific word interpreted by the
345
378
  portal adapter (on EVM, the low 128 bits are native value in wei, drawn from a
346
379
  shared budget), so the same pipeline bytes are meaningful to every port.
347
380
 
381
+ Hosts that implement a pipeline locally can inherit `InternalDebitAccount`,
382
+ `InternalCreditAccount`, and `InternalSettle` to advertise the canonical command
383
+ endpoints while routing their local command IDs through `executeDebitAccount`,
384
+ `executeCreditAccount`, and `executeSettle`. These adapters consume the
385
+ memory-backed pipeline state directly and avoid an external self-call. Pass the
386
+ step value into each adapter; all three reject nonzero value because the
387
+ commands are non-funded.
388
+
389
+ Positions also support backward-composed pipelines. In an exact-output route,
390
+ the asset side can represent the desired result while the liability side
391
+ represents the value currently required upstream. Each hop consumes one
392
+ position, fulfills or transforms its current requirement, and returns the next
393
+ position:
394
+
395
+ ```txt
396
+ position(C, 100, C, 100)
397
+ → position(C, 100, B, 50)
398
+ → position(C, 100, A, 25)
399
+ → settle
400
+ ```
401
+
402
+ This is backward composition, not backward execution: `#step` blocks still
403
+ execute forward in their encoded order. Exact-output routing is only one use;
404
+ other commands may transform the asset side, the liability side, or both.
405
+
348
406
  ## Queries
349
407
 
350
408
  Queries are the read endpoints: view functions that take a block-stream input
@@ -365,15 +423,15 @@ the descriptor's lanes through the published block schemas.
365
423
  Ports are the host-to-host surfaces, callable only by trusted peer hosts. The two
366
424
  central ones are batches all the way down:
367
425
 
368
- - `portSettle` consumes `transaction { bytes32 from, bytes32 to, bytes32 asset,
426
+ - `portPost` consumes `transaction { bytes32 from, bytes32 to, bytes32 asset,
369
427
  uint amount }` blocks, debiting `from` and crediting `to` per
370
- block — how two hosts record settlement between their ledgers.
428
+ block — how two hosts post transactions between their ledgers.
371
429
  - `portPipePayable` consumes `context` blocks, each carrying an account, an
372
430
  initial state, and a run of steps — a complete pipeline delivered by another
373
431
  host, executed locally against the port call's shared value budget.
374
432
 
375
- This is also the cross-portal mechanism. `relayPayable` (or `portDispatchPayable`)
376
- wraps a pipe and addresses it to a portal, commonly the destination host ID;
433
+ This is also the cross-portal mechanism. `relayPayable`, `relayBalancePayable`,
434
+ or `portDispatchPayable` wraps a pipe and addresses it to a portal, commonly the destination host ID;
377
435
  a bridge adapter moves the **raw
378
436
  bytes**; the destination host parses them with the same cursor rules and runs
379
437
  the same pipeline loop. Nothing in the payload is EVM-specific — step commands
@@ -386,9 +444,9 @@ bytes and produce the same output bytes for every endpoint.
386
444
 
387
445
  Admin commands use the regular command shape but are gated to the host's admin
388
446
  account: trust management (`authorize`, `unauthorize`), guardian management
389
- (`appoint`, `dismiss`), metadata (`label`, `publishSchema`), asset gating (`allowAssets`,
390
- `denyAssets`, `allowance`), lifecycle (`init`, `destroy`), and raw calls
391
- (`executePayable`). Guards go the other way: direct actions guardians can take
447
+ (`appoint`, `dismiss`), metadata (`annotate`), optional asset gating
448
+ (`allowAssets`, `denyAssets`, `allowance`), and raw calls (`executePayable`).
449
+ Guards go the other way: direct actions guardians can take
392
450
  without any command context — the default is `revoke`, which lets a guardian
393
451
  drop a trusted node immediately.
394
452
 
package/Utils.sol CHANGED
@@ -13,7 +13,7 @@ import { Ids } from "./utils/Ids.sol";
13
13
  import { Nodes } from "./utils/Nodes.sol";
14
14
  import { Selectors } from "./utils/Selectors.sol";
15
15
  import { Layout } from "./utils/Layout.sol";
16
- import { addrOr, applyBps, beforeBps, bytes32ToInt, bytes32ToString, divisible, hash32, intToBytes32, isFamily, matchesBase, MAX_BPS, max8, max16, max24, max32, max40, max64, max96, max128, max160, NotDivisible, retryTicket, toLocalBase, toUnspecifiedBase, ValueOverflow } from "./utils/Utils.sol";
16
+ import { addrOr, applyBps, beforeBps, bytes32ToInt, bytes32ToString, clear8, clear16, clear32, clear64, divisible, ensureAddr, hash32, intToBytes32, isFamily, matchesBase, MAX_BPS, max8, max16, max24, max32, max40, max64, max96, max128, max160, NotDivisible, replace8, replace16, replace32, replace64, retryTicket, toLocalBase, toUnspecifiedBase, ValueOverflow, ZeroAddress } from "./utils/Utils.sol";
17
17
 
18
18
 
19
19
 
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 Scope a consecutive block run into equal-sized groups.
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 Block key forming the run.
154
- /// @param stride Number of blocks per group.
155
- /// @return groups Number of complete groups in the run.
156
- /// @return end Absolute position immediately after the run.
157
- function scope(
158
- uint abs,
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
@@ -348,6 +335,22 @@ library Blocks {
348
335
  }
349
336
  }
350
337
 
338
+ /// @notice Write a HOST_ASSET block at `i`.
339
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B64` bytes first.
340
+ /// @param dst Destination buffer.
341
+ /// @param i Relative write position.
342
+ /// @param host Host identifier to encode.
343
+ /// @param asset Asset identifier to encode.
344
+ function writeHostAsset(bytes memory dst, uint i, uint host, bytes32 asset) internal pure {
345
+ uint spec = Specs.HostAsset;
346
+ assembly ("memory-safe") {
347
+ let p := add(add(dst, 0x20), i)
348
+ mstore(p, spec)
349
+ mstore(add(p, 0x08), host)
350
+ mstore(add(p, 0x28), asset)
351
+ }
352
+ }
353
+
351
354
  // Three-word payloads
352
355
 
353
356
  /// @notice Write an ALLOCATION block at `i`.
@@ -460,6 +463,33 @@ library Blocks {
460
463
 
461
464
  // Four-word payloads
462
465
 
466
+ /// @notice Write a POSITION block at `i`.
467
+ /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B128` bytes first.
468
+ /// @param dst Destination buffer.
469
+ /// @param i Relative write position.
470
+ /// @param asset Identifier for the asset side.
471
+ /// @param amount Quantity on the asset side.
472
+ /// @param liability Identifier for the liability side.
473
+ /// @param debt Quantity owed on the liability side.
474
+ function writePosition(
475
+ bytes memory dst,
476
+ uint i,
477
+ bytes32 asset,
478
+ uint amount,
479
+ bytes32 liability,
480
+ uint debt
481
+ ) internal pure {
482
+ uint spec = Specs.Position;
483
+ assembly ("memory-safe") {
484
+ let p := add(add(dst, 0x20), i)
485
+ mstore(p, spec)
486
+ mstore(add(p, 0x08), asset)
487
+ mstore(add(p, 0x28), amount)
488
+ mstore(add(p, 0x48), liability)
489
+ mstore(add(p, 0x68), debt)
490
+ }
491
+ }
492
+
463
493
  /// @notice Write a TRANSACTION block at `i`.
464
494
  /// @dev DANGER: Unchecked memory write. Reserve `Sizes.B128` bytes first.
465
495
  /// @param dst Destination buffer.
@@ -1249,6 +1279,44 @@ library Blocks {
1249
1279
 
1250
1280
  // Four-word payloads
1251
1281
 
1282
+ /// @notice Decode a low-level fixed-width POSITION block at `abs`.
1283
+ /// @param abs Absolute block position.
1284
+ /// @return asset Decoded asset-side identifier.
1285
+ /// @return amount Decoded asset-side quantity.
1286
+ /// @return liability Decoded liability-side identifier.
1287
+ /// @return debt Decoded liability-side debt.
1288
+ function unpackPosition(
1289
+ uint abs
1290
+ ) internal pure returns (bytes32 asset, uint amount, bytes32 liability, uint debt) {
1291
+ uint head;
1292
+ assembly ("memory-safe") {
1293
+ head := calldataload(abs)
1294
+ }
1295
+ if (head >> 192 != Specs.Position >> 192) revert InvalidBlock();
1296
+ assembly ("memory-safe") {
1297
+ asset := calldataload(add(abs, 0x08))
1298
+ amount := calldataload(add(abs, 0x28))
1299
+ liability := calldataload(add(abs, 0x48))
1300
+ debt := calldataload(add(abs, 0x68))
1301
+ }
1302
+ }
1303
+
1304
+ /// @notice Decode a low-level fixed-width HOST_ASSET block at `abs`.
1305
+ /// @param abs Absolute block position.
1306
+ /// @return host Decoded host identifier.
1307
+ /// @return asset Decoded asset identifier.
1308
+ function unpackHostAsset(uint abs) internal pure returns (uint host, bytes32 asset) {
1309
+ uint head;
1310
+ assembly ("memory-safe") {
1311
+ head := calldataload(abs)
1312
+ }
1313
+ if (head >> 192 != Specs.HostAsset >> 192) revert InvalidBlock();
1314
+ assembly ("memory-safe") {
1315
+ host := calldataload(add(abs, 0x08))
1316
+ asset := calldataload(add(abs, 0x28))
1317
+ }
1318
+ }
1319
+
1252
1320
  /// @notice Decode a low-level fixed-width TRANSACTION block at `abs`.
1253
1321
  /// @param abs Absolute block position.
1254
1322
  /// @return from Decoded debit account.
@@ -1577,6 +1645,28 @@ library Blocks {
1577
1645
  return bytes.concat(Keys.Balance, bytes4(uint32(64)), asset, bytes32(amount));
1578
1646
  }
1579
1647
 
1648
+ /// @notice Encode a POSITION block.
1649
+ /// @param asset Identifier for the asset side.
1650
+ /// @param amount Quantity on the asset side.
1651
+ /// @param liability Identifier for the liability side.
1652
+ /// @param debt Quantity owed on the liability side.
1653
+ /// @return Encoded POSITION block bytes.
1654
+ function position(
1655
+ bytes32 asset,
1656
+ uint amount,
1657
+ bytes32 liability,
1658
+ uint debt
1659
+ ) internal pure returns (bytes memory) {
1660
+ return bytes.concat(
1661
+ Keys.Position,
1662
+ bytes4(uint32(128)),
1663
+ asset,
1664
+ bytes32(amount),
1665
+ liability,
1666
+ bytes32(debt)
1667
+ );
1668
+ }
1669
+
1580
1670
  /// @notice Encode a CUSTODY block.
1581
1671
  /// @param host Host node ID holding the custody.
1582
1672
  /// @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 groups Number of logical groups represented by the buffer.
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 groups, bool growable, uint8 tag) internal pure returns (uint cur) {
26
- cur = Cursors.create(0, len, groups, growable ? Growable : 0, tag);
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.