@rootzero/contracts 1.22.0 → 1.23.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 (44) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/Endpoints.sol +2 -3
  3. package/Events.sol +1 -1
  4. package/README.md +13 -11
  5. package/annotations/Action.sol +1 -1
  6. package/annotations/Label.sol +1 -1
  7. package/annotations/Schema.sol +1 -1
  8. package/codec/Blocks.sol +39 -30
  9. package/commands/Allocate.sol +5 -8
  10. package/commands/Base.sol +29 -13
  11. package/commands/Burn.sol +5 -7
  12. package/commands/Credit.sol +5 -7
  13. package/commands/Debit.sol +5 -7
  14. package/commands/Deposit.sol +10 -14
  15. package/commands/Payout.sol +5 -8
  16. package/commands/Provision.sol +10 -14
  17. package/commands/Recover.sol +4 -6
  18. package/commands/Relay.sol +14 -21
  19. package/commands/Repay.sol +10 -14
  20. package/commands/Settle.sol +10 -14
  21. package/commands/Withdraw.sol +5 -7
  22. package/commands/admin/AllowAssets.sol +5 -7
  23. package/commands/admin/Allowance.sol +5 -7
  24. package/commands/admin/Annotate.sol +5 -7
  25. package/commands/admin/Appoint.sol +5 -7
  26. package/commands/admin/Authorize.sol +5 -7
  27. package/commands/admin/Base.sol +12 -3
  28. package/commands/admin/DenyAssets.sol +5 -7
  29. package/commands/admin/Dismiss.sol +5 -7
  30. package/commands/admin/Execute.sol +5 -7
  31. package/commands/admin/Unauthorize.sol +5 -7
  32. package/core/Calls.sol +72 -3
  33. package/core/Portal.sol +2 -2
  34. package/events/Positioned.sol +22 -0
  35. package/execution/Execution.sol +42 -0
  36. package/package.json +1 -1
  37. package/ports/Allowance.sol +22 -12
  38. package/ports/Assets.sol +99 -0
  39. package/utils/Cursors.sol +3 -3
  40. package/utils/Nodes.sol +1 -1
  41. package/utils/Utils.sol +31 -31
  42. package/events/Commander.sol +0 -19
  43. package/ports/AllowAssets.sol +0 -34
  44. package/ports/DenyAssets.sol +0 -34
package/CHANGELOG.md CHANGED
@@ -3,6 +3,74 @@
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.23.0
7
+
8
+ ### Breaking Changes
9
+
10
+ - Changed every command entrypoint from
11
+ `(bytes32 account, bytes state, bytes input)` to one `bytes context` argument
12
+ containing exactly one encoded `CONTEXT` block. Canonical command selectors
13
+ now use `(bytes)`, so every command node ID changes. Existing command callers,
14
+ cached IDs, and deployed host graphs are not compatible with this release.
15
+ - Added the acting account to `Execution`. `CommandBase.openCommand` and
16
+ `AdminBase.openAdminCommand` now accept the encoded context and return only
17
+ the initialized execution, and command implementations close with
18
+ `closeCommand(exec)` instead of `close(exec, account)`.
19
+ - Removed the separate state argument from `RelayPayableHook.relay`. Relay
20
+ implementations can obtain the complete validated state with
21
+ `exec.rawState()` while the explicit account and nested relay input arguments
22
+ remain unchanged.
23
+ - Consolidated `AllowAssetsPort` and `DenyAssetsPort` into
24
+ `ports/Assets.sol`; update direct source imports to the new path.
25
+ - Renamed the peer `AllowancePort` and `portAllowance` selector to
26
+ `RequestAllowancePort` and `portRequestAllowance`. The peer port now uses a
27
+ distinct `RequestAllowanceHook.requestAllowance` hook; the admin `Allowance`
28
+ command and its authoritative `AllowanceHook.allowance` hook are unchanged.
29
+ - Removed the `Commander` event declaration. Commander addresses and chain
30
+ context are off-chain configuration; host, native-asset, and admin IDs are
31
+ deterministic from that information.
32
+ - Prefixed every typed `Blocks` factory with `create`, including calldata-copy
33
+ variants; for example, use `createBalance`, `createStepCopy`, `createBytes`,
34
+ and `createString` instead of `balance`, `stepCopy`, `data`, and `text`.
35
+ - Changed the `max8`, `max16`, `max24`, `max32`, `max40`, `max64`, `max96`,
36
+ `max128`, and `max160` bounds helpers to return their corresponding narrowed
37
+ integer types instead of `uint`.
38
+
39
+ ### Added
40
+
41
+ - Added `PositionedEvent`, which publishes asset and liability sides together
42
+ with the semantic action that produced the observed position.
43
+ - Added `RequestAssetPort`, which passes trusted peers' batched asset and amount
44
+ requests to a host hook for validation and fulfillment.
45
+ - Added `Executions.takeBlock`, which validates and consumes a block from a
46
+ selected decoder lane and returns its complete calldata encoding.
47
+ - Added `Executions.rawState` and `Executions.rawInput` for retrieving complete
48
+ validated calldata lanes independently of current cursor progress.
49
+ - Added `Blocks.createAmount` for constructing canonical `AMOUNT` blocks.
50
+
51
+ ### Changed
52
+
53
+ - Command pipeline hops now construct `command(bytes)` calldata and the nested
54
+ `CONTEXT` block directly in one allocation, copying memory state and calldata
55
+ input into the final call buffer.
56
+ - Added memory `callPort`/`tryCallPort` helpers and calldata-copy
57
+ `callPortCopy`/`tryCallPortCopy` counterparts, matching the block factory
58
+ naming convention. Portal forwarding and recovery use the copy variants.
59
+
60
+ ### Upgrade Compatibility
61
+
62
+ - Rebuild command IDs from the new `(bytes)` selectors, redeploy command hosts,
63
+ and update pipeline builders and other callers to pass one encoded `CONTEXT`
64
+ block. Do not mix 1.22 command IDs or callers with 1.23 deployments.
65
+ - Update custom commands to read the acting account from `exec.account`, use
66
+ `openCommand(context, descriptor, batches)`, and return
67
+ `closeCommand(exec)`.
68
+ - Update relay hook implementations to remove the state parameter and use
69
+ `exec.rawState()` when the forwarded state is required.
70
+ - Update direct port imports, renamed request-allowance endpoints and hooks,
71
+ typed `Blocks` factory calls, and any assignments that relied on `max*`
72
+ returning `uint`.
73
+
6
74
  ## 1.22.0
