@rootzero/contracts 1.23.0 → 1.25.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 +78 -0
- package/Codec.sol +1 -1
- package/Commands.sol +1 -1
- package/Core.sol +3 -3
- package/Endpoints.sol +9 -1
- package/README.md +35 -24
- package/Utils.sol +1 -1
- package/annotations/Schema.sol +1 -7
- package/codec/Blocks.sol +153 -24
- package/codec/Decoders.sol +42 -5
- package/codec/Descriptors.sol +3 -1
- package/codec/Keys.sol +2 -0
- package/codec/Readers.sol +12 -0
- package/codec/Schema.sol +5 -4
- package/codec/Specs.sol +3 -0
- package/codec/Writers.sol +12 -1
- package/commands/Base.sol +1 -4
- package/commands/Debit.sol +2 -5
- package/commands/Repay.sol +110 -10
- package/commands/admin/Base.sol +1 -4
- package/core/Access.sol +8 -0
- package/core/Pipeline.sol +26 -7
- package/core/Types.sol +8 -0
- package/execution/Budget.sol +22 -0
- package/execution/Execution.sol +48 -4
- package/package.json +1 -1
- package/ports/Pipe.sol +4 -5
- package/utils/Utils.sol +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,84 @@
|
|
|
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
|
+
Add all changes made after a release to `Unreleased`. Published version
|
|
7
|
+
sections are immutable and must continue to describe the tagged release.
|
|
8
|
+
|
|
9
|
+
## Unreleased
|
|
10
|
+
|
|
11
|
+
## 1.25.0
|
|
12
|
+
|
|
13
|
+
### Breaking Changes
|
|
14
|
+
|
|
15
|
+
- Changed `Pipeline.pipe` to accept a scalar `uint` budget and return the
|
|
16
|
+
remaining scalar budget. The standalone mutable `Budget` type remains
|
|
17
|
+
available for other funded execution flows.
|
|
18
|
+
- Split the pipeline hook from its standard implementation. `PipePayablePort`
|
|
19
|
+
now inherits only `PipeHook`; hosts that want the built-in pipeline must
|
|
20
|
+
compose `Pipeline` explicitly, while custom hosts may implement the hook
|
|
21
|
+
without inheriting the standard dispatch and posting implementation.
|
|
22
|
+
- Changed `Decoders.open` to wrap the complete non-empty calldata source as an
|
|
23
|
+
ungrouped cursor. Code that needs the former counted first-homogeneous-run
|
|
24
|
+
behavior must use the new `Decoders.batch` helper.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- Added scalar `Budgets.useValue` and `Budgets.useResourceValue` overloads, and
|
|
29
|
+
`Executions.drainBudget` for transferring an execution budget as a `uint`.
|
|
30
|
+
- Added `PipeHook` to the `Core.sol` and `Endpoints.sol` package barrels.
|
|
31
|
+
- Added `Blocks.expectKey` and key-only `Decoders.consume` and
|
|
32
|
+
`Executions.consume` overloads for validating blocks whose payload shape is
|
|
33
|
+
established by specialized decoding logic.
|
|
34
|
+
- Added `Blocks.require1`, `require2`, `require4`, `require8`, and `require16`,
|
|
35
|
+
completing the fixed-width validation family alongside `require32`.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Specialized built-in composite block unpackers to validate their known keys
|
|
40
|
+
directly instead of constructing and evaluating generic specifications.
|
|
41
|
+
- Specialized fixed-width block validation, empty-block inspection, and
|
|
42
|
+
key-only `takeBlock` paths to avoid redundant specification and calldata
|
|
43
|
+
work.
|
|
44
|
+
- Pipeline execution now validates the complete STEP source and rejects a
|
|
45
|
+
trailing block with a different key instead of silently stopping after the
|
|
46
|
+
first homogeneous run.
|
|
47
|
+
- Simplified internal debit-account output allocation to use the fixed-width
|
|
48
|
+
input size directly.
|
|
49
|
+
|
|
50
|
+
## 1.24.0
|
|
51
|
+
|
|
52
|
+
### Breaking Changes
|
|
53
|
+
|
|
54
|
+
- Renamed the existing `Position`-consuming `repay` and `repayPayable`
|
|
55
|
+
commands to `repayPosition` and `repayPositionPayable`. Their state
|
|
56
|
+
transition remains `Position` to `Balance`; the new commands using the old
|
|
57
|
+
names consume `Debt` and return empty state. Command selectors and node IDs
|
|
58
|
+
for position repayment therefore change.
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
|
|
62
|
+
- Added the standalone `Debt { liability, debt }` pipeline state, its standard
|
|
63
|
+
block key and schema, and codec support across blocks, readers, writers,
|
|
64
|
+
decoders, and execution helpers.
|
|
65
|
+
- Added `repay` and `repayPayable` commands that consume `Debt` state and return
|
|
66
|
+
empty state.
|
|
67
|
+
- Added `RepayInternal` for dispatching the non-funded `repay` command directly
|
|
68
|
+
against memory-backed pipeline state.
|
|
69
|
+
- Added unchecked `Blocks.read1`, `read2`, `read8`, and `read16` absolute
|
|
70
|
+
calldata helpers, completing the power-of-two family alongside `read4` and
|
|
71
|
+
`read32`.
|
|
72
|
+
- Added the standalone `ensureContract` utility and shared `InvalidContract`
|
|
73
|
+
error for uniformly requiring addresses with deployed bytecode.
|
|
74
|
+
- Added the free `enforceSender` access helper for requiring an exact
|
|
75
|
+
`msg.sender` with the shared `AccessDenied` error.
|
|
76
|
+
- Documented descriptor flag bits 6 and 7 as endpoint-defined custom flags;
|
|
77
|
+
bits 2 through 5 remain reserved for future protocol flags.
|
|
78
|
+
|
|
79
|
+
### Changed
|
|
80
|
+
|
|
81
|
+
- Repayment commands now publish the canonical `Actions.Repay` annotation
|
|
82
|
+
instead of `Actions.Settle`.
|
|
83
|
+
|
|
6
84
|
## 1.23.0
|
|
7
85
|
|
|
8
86
|
### 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, HostAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Position, Tx } from "./core/Types.sol";
|
|
7
|
+
import { AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Debt, 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, Flags } from "./codec/Descriptors.sol";
|
package/Commands.sol
CHANGED
|
@@ -12,4 +12,4 @@ import {Blocks} from "./codec/Blocks.sol";
|
|
|
12
12
|
import {Sizes, Specs} from "./codec/Specs.sol";
|
|
13
13
|
import {Decoders} from "./codec/Decoders.sol";
|
|
14
14
|
import {Cursors, Cur} from "./utils/Cursors.sol";
|
|
15
|
-
import {AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Position, Tx} from "./core/Types.sol";
|
|
15
|
+
import {AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Debt, 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 { AccessDenied, AdminAccess, CallerAccess, CommanderAccess, CommanderNotAllowed, GuardianAccess, NodeAccess, TrustAccess } from "./core/Access.sol";
|
|
10
|
+
import { AccessDenied, AdminAccess, CallerAccess, CommanderAccess, CommanderNotAllowed, enforceSender, 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
16
|
import { EndpointBase, InputEndpointBase } from "./core/Endpoint.sol";
|
|
17
|
-
import { Pipeline } from "./core/Pipeline.sol";
|
|
17
|
+
import { PipeHook, Pipeline } from "./core/Pipeline.sol";
|
|
18
18
|
import { Budget, Budgets } from "./execution/Budget.sol";
|
|
19
19
|
import { CreditAccountHook, DebitAccountHook, PostHook, RepayHook, SettleHook, Settlement } from "./core/Settlement.sol";
|
|
20
20
|
import { Portal } from "./core/Portal.sol";
|
|
21
|
-
import { AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Position, Tx } from "./core/Types.sol";
|
|
21
|
+
import { AssetAmount, AccountAsset, HostAsset, AccountAmount, HostAmount, HostAccountAsset, HostAccountAmount, Debt, Position, Tx } from "./core/Types.sol";
|
|
22
22
|
import { Validator } from "./core/Validator.sol";
|
|
23
23
|
|
|
24
24
|
|
package/Endpoints.sol
CHANGED
|
@@ -6,6 +6,7 @@ pragma solidity ^0.8.33;
|
|
|
6
6
|
|
|
7
7
|
// Shared endpoint hooks
|
|
8
8
|
import {Flags} from "./codec/Descriptors.sol";
|
|
9
|
+
import {PipeHook} from "./core/Pipeline.sol";
|
|
9
10
|
import {CreditAccountHook, DebitAccountHook, PostHook, RepayHook, SettleHook} from "./core/Settlement.sol";
|
|
10
11
|
|
|
11
12
|
// Commands
|
|
@@ -18,7 +19,14 @@ import {Deposit, DepositHook, DepositPayable, DepositPayableHook} from "./comman
|
|
|
18
19
|
import {Payout, PayoutHook} from "./commands/Payout.sol";
|
|
19
20
|
import {Provision, ProvisionHook, ProvisionPayable, ProvisionPayableHook} from "./commands/Provision.sol";
|
|
20
21
|
import {RecoverPayable, RecoverPayableHook} from "./commands/Recover.sol";
|
|
21
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
Repay,
|
|
24
|
+
RepayInternal,
|
|
25
|
+
RepayPayable,
|
|
26
|
+
RepayPayableHook,
|
|
27
|
+
RepayPosition,
|
|
28
|
+
RepayPositionPayable
|
|
29
|
+
} from "./commands/Repay.sol";
|
|
22
30
|
import {RelayPayable, RelayBalancePayable, RelayPayableHook} from "./commands/Relay.sol";
|
|
23
31
|
import {Settle, SettlePayable, SettlePayableHook, SettleInternal} from "./commands/Settle.sol";
|
|
24
32
|
import {Withdraw, WithdrawHook} from "./commands/Withdraw.sol";
|
package/README.md
CHANGED
|
@@ -265,22 +265,24 @@ and return it, forward it intact, or revert. A command must never succeed while
|
|
|
265
265
|
silently ignoring or dropping supplied state. Commands that declare
|
|
266
266
|
`Specs.Empty` state therefore reject any non-empty state, while commands that
|
|
267
267
|
accept state validate the complete stream against their declared state schema.
|
|
268
|
-
This is especially important for `#position`, because dropping
|
|
269
|
-
silently discard
|
|
270
|
-
|
|
271
|
-
The input carries instructions; the state carries live value. While a
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
268
|
+
This is especially important for `#debt` and `#position`, because dropping
|
|
269
|
+
either could silently discard an outstanding debt requirement.
|
|
270
|
+
|
|
271
|
+
The input carries instructions; the state carries live value. While a sequence
|
|
272
|
+
of commands executes, `#balance`, `#debt`, `#custody`, and `#position` blocks in
|
|
273
|
+
the state are the value being moved — produced by one command, consumed by the
|
|
274
|
+
next. Balance carries `{ asset, amount }`, debt carries `{ liability, debt }`,
|
|
275
|
+
and position carries their flat combination
|
|
275
276
|
`{ asset, amount, liability, debt }`.
|
|
276
277
|
|
|
277
|
-
`#position`
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
278
|
+
`#debt` and `#position` are general live state rather than persisted
|
|
279
|
+
lending-specific debt records. Debt carries value owed or required; position
|
|
280
|
+
pairs that liability with value acquired or controlled. A command may preserve
|
|
281
|
+
or replace either side and return the resulting state for the next step;
|
|
282
|
+
`settle` terminally consumes a position pair. This supports swaps,
|
|
281
283
|
borrowing, refinancing, collateral changes, callback obligations, cross-host
|
|
282
|
-
claims, fees, netting, and other multi-step operations.
|
|
283
|
-
transient
|
|
284
|
+
claims, fees, netting, and other multi-step operations. Debt and position are
|
|
285
|
+
transient representations and do not themselves create or erase an obligation
|
|
284
286
|
recorded by an external system.
|
|
285
287
|
|
|
286
288
|
The standard `Deposit` mixin shows the canonical shape: open and validate both
|
|
@@ -330,7 +332,9 @@ abstract contract MyCommand is CommandBase {
|
|
|
330
332
|
|
|
331
333
|
The final argument is a packed flags byte. Pass `0` for an ordinary endpoint,
|
|
332
334
|
or compose values such as `Flags.Funded`, `Flags.Admin`, and
|
|
333
|
-
`Flags.AdminFunded` from the command or endpoint package entry point.
|
|
335
|
+
`Flags.AdminFunded` from the command or endpoint package entry point. Bits 6
|
|
336
|
+
and 7 are reserved for endpoint-defined custom flags. Bits 2 through 5 remain
|
|
337
|
+
reserved for future protocol flags.
|
|
334
338
|
|
|
335
339
|
The standard commands cover the common ledger movements: `deposit` and
|
|
336
340
|
`depositPayable` (external funds in), `settlePayable` (funded settlement),
|
|
@@ -338,7 +342,9 @@ The standard commands cover the common ledger movements: `deposit` and
|
|
|
338
342
|
`debitAccount` and `creditAccount` (internal movements), `payout` (deliver
|
|
339
343
|
state to other accounts), `allocate` (turn balance state into custody),
|
|
340
344
|
`provision` (provision custody from an external allocation), `settle` (consume
|
|
341
|
-
asset-liability position state), `
|
|
345
|
+
asset-liability position state), `repay` and `repayPayable` (consume standalone
|
|
346
|
+
debt state), `repayPosition` and `repayPositionPayable` (repay a position's debt
|
|
347
|
+
and return its asset as balance state), `relayPayable` (relay a pipeline without
|
|
342
348
|
state), and `relayBalancePayable` (relay balance state and a pipeline to another
|
|
343
349
|
portal).
|
|
344
350
|
|
|
@@ -360,13 +366,15 @@ running the next step. This is the core of `Pipeline.pipe`:
|
|
|
360
366
|
```solidity
|
|
361
367
|
while (cur.more()) {
|
|
362
368
|
(uint cmd, uint resources, bytes calldata input) = cur.unpackStep();
|
|
369
|
+
uint128 value;
|
|
370
|
+
(budget, value) = Budgets.useResourceValue(budget, resources);
|
|
363
371
|
Reader memory transactions;
|
|
364
372
|
(state, transactions.source) = dispatch(
|
|
365
373
|
cmd,
|
|
366
374
|
account,
|
|
367
375
|
state,
|
|
368
376
|
input,
|
|
369
|
-
|
|
377
|
+
value
|
|
370
378
|
);
|
|
371
379
|
while (transactions.more()) {
|
|
372
380
|
(bytes32 from, bytes32 to, bytes32 asset, uint amount) = transactions.unpackTransaction();
|
|
@@ -376,6 +384,9 @@ while (cur.more()) {
|
|
|
376
384
|
if (state.length != 0) revert UnexpectedState();
|
|
377
385
|
```
|
|
378
386
|
|
|
387
|
+
`Pipeline.pipe` takes the available native-value budget as a `uint` and returns
|
|
388
|
+
the remaining budget after every step has executed.
|
|
389
|
+
|
|
379
390
|
A transfer, for instance, is a two-step pipeline: `debitAccount` turns an
|
|
380
391
|
`#amount` input into `#balance` state, and `payout` consumes that state
|
|
381
392
|
toward a recipient. Because a pipeline is just blocks, it is also the unit of
|
|
@@ -384,12 +395,12 @@ portal adapter (on EVM, the low 128 bits are native value in wei, drawn from a
|
|
|
384
395
|
shared budget), so the same pipeline bytes are meaningful to every port.
|
|
385
396
|
|
|
386
397
|
Hosts that implement a pipeline locally can inherit `DebitAccountInternal`,
|
|
387
|
-
`CreditAccountInternal`, and `
|
|
388
|
-
endpoints while routing their local command IDs through
|
|
389
|
-
`executeCreditAccount`,
|
|
390
|
-
memory-backed pipeline state directly
|
|
391
|
-
step value into each adapter; all
|
|
392
|
-
commands are non-funded.
|
|
398
|
+
`CreditAccountInternal`, `SettleInternal`, and `RepayInternal` to advertise the
|
|
399
|
+
canonical command endpoints while routing their local command IDs through
|
|
400
|
+
`executeDebitAccount`, `executeCreditAccount`, `executeSettle`, and
|
|
401
|
+
`executeRepay`. These adapters consume the memory-backed pipeline state directly
|
|
402
|
+
and avoid an external self-call. Pass the step value into each adapter; all four
|
|
403
|
+
reject nonzero value because the commands are non-funded.
|
|
393
404
|
|
|
394
405
|
Positions also support backward-composed pipelines. In an exact-output route,
|
|
395
406
|
the asset side can represent the desired result while the liability side
|
|
@@ -476,11 +487,11 @@ names, access sets, balances — from logs alone, with no artifact files.
|
|
|
476
487
|
Import from the package entry points rather than deep paths:
|
|
477
488
|
|
|
478
489
|
- `@rootzero/contracts/Core.sol` — `Host`, access control, `Balances`,
|
|
479
|
-
`Settlement`, `Pipeline`, `Portal`, validator
|
|
490
|
+
`Settlement`, `PipeHook`, `Pipeline`, `Portal`, validator
|
|
480
491
|
- `@rootzero/contracts/Commands.sol` — `CommandBase`, `Execution`, `Flags`,
|
|
481
492
|
codec helpers, and shared value types for authoring custom commands
|
|
482
493
|
- `@rootzero/contracts/Endpoints.sol` — command, admin, port, guard, and query
|
|
483
|
-
mixins, their hooks, and `Flags`
|
|
494
|
+
mixins, their hooks (including `PipeHook`), and `Flags`
|
|
484
495
|
- `@rootzero/contracts/Codec.sol` — `Blocks`, calldata `Cur`/`Cursors`, memory
|
|
485
496
|
`Reader`/`Readers`, `Writers`, `Schemas`, `Descriptors`, `Flags`, `Keys`, and
|
|
486
497
|
`Specs`
|
package/Utils.sol
CHANGED
|
@@ -12,7 +12,7 @@ import { ECDSA } from "./utils/ECDSA.sol";
|
|
|
12
12
|
import { Ids } from "./utils/Ids.sol";
|
|
13
13
|
import { Nodes } from "./utils/Nodes.sol";
|
|
14
14
|
import { Layout } from "./utils/Layout.sol";
|
|
15
|
-
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";
|
|
15
|
+
import { addrOr, applyBps, beforeBps, bytes32ToInt, bytes32ToString, clear8, clear16, clear32, clear64, divisible, ensureAddr, ensureContract, hash32, intToBytes32, InvalidContract, 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";
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
package/annotations/Schema.sol
CHANGED
|
@@ -18,13 +18,7 @@ abstract contract Schema is Runtime, AnnotationEvent {
|
|
|
18
18
|
/// @param hint Initial per-block payload capacity.
|
|
19
19
|
/// @param body Schema DSL string describing the block payload body.
|
|
20
20
|
/// @return spec The context-local block specification.
|
|
21
|
-
function schema(
|
|
22
|
-
uint32 key,
|
|
23
|
-
uint32 min,
|
|
24
|
-
uint32 max,
|
|
25
|
-
uint32 hint,
|
|
26
|
-
string memory body
|
|
27
|
-
) internal returns (uint spec) {
|
|
21
|
+
function schema(uint32 key, uint32 min, uint32 max, uint32 hint, string memory body) internal returns (uint spec) {
|
|
28
22
|
return schema(key, min, max, hint, body, bytes32(0));
|
|
29
23
|
}
|
|
30
24
|
|
package/codec/Blocks.sol
CHANGED
|
@@ -100,16 +100,33 @@ library Blocks {
|
|
|
100
100
|
end = body + len;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
/// @notice Validate a known block key and return its payload bounds.
|
|
104
|
+
/// @dev DANGER: This performs an unchecked calldata read and validates only
|
|
105
|
+
/// the key. The caller must validate the known payload shape and returned end.
|
|
106
|
+
/// @param abs Absolute calldata position of the header.
|
|
107
|
+
/// @param key Expected block key.
|
|
108
|
+
/// @return body Absolute position of the first payload byte.
|
|
109
|
+
/// @return end Absolute position immediately after the payload.
|
|
110
|
+
function expectKey(uint abs, bytes4 key) internal pure returns (uint body, uint end) {
|
|
111
|
+
uint len = header(abs, key);
|
|
112
|
+
unchecked {
|
|
113
|
+
body = abs + Sizes.Header;
|
|
114
|
+
end = body + len;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
/// @dev Validate the key and exact payload size of a fixed-width block.
|
|
104
119
|
/// @param abs Absolute calldata position of the header.
|
|
105
|
-
/// @param
|
|
120
|
+
/// @param key Expected block key.
|
|
106
121
|
/// @param size Expected payload length.
|
|
107
122
|
/// @return body Absolute position of the payload.
|
|
108
123
|
/// @return end Absolute position after the payload.
|
|
109
|
-
function expectFixed(uint abs,
|
|
110
|
-
if (header(abs,
|
|
111
|
-
|
|
112
|
-
|
|
124
|
+
function expectFixed(uint abs, bytes4 key, uint size) private pure returns (uint body, uint end) {
|
|
125
|
+
if (header(abs, key) != size) revert InvalidBlock();
|
|
126
|
+
unchecked {
|
|
127
|
+
body = abs + Sizes.Header;
|
|
128
|
+
end = body + size;
|
|
129
|
+
}
|
|
113
130
|
}
|
|
114
131
|
|
|
115
132
|
/// @notice Validate an empty block at an absolute calldata position.
|
|
@@ -139,8 +156,9 @@ library Blocks {
|
|
|
139
156
|
/// @param key Expected block key.
|
|
140
157
|
/// @return Whether the expected key occurs with a zero-length payload.
|
|
141
158
|
function isEmpty(uint abs, uint end, bytes4 key) internal pure returns (bool) {
|
|
142
|
-
if (
|
|
143
|
-
|
|
159
|
+
if (abs > end || Sizes.Header > end - abs) return false;
|
|
160
|
+
uint head = uint(read32(abs));
|
|
161
|
+
return uint32(head >> 224) == uint32(key) && uint32(head >> 192) == 0;
|
|
144
162
|
}
|
|
145
163
|
|
|
146
164
|
/// @notice Find the first block with `key` at or after absolute position `abs`.
|
|
@@ -382,6 +400,22 @@ library Blocks {
|
|
|
382
400
|
}
|
|
383
401
|
}
|
|
384
402
|
|
|
403
|
+
/// @notice Write a DEBT block at `i`.
|
|
404
|
+
/// @dev DANGER: Unchecked memory write. Reserve `Sizes.B64` bytes first.
|
|
405
|
+
/// @param dst Destination buffer.
|
|
406
|
+
/// @param i Relative write position.
|
|
407
|
+
/// @param liability Liability identifier to encode.
|
|
408
|
+
/// @param debt Debt quantity to encode.
|
|
409
|
+
function writeDebt(bytes memory dst, uint i, bytes32 liability, uint debt) internal pure {
|
|
410
|
+
uint spec = Specs.Debt;
|
|
411
|
+
assembly ("memory-safe") {
|
|
412
|
+
let p := add(add(dst, 0x20), i)
|
|
413
|
+
mstore(p, spec)
|
|
414
|
+
mstore(add(p, 0x08), liability)
|
|
415
|
+
mstore(add(p, 0x28), debt)
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
385
419
|
/// @notice Write a HOST_ASSET block at `i`.
|
|
386
420
|
/// @dev DANGER: Unchecked memory write. Reserve `Sizes.B64` bytes first.
|
|
387
421
|
/// @param dst Destination buffer.
|
|
@@ -1014,14 +1048,44 @@ library Blocks {
|
|
|
1014
1048
|
|
|
1015
1049
|
// Raw reads
|
|
1016
1050
|
|
|
1051
|
+
/// @notice Read one byte from an absolute calldata position.
|
|
1052
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1053
|
+
/// @param abs Absolute calldata position.
|
|
1054
|
+
/// @return value Decoded one-byte value.
|
|
1055
|
+
function read1(uint abs) internal pure returns (bytes1 value) {
|
|
1056
|
+
return bytes1(read32(abs));
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/// @notice Read two bytes from an absolute calldata position.
|
|
1060
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1061
|
+
/// @param abs Absolute calldata position.
|
|
1062
|
+
/// @return value Decoded two-byte value.
|
|
1063
|
+
function read2(uint abs) internal pure returns (bytes2 value) {
|
|
1064
|
+
return bytes2(read32(abs));
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1017
1067
|
/// @notice Read four bytes from an absolute calldata position.
|
|
1018
1068
|
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1019
1069
|
/// @param abs Absolute calldata position.
|
|
1020
1070
|
/// @return value Decoded four-byte value.
|
|
1021
1071
|
function read4(uint abs) internal pure returns (bytes4 value) {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1072
|
+
return bytes4(read32(abs));
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/// @notice Read eight bytes from an absolute calldata position.
|
|
1076
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1077
|
+
/// @param abs Absolute calldata position.
|
|
1078
|
+
/// @return value Decoded eight-byte value.
|
|
1079
|
+
function read8(uint abs) internal pure returns (bytes8 value) {
|
|
1080
|
+
return bytes8(read32(abs));
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/// @notice Read sixteen bytes from an absolute calldata position.
|
|
1084
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1085
|
+
/// @param abs Absolute calldata position.
|
|
1086
|
+
/// @return value Decoded sixteen-byte value.
|
|
1087
|
+
function read16(uint abs) internal pure returns (bytes16 value) {
|
|
1088
|
+
return bytes16(read32(abs));
|
|
1025
1089
|
}
|
|
1026
1090
|
|
|
1027
1091
|
/// @notice Read one word from an absolute calldata position.
|
|
@@ -1034,6 +1098,46 @@ library Blocks {
|
|
|
1034
1098
|
}
|
|
1035
1099
|
}
|
|
1036
1100
|
|
|
1101
|
+
/// @notice Require the byte at an absolute calldata position to match `expected`.
|
|
1102
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1103
|
+
/// @param abs Absolute calldata position.
|
|
1104
|
+
/// @param expected Expected byte.
|
|
1105
|
+
function require1(uint abs, bytes1 expected) internal pure {
|
|
1106
|
+
if (read1(abs) != expected) revert UnexpectedValue();
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/// @notice Require the two bytes at an absolute calldata position to match `expected`.
|
|
1110
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1111
|
+
/// @param abs Absolute calldata position.
|
|
1112
|
+
/// @param expected Expected two-byte value.
|
|
1113
|
+
function require2(uint abs, bytes2 expected) internal pure {
|
|
1114
|
+
if (read2(abs) != expected) revert UnexpectedValue();
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
/// @notice Require the four bytes at an absolute calldata position to match `expected`.
|
|
1118
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1119
|
+
/// @param abs Absolute calldata position.
|
|
1120
|
+
/// @param expected Expected four-byte value.
|
|
1121
|
+
function require4(uint abs, bytes4 expected) internal pure {
|
|
1122
|
+
if (read4(abs) != expected) revert UnexpectedValue();
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/// @notice Require the eight bytes at an absolute calldata position to match `expected`.
|
|
1126
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1127
|
+
/// @param abs Absolute calldata position.
|
|
1128
|
+
/// @param expected Expected eight-byte value.
|
|
1129
|
+
function require8(uint abs, bytes8 expected) internal pure {
|
|
1130
|
+
if (read8(abs) != expected) revert UnexpectedValue();
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
/// @notice Require the sixteen bytes at an absolute calldata position to match `expected`.
|
|
1134
|
+
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1135
|
+
/// @param abs Absolute calldata position.
|
|
1136
|
+
/// @param expected Expected sixteen-byte value.
|
|
1137
|
+
function require16(uint abs, bytes16 expected) internal pure {
|
|
1138
|
+
if (read16(abs) != expected) revert UnexpectedValue();
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1037
1141
|
/// @notice Require the word at an absolute calldata position to match `expected`.
|
|
1038
1142
|
/// @dev DANGER: Unchecked calldata read. Values beyond calldata are zero-padded.
|
|
1039
1143
|
/// @param abs Absolute calldata position.
|
|
@@ -1060,7 +1164,7 @@ library Blocks {
|
|
|
1060
1164
|
/// @return a First payload word.
|
|
1061
1165
|
/// @return end Absolute position after the block.
|
|
1062
1166
|
function unpack32(uint abs, uint spec) internal pure returns (bytes32 a, uint end) {
|
|
1063
|
-
(abs, end) = expectFixed(abs, spec, 32);
|
|
1167
|
+
(abs, end) = expectFixed(abs, Specs.key(spec), 32);
|
|
1064
1168
|
a = read32(abs);
|
|
1065
1169
|
}
|
|
1066
1170
|
|
|
@@ -1071,7 +1175,7 @@ library Blocks {
|
|
|
1071
1175
|
/// @return b Second payload word.
|
|
1072
1176
|
/// @return end Absolute position after the block.
|
|
1073
1177
|
function unpack64(uint abs, uint spec) internal pure returns (bytes32 a, bytes32 b, uint end) {
|
|
1074
|
-
(abs, end) = expectFixed(abs, spec, 64);
|
|
1178
|
+
(abs, end) = expectFixed(abs, Specs.key(spec), 64);
|
|
1075
1179
|
assembly ("memory-safe") {
|
|
1076
1180
|
a := calldataload(abs)
|
|
1077
1181
|
b := calldataload(add(abs, 0x20))
|
|
@@ -1089,7 +1193,7 @@ library Blocks {
|
|
|
1089
1193
|
uint abs,
|
|
1090
1194
|
uint spec
|
|
1091
1195
|
) internal pure returns (bytes32 a, bytes32 b, bytes32 c, uint end) {
|
|
1092
|
-
(abs, end) = expectFixed(abs, spec, 96);
|
|
1196
|
+
(abs, end) = expectFixed(abs, Specs.key(spec), 96);
|
|
1093
1197
|
assembly ("memory-safe") {
|
|
1094
1198
|
a := calldataload(abs)
|
|
1095
1199
|
b := calldataload(add(abs, 0x20))
|
|
@@ -1109,7 +1213,7 @@ library Blocks {
|
|
|
1109
1213
|
uint abs,
|
|
1110
1214
|
uint spec
|
|
1111
1215
|
) internal pure returns (bytes32 a, bytes32 b, bytes32 c, bytes32 d, uint end) {
|
|
1112
|
-
(abs, end) = expectFixed(abs, spec, 128);
|
|
1216
|
+
(abs, end) = expectFixed(abs, Specs.key(spec), 128);
|
|
1113
1217
|
assembly ("memory-safe") {
|
|
1114
1218
|
a := calldataload(abs)
|
|
1115
1219
|
b := calldataload(add(abs, 0x20))
|
|
@@ -1131,7 +1235,7 @@ library Blocks {
|
|
|
1131
1235
|
uint abs,
|
|
1132
1236
|
uint spec
|
|
1133
1237
|
) internal pure returns (bytes32 a, bytes32 b, bytes32 c, bytes32 d, bytes32 e, uint end) {
|
|
1134
|
-
(abs, end) = expectFixed(abs, spec, 160);
|
|
1238
|
+
(abs, end) = expectFixed(abs, Specs.key(spec), 160);
|
|
1135
1239
|
assembly ("memory-safe") {
|
|
1136
1240
|
a := calldataload(abs)
|
|
1137
1241
|
b := calldataload(add(abs, 0x20))
|
|
@@ -1322,6 +1426,22 @@ library Blocks {
|
|
|
1322
1426
|
}
|
|
1323
1427
|
}
|
|
1324
1428
|
|
|
1429
|
+
/// @notice Decode a low-level fixed-width DEBT block at `abs`.
|
|
1430
|
+
/// @param abs Absolute block position.
|
|
1431
|
+
/// @return liability Decoded liability identifier.
|
|
1432
|
+
/// @return debt Decoded debt quantity.
|
|
1433
|
+
function unpackDebt(uint abs) internal pure returns (bytes32 liability, uint debt) {
|
|
1434
|
+
uint head;
|
|
1435
|
+
assembly ("memory-safe") {
|
|
1436
|
+
head := calldataload(abs)
|
|
1437
|
+
}
|
|
1438
|
+
if (head >> 192 != Specs.Debt >> 192) revert InvalidBlock();
|
|
1439
|
+
assembly ("memory-safe") {
|
|
1440
|
+
liability := calldataload(add(abs, 0x08))
|
|
1441
|
+
debt := calldataload(add(abs, 0x28))
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1325
1445
|
/// @notice Decode a low-level fixed-width ACCOUNT_ASSET block at `abs`.
|
|
1326
1446
|
/// @param abs Absolute block position.
|
|
1327
1447
|
/// @return account Decoded account identifier.
|
|
@@ -1591,7 +1711,7 @@ library Blocks {
|
|
|
1591
1711
|
uint abs
|
|
1592
1712
|
) internal pure returns (uint entity, bytes calldata stream, uint end) {
|
|
1593
1713
|
uint limit;
|
|
1594
|
-
(abs, limit) =
|
|
1714
|
+
(abs, limit) = expectKey(abs, Keys.Annotation);
|
|
1595
1715
|
assembly ("memory-safe") {
|
|
1596
1716
|
entity := calldataload(abs)
|
|
1597
1717
|
}
|
|
@@ -1609,7 +1729,7 @@ library Blocks {
|
|
|
1609
1729
|
uint abs
|
|
1610
1730
|
) internal pure returns (bytes32 account, bytes calldata state, bytes calldata input, uint end) {
|
|
1611
1731
|
uint limit;
|
|
1612
|
-
(abs, limit) =
|
|
1732
|
+
(abs, limit) = expectKey(abs, Keys.Context);
|
|
1613
1733
|
assembly ("memory-safe") {
|
|
1614
1734
|
account := calldataload(abs)
|
|
1615
1735
|
}
|
|
@@ -1630,7 +1750,7 @@ library Blocks {
|
|
|
1630
1750
|
uint abs
|
|
1631
1751
|
) internal pure returns (uint cmd, uint resources, bytes calldata input, uint end) {
|
|
1632
1752
|
uint limit;
|
|
1633
|
-
(abs, limit) =
|
|
1753
|
+
(abs, limit) = expectKey(abs, Keys.Step);
|
|
1634
1754
|
assembly ("memory-safe") {
|
|
1635
1755
|
cmd := calldataload(abs)
|
|
1636
1756
|
resources := calldataload(add(abs, 0x20))
|
|
@@ -1649,7 +1769,7 @@ library Blocks {
|
|
|
1649
1769
|
uint abs
|
|
1650
1770
|
) internal pure returns (uint target, uint resources, bytes calldata payload, uint end) {
|
|
1651
1771
|
uint limit;
|
|
1652
|
-
(abs, limit) =
|
|
1772
|
+
(abs, limit) = expectKey(abs, Keys.Call);
|
|
1653
1773
|
assembly ("memory-safe") {
|
|
1654
1774
|
target := calldataload(abs)
|
|
1655
1775
|
resources := calldataload(add(abs, 0x20))
|
|
@@ -1668,7 +1788,7 @@ library Blocks {
|
|
|
1668
1788
|
uint abs
|
|
1669
1789
|
) internal pure returns (uint portal, uint resources, bytes calldata input, uint end) {
|
|
1670
1790
|
uint limit;
|
|
1671
|
-
(abs, limit) =
|
|
1791
|
+
(abs, limit) = expectKey(abs, Keys.Relay);
|
|
1672
1792
|
assembly ("memory-safe") {
|
|
1673
1793
|
portal := calldataload(abs)
|
|
1674
1794
|
resources := calldataload(add(abs, 0x20))
|
|
@@ -1687,7 +1807,7 @@ library Blocks {
|
|
|
1687
1807
|
uint abs
|
|
1688
1808
|
) internal pure returns (uint portal, uint resources, bytes calldata payload, uint end) {
|
|
1689
1809
|
uint limit;
|
|
1690
|
-
(abs, limit) =
|
|
1810
|
+
(abs, limit) = expectKey(abs, Keys.Dispatch);
|
|
1691
1811
|
assembly ("memory-safe") {
|
|
1692
1812
|
portal := calldataload(abs)
|
|
1693
1813
|
resources := calldataload(add(abs, 0x20))
|
|
@@ -1703,7 +1823,7 @@ library Blocks {
|
|
|
1703
1823
|
/// @return end Absolute position after the block.
|
|
1704
1824
|
function unpackLabel(uint abs) internal pure returns (bytes32 namespace, string memory name, uint end) {
|
|
1705
1825
|
uint limit;
|
|
1706
|
-
(abs, limit) =
|
|
1826
|
+
(abs, limit) = expectKey(abs, Keys.Label);
|
|
1707
1827
|
assembly ("memory-safe") {
|
|
1708
1828
|
namespace := calldataload(abs)
|
|
1709
1829
|
}
|
|
@@ -1721,7 +1841,7 @@ library Blocks {
|
|
|
1721
1841
|
/// @return end Absolute position after the block.
|
|
1722
1842
|
function unpackSchema(uint abs) internal pure returns (uint spec, string memory body, bytes32 name, uint end) {
|
|
1723
1843
|
uint limit;
|
|
1724
|
-
(abs, limit) =
|
|
1844
|
+
(abs, limit) = expectKey(abs, Keys.Schema);
|
|
1725
1845
|
assembly ("memory-safe") {
|
|
1726
1846
|
spec := calldataload(abs)
|
|
1727
1847
|
}
|
|
@@ -1748,7 +1868,7 @@ library Blocks {
|
|
|
1748
1868
|
uint abs
|
|
1749
1869
|
) internal pure returns (uint handler, uint resources, bytes32 key, bytes calldata witness, uint end) {
|
|
1750
1870
|
uint limit;
|
|
1751
|
-
(abs, limit) =
|
|
1871
|
+
(abs, limit) = expectKey(abs, Keys.Recover);
|
|
1752
1872
|
assembly ("memory-safe") {
|
|
1753
1873
|
handler := calldataload(abs)
|
|
1754
1874
|
resources := calldataload(add(abs, 0x20))
|
|
@@ -1919,6 +2039,15 @@ library Blocks {
|
|
|
1919
2039
|
writeBalance(value, 0, asset, amount);
|
|
1920
2040
|
}
|
|
1921
2041
|
|
|
2042
|
+
/// @notice Encode a DEBT block.
|
|
2043
|
+
/// @param liability Liability identifier.
|
|
2044
|
+
/// @param debt Debt quantity.
|
|
2045
|
+
/// @return value Encoded DEBT block bytes.
|
|
2046
|
+
function createDebt(bytes32 liability, uint debt) internal pure returns (bytes memory value) {
|
|
2047
|
+
value = allocate(Sizes.Debt);
|
|
2048
|
+
writeDebt(value, 0, liability, debt);
|
|
2049
|
+
}
|
|
2050
|
+
|
|
1922
2051
|
/// @notice Encode a CUSTODY block.
|
|
1923
2052
|
/// @param host Host node ID holding the custody.
|
|
1924
2053
|
/// @param asset Asset identifier.
|