7
75
 
8
76
  ### Breaking Changes
package/Endpoints.sol CHANGED
@@ -37,12 +37,11 @@ import {Unauthorize} from "./commands/admin/Unauthorize.sol";
37
37
 
38
38
  // Port endpoints
39
39
  import {PortBase} from "./ports/Base.sol";
40
- import {AllowAssetsPort} from "./ports/AllowAssets.sol";
41
- import {AllowancePort} from "./ports/Allowance.sol";
40
+ import {AllowAssetsPort, DenyAssetsPort, RequestAssetPort, RequestAssetHook} from "./ports/Assets.sol";
41
+ import {RequestAllowancePort, RequestAllowanceHook} from "./ports/Allowance.sol";
42
42
  import {RedeemBalancePort, RedeemBalanceHook} from "./ports/Redeem.sol";
43
43
  import {CreditAccountPort} from "./ports/Credit.sol";
44
44
  import {DebitAccountPort} from "./ports/Debit.sol";
45
- import {DenyAssetsPort} from "./ports/DenyAssets.sol";
46
45
  import {PipePayablePort} from "./ports/Pipe.sol";
47
46
  import {DispatchPayablePort, DispatchPayableHook} from "./ports/Dispatch.sol";
48
47
  import {PostPort} from "./ports/Post.sol";
package/Events.sol CHANGED
@@ -8,7 +8,6 @@ import { AnnotationEvent } from "./events/Annotation.sol";
8
8
  import { AssetEvent, AssetStatusEvent } from "./events/Asset.sol";
9
9
  import { Actions } from "./utils/Actions.sol";
10
10
  import { BalanceEvent } from "./events/Balance.sol";
11
- import { CommanderEvent } from "./events/Commander.sol";
12
11
  import { DispatchEvent } from "./events/Dispatch.sol";
13
12
  import { EndpointEvent } from "./events/Endpoint.sol";
14
13
  import { ReceivedEvent } from "./events/Received.sol";
@@ -19,6 +18,7 @@ import { GuardianEvent } from "./events/Guardian.sol";
19
18
  import { IntroductionEvent } from "./events/Introduction.sol";
20
19
  import { LockedEvent } from "./events/Locked.sol";
21
20
  import { NodeEvent } from "./events/Node.sol";
21
+ import { PositionedEvent } from "./events/Positioned.sol";
22
22
  import { RootedEvent } from "./events/Rooted.sol";
23
23
  import { RouteEvent } from "./events/Route.sol";
24
24
  import { SpentEvent } from "./events/Spent.sol";
package/README.md CHANGED
@@ -288,19 +288,17 @@ command lanes, loop the batch, call the hook, and write the output run:
288
288
 
289
289
  ```solidity
290
290
  function deposit(
291
- bytes32 account,
292
- bytes calldata state,
293
- bytes calldata input
291
+ bytes calldata context
294
292
  ) external onlyCommand returns (bytes memory, bytes memory) {
295
- Execution memory exec = openCommand(state, input, descriptor, 0);
293
+ Execution memory exec = openCommand(context, descriptor, 0);
296
294
 
297
295
  while (exec.more()) {
298
296
  (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
299
- deposit(account, asset, amount); // host policy hook
297
+ deposit(exec.account, asset, amount); // host policy hook
300
298
  exec.outputBalance(asset, amount);
301
299
  }
302
300
 
303
- return close(exec, account);
301
+ return closeCommand(exec);
304
302
  }
305
303
  ```
306
304
 
@@ -317,17 +315,15 @@ abstract contract MyCommand is CommandBase {
317
315
  }
318
316
 
319
317
  function myCommand(
320
- bytes32 account,
321
- bytes calldata state,
322
- bytes calldata input
318
+ bytes calldata context
323
319
  ) external onlyCommand returns (bytes memory, bytes memory) {
324
- Execution memory exec = openCommand(state, input, descriptor, 0);
320
+ Execution memory exec = openCommand(context, descriptor, 0);
325
321
  while (exec.more()) {
326
322
  (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
327
323
  // Apply command-specific behavior for this group.
328
324
  exec.outputBalance(asset, amount);
329
325
  }
330
- return close(exec, account);
326
+ return closeCommand(exec);
331
327
  }
332
328
  }
333
329
  ```
@@ -435,6 +431,12 @@ central ones are batches all the way down:
435
431
  - `portPost` consumes `transaction { bytes32 from, bytes32 to, bytes32 asset,
436
432
  uint amount }` blocks, debiting `from` and crediting `to` per
437
433
  block — how two hosts post transactions between their ledgers.
434
+ - `portRequestAsset` consumes `amount { bytes32 asset, uint amount }` blocks and
435
+ passes the authenticated peer, asset, and amount to a host hook. The hook
436
+ validates asset support and applies the host's request and transfer policy.
437
+ - `portRequestAllowance` consumes the same amount blocks and lets the
438
+ authenticated peer request an asset allowance. The hook decides what
439
+ allowance, if any, to grant.
438
440
  - `portPipePayable` consumes `context` blocks, each carrying an account, an
439
441
  initial state, and a run of steps — a complete pipeline delivered by another
440
442
  host, executed locally against the port call's shared value budget.
@@ -12,6 +12,6 @@ abstract contract Action is AnnotationEvent {
12
12
  /// @param entity Entity receiving the action annotation.
13
13
  /// @param value Canonical action identifier, such as a value from `Actions`.
14
14
  function action(uint entity, uint value) internal virtual {
15
- emit Annotation(entity, Blocks.action(value));
15
+ emit Annotation(entity, Blocks.createAction(value));
16
16
  }
17
17
  }
@@ -14,6 +14,6 @@ abstract contract Label is AnnotationEvent {
14
14
  /// @param namespace Label namespace.
15
15
  /// @param name Human-readable name within the namespace.
16
16
  function label(uint entity, bytes32 namespace, string memory name) internal virtual {
17
- emit Annotation(entity, Blocks.label(namespace, name));
17
+ emit Annotation(entity, Blocks.createLabel(namespace, name));
18
18
  }
19
19
  }
@@ -80,7 +80,7 @@ abstract contract Schema is Runtime, AnnotationEvent {
80
80
  /// @param name Schema alias name, or zero for unnamed schemas.
81
81
  /// @return The published block specification.
82
82
  function schema(uint spec, string memory body, bytes32 name) internal returns (uint) {
83
- emit Annotation(host, Blocks.schema(spec, body, name));
83
+ emit Annotation(host, Blocks.createSchema(spec, body, name));
84
84
  return spec;
85
85
  }
86
86
  }
package/codec/Blocks.sol CHANGED
@@ -1776,7 +1776,7 @@ library Blocks {
1776
1776
  /// @notice Encode an empty block.
1777
1777
  /// @param key Block type key.
1778
1778
  /// @return value Encoded empty block header.
1779
- function empty(bytes4 key) internal pure returns (bytes memory value) {
1779
+ function createEmpty(bytes4 key) internal pure returns (bytes memory value) {
1780
1780
  value = allocate(Sizes.Header);
1781
1781
  writeEmpty(value, 0, key);
1782
1782
  }
@@ -1801,28 +1801,28 @@ library Blocks {
1801
1801
  // Dynamic leaf factories
1802
1802
 
1803
1803
  /// @notice Encode a LIST block.
1804
- function list(bytes memory value) internal pure returns (bytes memory blockdata) {
1804
+ function createList(bytes memory value) internal pure returns (bytes memory blockdata) {
1805
1805
  uint len = max32(value.length);
1806
1806
  blockdata = allocate(Sizes.Header + len);
1807
1807
  writeList(blockdata, 0, value);
1808
1808
  }
1809
1809
 
1810
1810
  /// @notice Encode a LIST block by copying its payload from calldata.
1811
- function listCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
1811
+ function createListCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
1812
1812
  uint len = max32(value.length);
1813
1813
  blockdata = allocate(Sizes.Header + len);
1814
1814
  copyList(blockdata, 0, value);
1815
1815
  }
1816
1816
 
1817
1817
  /// @notice Encode an EVM block.
1818
- function evm(bytes memory value) internal pure returns (bytes memory blockdata) {
1818
+ function createEvm(bytes memory value) internal pure returns (bytes memory blockdata) {
1819
1819
  uint len = max32(value.length);
1820
1820
  blockdata = allocate(Sizes.Header + len);
1821
1821
  writeEvm(blockdata, 0, value);
1822
1822
  }
1823
1823
 
1824
1824
  /// @notice Encode an EVM block by copying its payload from calldata.
1825
- function evmCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
1825
+ function createEvmCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
1826
1826
  uint len = max32(value.length);
1827
1827
  blockdata = allocate(Sizes.Header + len);
1828
1828
  copyEvm(blockdata, 0, value);
@@ -1831,14 +1831,14 @@ library Blocks {
1831
1831
  /// @notice Encode a BYTES block with a raw payload.
1832
1832
  /// @param value Raw payload bytes.
1833
1833
  /// @return blockdata Encoded BYTES block bytes.
1834
- function data(bytes memory value) internal pure returns (bytes memory blockdata) {
1834
+ function createBytes(bytes memory value) internal pure returns (bytes memory blockdata) {
1835
1835
  uint len = max32(value.length);
1836
1836
  blockdata = allocate(Sizes.Header + len);
1837
1837
  writeBytes(blockdata, 0, value);
1838
1838
  }
1839
1839
 
1840
1840
  /// @notice Encode a BYTES block by copying its payload from calldata.
1841
- function dataCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
1841
+ function createBytesCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
1842
1842
  uint len = max32(value.length);
1843
1843
  blockdata = allocate(Sizes.Header + len);
1844
1844
  copyBytes(blockdata, 0, value);
@@ -1847,14 +1847,14 @@ library Blocks {
1847
1847
  /// @notice Encode a STRING block with a UTF-8 payload.
1848
1848
  /// @param value String payload.
1849
1849
  /// @return blockdata Encoded STRING block bytes.
1850
- function text(string memory value) internal pure returns (bytes memory blockdata) {
1850
+ function createString(string memory value) internal pure returns (bytes memory blockdata) {
1851
1851
  uint len = max32(bytes(value).length);
1852
1852
  blockdata = allocate(Sizes.Header + len);
1853
1853
  writeString(blockdata, 0, value);
1854
1854
  }
1855
1855
 
1856
1856
  /// @notice Encode a STRING block by copying its payload from calldata.
1857
- function textCopy(string calldata value) internal pure returns (bytes memory blockdata) {
1857
+ function createStringCopy(string calldata value) internal pure returns (bytes memory blockdata) {
1858
1858
  uint len = max32(bytes(value).length);
1859
1859
  blockdata = allocate(Sizes.Header + len);
1860
1860
  copyString(blockdata, 0, value);
@@ -1866,7 +1866,7 @@ library Blocks {
1866
1866
  /// @param namespace Label namespace.
1867
1867
  /// @param name Label text.
1868
1868
  /// @return value Encoded LABEL block bytes.
1869
- function label(bytes32 namespace, string memory name) internal pure returns (bytes memory value) {
1869
+ function createLabel(bytes32 namespace, string memory name) internal pure returns (bytes memory value) {
1870
1870
  uint len = max32(Sizes.B32 + bytes(name).length);
1871
1871
  value = allocate(Sizes.Header + len);
1872
1872
  writeLabel(value, 0, namespace, name);
@@ -1875,7 +1875,7 @@ library Blocks {
1875
1875
  /// @notice Encode an ACTION annotation block.
1876
1876
  /// @param actionid Canonical semantic action identifier.
1877
1877
  /// @return value Encoded ACTION block bytes.
1878
- function action(uint actionid) internal pure returns (bytes memory value) {
1878
+ function createAction(uint actionid) internal pure returns (bytes memory value) {
1879
1879
  value = allocate(Sizes.B32);
1880
1880
  write32(value, 0, Keys.Action, bytes32(actionid));
1881
1881
  }
@@ -1884,8 +1884,8 @@ library Blocks {
1884
1884
  /// @param spec Block specification.
1885
1885
  /// @param body Schema body.
1886
1886
  /// @return value Encoded SCHEMA block bytes.
1887
- function schema(uint spec, string memory body) internal pure returns (bytes memory value) {
1888
- return schema(spec, body, bytes32(0));
1887
+ function createSchema(uint spec, string memory body) internal pure returns (bytes memory value) {
1888
+ return createSchema(spec, body, bytes32(0));
1889
1889
  }
1890
1890
 
1891
1891
  /// @notice Encode a named SCHEMA block.
@@ -1893,7 +1893,7 @@ library Blocks {
1893
1893
  /// @param body Schema body.
1894
1894
  /// @param name Schema name.
1895
1895
  /// @return value Encoded SCHEMA block bytes.
1896
- function schema(uint spec, string memory body, bytes32 name) internal pure returns (bytes memory value) {
1896
+ function createSchema(uint spec, string memory body, bytes32 name) internal pure returns (bytes memory value) {
1897
1897
  uint len = max32(Sizes.B64 + bytes(body).length);
1898
1898
  value = allocate(Sizes.Header + len);
1899
1899
  writeSchema(value, 0, spec, body, name);
@@ -1901,11 +1901,20 @@ library Blocks {
1901
1901
 
1902
1902
  // Fixed-width factories
1903
1903
 
1904
+ /// @notice Encode an AMOUNT block.
1905
+ /// @param asset Asset identifier.
1906
+ /// @param amount Token amount.
1907
+ /// @return value Encoded AMOUNT block bytes.
1908
+ function createAmount(bytes32 asset, uint amount) internal pure returns (bytes memory value) {
1909
+ value = allocate(Sizes.Amount);
1910
+ writeAmount(value, 0, asset, amount);
1911
+ }
1912
+
1904
1913
  /// @notice Encode a BALANCE block.
1905
1914
  /// @param asset Asset identifier.
1906
1915
  /// @param amount Token amount.
1907
1916
  /// @return value Encoded BALANCE block bytes.
1908
- function balance(bytes32 asset, uint amount) internal pure returns (bytes memory value) {
1917
+ function createBalance(bytes32 asset, uint amount) internal pure returns (bytes memory value) {
1909
1918
  value = allocate(Sizes.Balance);
1910
1919
  writeBalance(value, 0, asset, amount);
1911
1920
  }
@@ -1915,7 +1924,7 @@ library Blocks {
1915
1924
  /// @param asset Asset identifier.
1916
1925
  /// @param amount Token amount.
1917
1926
  /// @return value Encoded CUSTODY block bytes.
1918
- function custody(uint host, bytes32 asset, uint amount) internal pure returns (bytes memory value) {
1927
+ function createCustody(uint host, bytes32 asset, uint amount) internal pure returns (bytes memory value) {
1919
1928
  value = allocate(Sizes.B96);
1920
1929
  writeCustody(value, 0, host, asset, amount);
1921
1930
  }
@@ -1926,7 +1935,7 @@ library Blocks {
1926
1935
  /// @param liability Identifier for the liability side.
1927
1936
  /// @param debt Quantity owed on the liability side.
1928
1937
  /// @return value Encoded POSITION block bytes.
1929
- function position(
1938
+ function createPosition(
1930
1939
  bytes32 asset,
1931
1940
  uint amount,
1932
1941
  bytes32 liability,
@@ -1942,7 +1951,7 @@ library Blocks {
1942
1951
  /// @param asset Asset identifier.
1943
1952
  /// @param amount Transfer amount.
1944
1953
  /// @return value Encoded TRANSACTION block bytes.
1945
- function transaction(
1954
+ function createTransaction(
1946
1955
  bytes32 from,
1947
1956
  bytes32 to,
1948
1957
  bytes32 asset,
@@ -1959,14 +1968,14 @@ library Blocks {
1959
1968
  /// @param resources Packed resources assigned to the step.
1960
1969
  /// @param input Raw nested input payload.
1961
1970
  /// @return value Encoded STEP block bytes.
1962
- function step(uint cmd, uint resources, bytes memory input) internal pure returns (bytes memory value) {
1971
+ function createStep(uint cmd, uint resources, bytes memory input) internal pure returns (bytes memory value) {
1963
1972
  uint len = max32(Sizes.B64 + Sizes.Header + input.length);
1964
1973
  value = allocate(len);
1965
1974
  writeStep(value, 0, cmd, resources, input);
1966
1975
  }
1967
1976
 
1968
1977
  /// @notice Encode a STEP block by copying its nested input from calldata.
1969
- function stepCopy(uint cmd, uint resources, bytes calldata input) internal pure returns (bytes memory value) {
1978
+ function createStepCopy(uint cmd, uint resources, bytes calldata input) internal pure returns (bytes memory value) {
1970
1979
  uint len = max32(Sizes.B64 + Sizes.Header + input.length);
1971
1980
  value = allocate(len);
1972
1981
  copyStep(value, 0, cmd, resources, input);
@@ -1977,14 +1986,14 @@ library Blocks {
1977
1986
  /// @param resources Packed resources assigned to the call.
1978
1987
  /// @param payload Raw calldata payload for the target.
1979
1988
  /// @return value Encoded CALL block bytes.
1980
- function call(uint target, uint resources, bytes memory payload) internal pure returns (bytes memory value) {
1989
+ function createCall(uint target, uint resources, bytes memory payload) internal pure returns (bytes memory value) {
1981
1990
  uint len = max32(Sizes.B64 + Sizes.Header + payload.length);
1982
1991
  value = allocate(len);
1983
1992
  writeCall(value, 0, target, resources, payload);
1984
1993
  }
1985
1994
 
1986
1995
  /// @notice Encode a CALL block by copying its nested payload from calldata.
1987
- function callCopy(uint target, uint resources, bytes calldata payload) internal pure returns (bytes memory value) {
1996
+ function createCallCopy(uint target, uint resources, bytes calldata payload) internal pure returns (bytes memory value) {
1988
1997
  uint len = max32(Sizes.B64 + Sizes.Header + payload.length);
1989
1998
  value = allocate(len);
1990
1999
  copyCall(value, 0, target, resources, payload);
@@ -1996,14 +2005,14 @@ library Blocks {
1996
2005
  /// @param resources Chain-specific resources for the destination context.
1997
2006
  /// @param input Nested input block stream.
1998
2007
  /// @return value Encoded RELAY block bytes.
1999
- function relay(uint portal, uint resources, bytes memory input) internal pure returns (bytes memory value) {
2008
+ function createRelay(uint portal, uint resources, bytes memory input) internal pure returns (bytes memory value) {
2000
2009
  uint len = max32(Sizes.B64 + Sizes.Header + input.length);
2001
2010
  value = allocate(len);
2002
2011
  writeRelay(value, 0, portal, resources, input);
2003
2012
  }
2004
2013
 
2005
2014
  /// @notice Encode a RELAY block by copying its nested input from calldata.
2006
- function relayCopy(uint portal, uint resources, bytes calldata input) internal pure returns (bytes memory value) {
2015
+ function createRelayCopy(uint portal, uint resources, bytes calldata input) internal pure returns (bytes memory value) {
2007
2016
  uint len = max32(Sizes.B64 + Sizes.Header + input.length);
2008
2017
  value = allocate(len);
2009
2018
  copyRelay(value, 0, portal, resources, input);
@@ -2015,14 +2024,14 @@ library Blocks {
2015
2024
  /// @param resources Chain-specific resources for the destination dispatch.
2016
2025
  /// @param payload Encoded payload.
2017
2026
  /// @return value Encoded DISPATCH block bytes.
2018
- function dispatch(uint portal, uint resources, bytes memory payload) internal pure returns (bytes memory value) {
2027
+ function createDispatch(uint portal, uint resources, bytes memory payload) internal pure returns (bytes memory value) {
2019
2028
  uint len = max32(Sizes.B64 + Sizes.Header + payload.length);
2020
2029
  value = allocate(len);
2021
2030
  writeDispatch(value, 0, portal, resources, payload);
2022
2031
  }
2023
2032
 
2024
2033
  /// @notice Encode a DISPATCH block by copying its nested payload from calldata.
2025
- function dispatchCopy(
2034
+ function createDispatchCopy(
2026
2035
  uint portal,
2027
2036
  uint resources,
2028
2037
  bytes calldata payload
@@ -2033,7 +2042,7 @@ library Blocks {
2033
2042
  }
2034
2043
 
2035
2044
  /// @notice Encode a CONTEXT block.
2036
- function context(
2045
+ function createContext(
2037
2046
  bytes32 account,
2038
2047
  bytes memory state,
2039
2048
  bytes memory input
@@ -2044,7 +2053,7 @@ library Blocks {
2044
2053
  }
2045
2054
 
2046
2055
  /// @notice Encode a CONTEXT block by copying its nested streams from calldata.
2047
- function contextCopy(
2056
+ function createContextCopy(
2048
2057
  bytes32 account,
2049
2058
  bytes calldata state,
2050
2059
  bytes calldata input
@@ -2055,7 +2064,7 @@ library Blocks {
2055
2064
  }
2056
2065
 
2057
2066
  /// @notice Encode a RECOVER block.
2058
- function recover(
2067
+ function createRecover(
2059
2068
  uint handler,
2060
2069
  uint resources,
2061
2070
  bytes32 recoverykey,
@@ -2067,7 +2076,7 @@ library Blocks {
2067
2076
  }
2068
2077
 
2069
2078
  /// @notice Encode a RECOVER block by copying its nested witness from calldata.
2070
- function recoverCopy(
2079
+ function createRecoverCopy(
2071
2080
  uint handler,
2072
2081
  uint resources,
2073
2082
  bytes32 recoverykey,
@@ -28,23 +28,20 @@ abstract contract Allocate is CommandBase, AllocateHook {
28
28
  }
29
29
 
30
30
  /// @notice Allocate BALANCE state blocks to matching NODE input blocks.
31
- /// @param state BALANCE block stream.
32
- /// @param input Matching NODE block stream.
31
+ /// @param context Command context carrying BALANCE state and matching NODE input.
33
32
  /// @return CUSTODY block stream matching the allocated balances.
34
33
  /// @return Empty transaction stream.
35
34
  function allocate(
36
- bytes32 account,
37
- bytes calldata state,
38
- bytes calldata input
35
+ bytes calldata context
39
36
  ) external onlyCommand returns (bytes memory, bytes memory) {
40
- Execution memory exec = openCommand(state, input, descriptor, 0);
37
+ Execution memory exec = openCommand(context, descriptor, 0);
41
38
 
42
39
  while (exec.more()) {
43
40
  HostAmount memory custody = exec.unpackBalanceForHost(Lanes.State, exec.unpackNode(Lanes.Input));
44
- allocate(account, custody);
41
+ allocate(exec.account, custody);
45
42
  exec.outputCustody(custody);
46
43
  }
47
44
 
48
- return close(exec, account);
45
+ return closeCommand(exec);
49
46
  }
50
47
  }
package/commands/Base.sol CHANGED
@@ -70,40 +70,56 @@ abstract contract CommandBase is CallerAccess, EndpointBase, ReceivedEvent {
70
70
  published = endpoint(id, name, descriptor);
71
71
  }
72
72
 
73
- /// @notice Open and validate both command lanes, including lanes declared EMPTY.
73
+ /// @notice Decode the command ABI argument as exactly one complete CONTEXT block.
74
+ /// @dev Rejects empty input, trailing bytes, and additional context blocks.
75
+ function unpackCommandContext(
76
+ bytes calldata context
77
+ ) internal pure returns (bytes32 account, bytes calldata state, bytes calldata input) {
78
+ uint abs;
79
+ assembly ("memory-safe") {
80
+ abs := context.offset
81
+ }
82
+
83
+ uint end;
84
+ (account, state, input, end) = Blocks.unpackContext(abs);
85
+ if (end != abs + context.length) revert Blocks.InvalidBlock();
86
+ }
87
+
88
+ /// @notice Decode one command context and validate both lanes, including lanes declared EMPTY.
74
89
  /// Batches are derived from the input and state lanes. A non-empty stream for
75
90
  /// a lane whose descriptor has zero stride reverts instead of being ignored.
76
91
  /// Commands must account for the complete validated state by consuming it,
77
92
  /// transforming and returning it, forwarding it intact, or reverting.
78
- /// @param state Current command state block stream.
79
- /// @param input Command input block stream.
93
+ /// @param context Exactly one CONTEXT block carrying the account, state, and input.
80
94
  /// @param descriptor Packed command endpoint descriptor.
81
95
  /// @param batches Required batch count, or zero to reconcile the lane counts.
82
96
  /// @return exec Execution with its output buffer metadata initialized for the reconciled batch count.
83
97
  function openCommand(
84
- bytes calldata state,
85
- bytes calldata input,
98
+ bytes calldata context,
86
99
  uint descriptor,
87
100
  uint batches
88
101
  ) internal view returns (Execution memory exec) {
89
- return Executions.open(state, input, descriptor, batches);
102
+ bytes32 account;
103
+ bytes calldata state;
104
+ bytes calldata input;
105
+ (account, state, input) = unpackCommandContext(context);
106
+ exec = Executions.open(state, input, descriptor, batches);
107
+ exec.account = account;
90
108
  }
91
109
 
92
- /// @notice Close a command execution and refund unspent value to `account`.
110
+ /// @notice Close a command execution and refund unspent value to its account.
93
111
  /// @param exec Command execution to close.
94
- /// @param account Account that should receive any unspent value.
95
112
  /// @return output Final encoded output block stream.
96
113
  /// @return transactions Final encoded transaction block stream.
97
- function close(
98
- Execution memory exec,
99
- bytes32 account
114
+ function closeCommand(
115
+ Execution memory exec
100
116
  ) internal returns (bytes memory output, bytes memory transactions) {
101
117
  if (exec.budget == 0 && Cursors.initial(exec.writers)) return ("", "");
102
118
 
103
119
  output = close(exec);
104
- uint amount = exec.refundValue(account, nativeAsset);
120
+ uint amount = exec.refundValue(exec.account, nativeAsset);
105
121
  if (amount != 0) {
106
- emit Received(account, nativeAsset, amount, Actions.Refund, 0);
122
+ emit Received(exec.account, nativeAsset, amount, Actions.Refund, 0);
107
123
  }
108
124
 
109
125
  transactions = exec.finishTransactions();
package/commands/Burn.sol CHANGED
@@ -30,22 +30,20 @@ abstract contract Burn is CommandBase, BurnHook, Action {
30
30
  }
31
31
 
32
32
  /// @notice Burn each BALANCE block from the command state.
33
- /// @param state BALANCE block stream.
33
+ /// @param context Command context carrying the BALANCE state stream.
34
34
  /// @return Empty output state.
35
35
  /// @return Empty transaction stream.
36
36
  function burn(
37
- bytes32 account,
38
- bytes calldata state,
39
- bytes calldata input
37
+ bytes calldata context
40
38
  ) external onlyCommand returns (bytes memory, bytes memory) {
41
- Execution memory exec = openCommand(state, input, descriptor, 0);
39
+ Execution memory exec = openCommand(context, descriptor, 0);
42
40
 
43
41
  while (exec.more()) {
44
42
  (bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
45
- burn(account, asset, amount);
43
+ burn(exec.account, asset, amount);
46
44
  }
47
45
 
48
- return close(exec, account);
46
+ return closeCommand(exec);
49
47
  }
50
48
  }
51
49
 
@@ -26,22 +26,20 @@ abstract contract CreditAccount is CommandBase, CreditAccountHook {
26
26
  }
27
27
 
28
28
  /// @notice Credit each BALANCE block from the command state to the command account.
29
- /// @param state BALANCE block stream.
29
+ /// @param context Command context carrying the BALANCE state stream.
30
30
  /// @return Empty output state.
31
31
  /// @return Empty transaction stream.
32
32
  function creditAccount(
33
- bytes32 account,
34
- bytes calldata state,
35
- bytes calldata input
33
+ bytes calldata context
36
34
  ) external onlyCommand returns (bytes memory, bytes memory) {
37
- Execution memory exec = openCommand(state, input, descriptor, 0);
35
+ Execution memory exec = openCommand(context, descriptor, 0);
38
36
 
39
37
  while (exec.more()) {
40
38
  (bytes32 asset, uint amount) = exec.unpackBalance(Lanes.State);
41
- creditAccount(account, asset, amount);
39
+ creditAccount(exec.account, asset, amount);
42
40
  }
43
41
 
44
- return close(exec, account);
42
+ return closeCommand(exec);
45
43
  }
46
44
  }
47
45
 
@@ -29,23 +29,21 @@ abstract contract DebitAccount is CommandBase, DebitAccountHook {
29
29
  }
30
30
 
31
31
  /// @notice Debit AMOUNT input blocks from the command account and output matching BALANCE blocks.
32
- /// @param input AMOUNT block stream.
32
+ /// @param context Command context carrying the AMOUNT input stream.
33
33
  /// @return BALANCE block stream matching the debited amounts.
34
34
  /// @return Empty transaction stream.
35
35
  function debitAccount(
36
- bytes32 account,
37
- bytes calldata state,
38
- bytes calldata input
36
+ bytes calldata context
39
37
  ) external onlyCommand returns (bytes memory, bytes memory) {
40
- Execution memory exec = openCommand(state, input, descriptor, 0);
38
+ Execution memory exec = openCommand(context, descriptor, 0);
41
39
 
42
40
  while (exec.more()) {
43
41
  (bytes32 asset, uint amount) = exec.unpackAmount(Lanes.Input);
44
- debitAccount(account, asset, amount);
42
+ debitAccount(exec.account, asset, amount);
45
43
  exec.outputBalance(asset, amount);
46
44
  }
47
45
 
48
- return close(exec, account);
46
+ return closeCommand(exec);
49
47
  }
50
48
  }
51
49