@rootzero/contracts 1.21.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.
- package/CHANGELOG.md +125 -0
- package/Endpoints.sol +2 -3
- package/Events.sol +1 -1
- package/README.md +25 -19
- package/annotations/Action.sol +1 -1
- package/annotations/Label.sol +1 -1
- package/annotations/Schema.sol +36 -3
- package/codec/Blocks.sol +100 -29
- package/codec/Decoders.sol +62 -8
- package/codec/Readers.sol +39 -0
- package/codec/Schema.sol +44 -35
- package/codec/Writers.sol +8 -0
- package/commands/Allocate.sol +5 -8
- package/commands/Base.sol +29 -13
- package/commands/Burn.sol +5 -7
- package/commands/Credit.sol +5 -7
- package/commands/Debit.sol +5 -7
- package/commands/Deposit.sol +10 -14
- package/commands/Payout.sol +5 -8
- package/commands/Provision.sol +10 -14
- package/commands/Recover.sol +4 -6
- package/commands/Relay.sol +16 -22
- package/commands/Repay.sol +10 -14
- package/commands/Settle.sol +10 -14
- package/commands/Withdraw.sol +5 -7
- package/commands/admin/AllowAssets.sol +5 -7
- package/commands/admin/Allowance.sol +5 -7
- package/commands/admin/Annotate.sol +5 -7
- package/commands/admin/Appoint.sol +5 -7
- package/commands/admin/Authorize.sol +5 -7
- package/commands/admin/Base.sol +12 -3
- package/commands/admin/DenyAssets.sol +5 -7
- package/commands/admin/Dismiss.sol +5 -7
- package/commands/admin/Execute.sol +5 -7
- package/commands/admin/Unauthorize.sol +5 -7
- package/core/Calls.sol +72 -3
- package/core/Host.sol +7 -10
- package/core/Portal.sol +2 -2
- package/events/Dispatch.sol +1 -1
- package/events/Positioned.sol +22 -0
- package/events/Relay.sol +1 -1
- package/events/Route.sol +1 -1
- package/execution/Execution.sol +124 -4
- package/package.json +2 -3
- package/ports/Allowance.sol +22 -12
- package/ports/Assets.sol +99 -0
- package/ports/Dispatch.sol +2 -1
- package/utils/Cursors.sol +3 -3
- package/utils/Nodes.sol +1 -1
- package/utils/Utils.sol +31 -31
- package/docs/Schema.md +0 -427
- package/events/Commander.sol +0 -19
- package/ports/AllowAssets.sol +0 -34
- package/ports/DenyAssets.sol +0 -34
package/codec/Blocks.sol
CHANGED
|
@@ -73,6 +73,17 @@ library Blocks {
|
|
|
73
73
|
len = uint32(head >> 192);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/// @notice Decode a complete block header within an absolute calldata region.
|
|
77
|
+
/// @param abs Absolute position of the header.
|
|
78
|
+
/// @param end Absolute region boundary.
|
|
79
|
+
/// @return key Decoded block key.
|
|
80
|
+
/// @return len Decoded payload length.
|
|
81
|
+
function peek(uint abs, uint end) internal pure returns (bytes4 key, uint len) {
|
|
82
|
+
if (abs > end || Sizes.Header > end - abs) revert MalformedBlocks();
|
|
83
|
+
(key, len) = header(abs);
|
|
84
|
+
if (len > end - abs - Sizes.Header) revert MalformedBlocks();
|
|
85
|
+
}
|
|
86
|
+
|
|
76
87
|
/// @notice Validate a block header at an absolute calldata position.
|
|
77
88
|
/// @dev DANGER: This performs an unchecked calldata read and does not ensure `end`
|
|
78
89
|
/// lies within the caller's logical calldata region. Only the key, minimum,
|
|
@@ -101,6 +112,17 @@ library Blocks {
|
|
|
101
112
|
end = body + size;
|
|
102
113
|
}
|
|
103
114
|
|
|
115
|
+
/// @notice Validate an empty block at an absolute calldata position.
|
|
116
|
+
/// @dev DANGER: This performs an unchecked calldata read. The caller must
|
|
117
|
+
/// validate the returned end against its logical calldata region.
|
|
118
|
+
/// @param abs Absolute position of the block header.
|
|
119
|
+
/// @param key Expected block key.
|
|
120
|
+
/// @return end Absolute position immediately after the empty block header.
|
|
121
|
+
function expectEmpty(uint abs, bytes4 key) internal pure returns (uint end) {
|
|
122
|
+
if (header(abs, key) != 0) revert InvalidBlock();
|
|
123
|
+
return abs + Sizes.Header;
|
|
124
|
+
}
|
|
125
|
+
|
|
104
126
|
/// @notice Return whether `abs` identifies a header with `key` before an absolute end.
|
|
105
127
|
/// @param abs Absolute calldata position to inspect.
|
|
106
128
|
/// @param end Absolute region boundary.
|
|
@@ -111,6 +133,16 @@ library Blocks {
|
|
|
111
133
|
return bytes4(read32(abs)) == key;
|
|
112
134
|
}
|
|
113
135
|
|
|
136
|
+
/// @notice Return whether `abs` identifies a complete empty block header.
|
|
137
|
+
/// @param abs Absolute position to inspect.
|
|
138
|
+
/// @param end Absolute region boundary.
|
|
139
|
+
/// @param key Expected block key.
|
|
140
|
+
/// @return Whether the expected key occurs with a zero-length payload.
|
|
141
|
+
function isEmpty(uint abs, uint end, bytes4 key) internal pure returns (bool) {
|
|
142
|
+
if (!hasAt(abs, end, key)) return false;
|
|
143
|
+
return uint32(uint(read32(abs)) >> 192) == 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
114
146
|
/// @notice Find the first block with `key` at or after absolute position `abs`.
|
|
115
147
|
/// @param abs Absolute search position.
|
|
116
148
|
/// @param end Absolute region boundary.
|
|
@@ -160,6 +192,18 @@ library Blocks {
|
|
|
160
192
|
|
|
161
193
|
// Generic block writes
|
|
162
194
|
|
|
195
|
+
/// @notice Write an empty block header at `i`.
|
|
196
|
+
/// @dev DANGER: Unchecked memory write. Reserve `Sizes.Header` bytes first.
|
|
197
|
+
/// @param dst Destination buffer.
|
|
198
|
+
/// @param i Relative write position.
|
|
199
|
+
/// @param key Block key.
|
|
200
|
+
function writeEmpty(bytes memory dst, uint i, bytes4 key) internal pure {
|
|
201
|
+
uint head = uint(uint32(key)) << 224;
|
|
202
|
+
assembly ("memory-safe") {
|
|
203
|
+
mstore(add(add(dst, 0x20), i), head)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
163
207
|
/// @notice Write a custom block with one payload word at `i`.
|
|
164
208
|
/// @dev DANGER: Unchecked memory write. Reserve `Sizes.B32` bytes first.
|
|
165
209
|
/// @param dst Destination buffer.
|
|
@@ -1729,6 +1773,14 @@ library Blocks {
|
|
|
1729
1773
|
|
|
1730
1774
|
// Generic factories
|
|
1731
1775
|
|
|
1776
|
+
/// @notice Encode an empty block.
|
|
1777
|
+
/// @param key Block type key.
|
|
1778
|
+
/// @return value Encoded empty block header.
|
|
1779
|
+
function createEmpty(bytes4 key) internal pure returns (bytes memory value) {
|
|
1780
|
+
value = allocate(Sizes.Header);
|
|
1781
|
+
writeEmpty(value, 0, key);
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1732
1784
|
/// @notice Encode a block with a raw payload.
|
|
1733
1785
|
/// @param key Block type key.
|
|
1734
1786
|
/// @param payload Raw payload bytes.
|
|
@@ -1749,28 +1801,28 @@ library Blocks {
|
|
|
1749
1801
|
// Dynamic leaf factories
|
|
1750
1802
|
|
|
1751
1803
|
/// @notice Encode a LIST block.
|
|
1752
|
-
function
|
|
1804
|
+
function createList(bytes memory value) internal pure returns (bytes memory blockdata) {
|
|
1753
1805
|
uint len = max32(value.length);
|
|
1754
1806
|
blockdata = allocate(Sizes.Header + len);
|
|
1755
1807
|
writeList(blockdata, 0, value);
|
|
1756
1808
|
}
|
|
1757
1809
|
|
|
1758
1810
|
/// @notice Encode a LIST block by copying its payload from calldata.
|
|
1759
|
-
function
|
|
1811
|
+
function createListCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
|
|
1760
1812
|
uint len = max32(value.length);
|
|
1761
1813
|
blockdata = allocate(Sizes.Header + len);
|
|
1762
1814
|
copyList(blockdata, 0, value);
|
|
1763
1815
|
}
|
|
1764
1816
|
|
|
1765
1817
|
/// @notice Encode an EVM block.
|
|
1766
|
-
function
|
|
1818
|
+
function createEvm(bytes memory value) internal pure returns (bytes memory blockdata) {
|
|
1767
1819
|
uint len = max32(value.length);
|
|
1768
1820
|
blockdata = allocate(Sizes.Header + len);
|
|
1769
1821
|
writeEvm(blockdata, 0, value);
|
|
1770
1822
|
}
|
|
1771
1823
|
|
|
1772
1824
|
/// @notice Encode an EVM block by copying its payload from calldata.
|
|
1773
|
-
function
|
|
1825
|
+
function createEvmCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
|
|
1774
1826
|
uint len = max32(value.length);
|
|
1775
1827
|
blockdata = allocate(Sizes.Header + len);
|
|
1776
1828
|
copyEvm(blockdata, 0, value);
|
|
@@ -1779,14 +1831,14 @@ library Blocks {
|
|
|
1779
1831
|
/// @notice Encode a BYTES block with a raw payload.
|
|
1780
1832
|
/// @param value Raw payload bytes.
|
|
1781
1833
|
/// @return blockdata Encoded BYTES block bytes.
|
|
1782
|
-
function
|
|
1834
|
+
function createBytes(bytes memory value) internal pure returns (bytes memory blockdata) {
|
|
1783
1835
|
uint len = max32(value.length);
|
|
1784
1836
|
blockdata = allocate(Sizes.Header + len);
|
|
1785
1837
|
writeBytes(blockdata, 0, value);
|
|
1786
1838
|
}
|
|
1787
1839
|
|
|
1788
1840
|
/// @notice Encode a BYTES block by copying its payload from calldata.
|
|
1789
|
-
function
|
|
1841
|
+
function createBytesCopy(bytes calldata value) internal pure returns (bytes memory blockdata) {
|
|
1790
1842
|
uint len = max32(value.length);
|
|
1791
1843
|
blockdata = allocate(Sizes.Header + len);
|
|
1792
1844
|
copyBytes(blockdata, 0, value);
|
|
@@ -1795,14 +1847,14 @@ library Blocks {
|
|
|
1795
1847
|
/// @notice Encode a STRING block with a UTF-8 payload.
|
|
1796
1848
|
/// @param value String payload.
|
|
1797
1849
|
/// @return blockdata Encoded STRING block bytes.
|
|
1798
|
-
function
|
|
1850
|
+
function createString(string memory value) internal pure returns (bytes memory blockdata) {
|
|
1799
1851
|
uint len = max32(bytes(value).length);
|
|
1800
1852
|
blockdata = allocate(Sizes.Header + len);
|
|
1801
1853
|
writeString(blockdata, 0, value);
|
|
1802
1854
|
}
|
|
1803
1855
|
|
|
1804
1856
|
/// @notice Encode a STRING block by copying its payload from calldata.
|
|
1805
|
-
function
|
|
1857
|
+
function createStringCopy(string calldata value) internal pure returns (bytes memory blockdata) {
|
|
1806
1858
|
uint len = max32(bytes(value).length);
|
|
1807
1859
|
blockdata = allocate(Sizes.Header + len);
|
|
1808
1860
|
copyString(blockdata, 0, value);
|
|
@@ -1814,7 +1866,7 @@ library Blocks {
|
|
|
1814
1866
|
/// @param namespace Label namespace.
|
|
1815
1867
|
/// @param name Label text.
|
|
1816
1868
|
/// @return value Encoded LABEL block bytes.
|
|
1817
|
-
function
|
|
1869
|
+
function createLabel(bytes32 namespace, string memory name) internal pure returns (bytes memory value) {
|
|
1818
1870
|
uint len = max32(Sizes.B32 + bytes(name).length);
|
|
1819
1871
|
value = allocate(Sizes.Header + len);
|
|
1820
1872
|
writeLabel(value, 0, namespace, name);
|
|
@@ -1823,7 +1875,7 @@ library Blocks {
|
|
|
1823
1875
|
/// @notice Encode an ACTION annotation block.
|
|
1824
1876
|
/// @param actionid Canonical semantic action identifier.
|
|
1825
1877
|
/// @return value Encoded ACTION block bytes.
|
|
1826
|
-
function
|
|
1878
|
+
function createAction(uint actionid) internal pure returns (bytes memory value) {
|
|
1827
1879
|
value = allocate(Sizes.B32);
|
|
1828
1880
|
write32(value, 0, Keys.Action, bytes32(actionid));
|
|
1829
1881
|
}
|
|
@@ -1831,9 +1883,17 @@ library Blocks {
|
|
|
1831
1883
|
/// @notice Encode a SCHEMA block.
|
|
1832
1884
|
/// @param spec Block specification.
|
|
1833
1885
|
/// @param body Schema body.
|
|
1886
|
+
/// @return value Encoded SCHEMA block bytes.
|
|
1887
|
+
function createSchema(uint spec, string memory body) internal pure returns (bytes memory value) {
|
|
1888
|
+
return createSchema(spec, body, bytes32(0));
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
/// @notice Encode a named SCHEMA block.
|
|
1892
|
+
/// @param spec Block specification.
|
|
1893
|
+
/// @param body Schema body.
|
|
1834
1894
|
/// @param name Schema name.
|
|
1835
1895
|
/// @return value Encoded SCHEMA block bytes.
|
|
1836
|
-
function
|
|
1896
|
+
function createSchema(uint spec, string memory body, bytes32 name) internal pure returns (bytes memory value) {
|
|
1837
1897
|
uint len = max32(Sizes.B64 + bytes(body).length);
|
|
1838
1898
|
value = allocate(Sizes.Header + len);
|
|
1839
1899
|
writeSchema(value, 0, spec, body, name);
|
|
@@ -1841,11 +1901,20 @@ library Blocks {
|
|
|
1841
1901
|
|
|
1842
1902
|
// Fixed-width factories
|
|
1843
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
|
+
|
|
1844
1913
|
/// @notice Encode a BALANCE block.
|
|
1845
1914
|
/// @param asset Asset identifier.
|
|
1846
1915
|
/// @param amount Token amount.
|
|
1847
1916
|
/// @return value Encoded BALANCE block bytes.
|
|
1848
|
-
function
|
|
1917
|
+
function createBalance(bytes32 asset, uint amount) internal pure returns (bytes memory value) {
|
|
1849
1918
|
value = allocate(Sizes.Balance);
|
|
1850
1919
|
writeBalance(value, 0, asset, amount);
|
|
1851
1920
|
}
|
|
@@ -1855,7 +1924,7 @@ library Blocks {
|
|
|
1855
1924
|
/// @param asset Asset identifier.
|
|
1856
1925
|
/// @param amount Token amount.
|
|
1857
1926
|
/// @return value Encoded CUSTODY block bytes.
|
|
1858
|
-
function
|
|
1927
|
+
function createCustody(uint host, bytes32 asset, uint amount) internal pure returns (bytes memory value) {
|
|
1859
1928
|
value = allocate(Sizes.B96);
|
|
1860
1929
|
writeCustody(value, 0, host, asset, amount);
|
|
1861
1930
|
}
|
|
@@ -1866,7 +1935,7 @@ library Blocks {
|
|
|
1866
1935
|
/// @param liability Identifier for the liability side.
|
|
1867
1936
|
/// @param debt Quantity owed on the liability side.
|
|
1868
1937
|
/// @return value Encoded POSITION block bytes.
|
|
1869
|
-
function
|
|
1938
|
+
function createPosition(
|
|
1870
1939
|
bytes32 asset,
|
|
1871
1940
|
uint amount,
|
|
1872
1941
|
bytes32 liability,
|
|
@@ -1882,7 +1951,7 @@ library Blocks {
|
|
|
1882
1951
|
/// @param asset Asset identifier.
|
|
1883
1952
|
/// @param amount Transfer amount.
|
|
1884
1953
|
/// @return value Encoded TRANSACTION block bytes.
|
|
1885
|
-
function
|
|
1954
|
+
function createTransaction(
|
|
1886
1955
|
bytes32 from,
|
|
1887
1956
|
bytes32 to,
|
|
1888
1957
|
bytes32 asset,
|
|
@@ -1899,14 +1968,14 @@ library Blocks {
|
|
|
1899
1968
|
/// @param resources Packed resources assigned to the step.
|
|
1900
1969
|
/// @param input Raw nested input payload.
|
|
1901
1970
|
/// @return value Encoded STEP block bytes.
|
|
1902
|
-
function
|
|
1971
|
+
function createStep(uint cmd, uint resources, bytes memory input) internal pure returns (bytes memory value) {
|
|
1903
1972
|
uint len = max32(Sizes.B64 + Sizes.Header + input.length);
|
|
1904
1973
|
value = allocate(len);
|
|
1905
1974
|
writeStep(value, 0, cmd, resources, input);
|
|
1906
1975
|
}
|
|
1907
1976
|
|
|
1908
1977
|
/// @notice Encode a STEP block by copying its nested input from calldata.
|
|
1909
|
-
function
|
|
1978
|
+
function createStepCopy(uint cmd, uint resources, bytes calldata input) internal pure returns (bytes memory value) {
|
|
1910
1979
|
uint len = max32(Sizes.B64 + Sizes.Header + input.length);
|
|
1911
1980
|
value = allocate(len);
|
|
1912
1981
|
copyStep(value, 0, cmd, resources, input);
|
|
@@ -1917,50 +1986,52 @@ library Blocks {
|
|
|
1917
1986
|
/// @param resources Packed resources assigned to the call.
|
|
1918
1987
|
/// @param payload Raw calldata payload for the target.
|
|
1919
1988
|
/// @return value Encoded CALL block bytes.
|
|
1920
|
-
function
|
|
1989
|
+
function createCall(uint target, uint resources, bytes memory payload) internal pure returns (bytes memory value) {
|
|
1921
1990
|
uint len = max32(Sizes.B64 + Sizes.Header + payload.length);
|
|
1922
1991
|
value = allocate(len);
|
|
1923
1992
|
writeCall(value, 0, target, resources, payload);
|
|
1924
1993
|
}
|
|
1925
1994
|
|
|
1926
1995
|
/// @notice Encode a CALL block by copying its nested payload from calldata.
|
|
1927
|
-
function
|
|
1996
|
+
function createCallCopy(uint target, uint resources, bytes calldata payload) internal pure returns (bytes memory value) {
|
|
1928
1997
|
uint len = max32(Sizes.B64 + Sizes.Header + payload.length);
|
|
1929
1998
|
value = allocate(len);
|
|
1930
1999
|
copyCall(value, 0, target, resources, payload);
|
|
1931
2000
|
}
|
|
1932
2001
|
|
|
1933
2002
|
/// @notice Encode a RELAY block.
|
|
1934
|
-
/// @param portal Destination portal
|
|
2003
|
+
/// @param portal Destination portal implementation's host ID, passed through
|
|
2004
|
+
/// without semantic validation.
|
|
1935
2005
|
/// @param resources Chain-specific resources for the destination context.
|
|
1936
2006
|
/// @param input Nested input block stream.
|
|
1937
2007
|
/// @return value Encoded RELAY block bytes.
|
|
1938
|
-
function
|
|
2008
|
+
function createRelay(uint portal, uint resources, bytes memory input) internal pure returns (bytes memory value) {
|
|
1939
2009
|
uint len = max32(Sizes.B64 + Sizes.Header + input.length);
|
|
1940
2010
|
value = allocate(len);
|
|
1941
2011
|
writeRelay(value, 0, portal, resources, input);
|
|
1942
2012
|
}
|
|
1943
2013
|
|
|
1944
2014
|
/// @notice Encode a RELAY block by copying its nested input from calldata.
|
|
1945
|
-
function
|
|
2015
|
+
function createRelayCopy(uint portal, uint resources, bytes calldata input) internal pure returns (bytes memory value) {
|
|
1946
2016
|
uint len = max32(Sizes.B64 + Sizes.Header + input.length);
|
|
1947
2017
|
value = allocate(len);
|
|
1948
2018
|
copyRelay(value, 0, portal, resources, input);
|
|
1949
2019
|
}
|
|
1950
2020
|
|
|
1951
2021
|
/// @notice Encode a DISPATCH block.
|
|
1952
|
-
/// @param portal Destination portal
|
|
2022
|
+
/// @param portal Destination portal implementation's host ID, passed through
|
|
2023
|
+
/// without semantic validation.
|
|
1953
2024
|
/// @param resources Chain-specific resources for the destination dispatch.
|
|
1954
2025
|
/// @param payload Encoded payload.
|
|
1955
2026
|
/// @return value Encoded DISPATCH block bytes.
|
|
1956
|
-
function
|
|
2027
|
+
function createDispatch(uint portal, uint resources, bytes memory payload) internal pure returns (bytes memory value) {
|
|
1957
2028
|
uint len = max32(Sizes.B64 + Sizes.Header + payload.length);
|
|
1958
2029
|
value = allocate(len);
|
|
1959
2030
|
writeDispatch(value, 0, portal, resources, payload);
|
|
1960
2031
|
}
|
|
1961
2032
|
|
|
1962
2033
|
/// @notice Encode a DISPATCH block by copying its nested payload from calldata.
|
|
1963
|
-
function
|
|
2034
|
+
function createDispatchCopy(
|
|
1964
2035
|
uint portal,
|
|
1965
2036
|
uint resources,
|
|
1966
2037
|
bytes calldata payload
|
|
@@ -1971,7 +2042,7 @@ library Blocks {
|
|
|
1971
2042
|
}
|
|
1972
2043
|
|
|
1973
2044
|
/// @notice Encode a CONTEXT block.
|
|
1974
|
-
function
|
|
2045
|
+
function createContext(
|
|
1975
2046
|
bytes32 account,
|
|
1976
2047
|
bytes memory state,
|
|
1977
2048
|
bytes memory input
|
|
@@ -1982,7 +2053,7 @@ library Blocks {
|
|
|
1982
2053
|
}
|
|
1983
2054
|
|
|
1984
2055
|
/// @notice Encode a CONTEXT block by copying its nested streams from calldata.
|
|
1985
|
-
function
|
|
2056
|
+
function createContextCopy(
|
|
1986
2057
|
bytes32 account,
|
|
1987
2058
|
bytes calldata state,
|
|
1988
2059
|
bytes calldata input
|
|
@@ -1993,7 +2064,7 @@ library Blocks {
|
|
|
1993
2064
|
}
|
|
1994
2065
|
|
|
1995
2066
|
/// @notice Encode a RECOVER block.
|
|
1996
|
-
function
|
|
2067
|
+
function createRecover(
|
|
1997
2068
|
uint handler,
|
|
1998
2069
|
uint resources,
|
|
1999
2070
|
bytes32 recoverykey,
|
|
@@ -2005,7 +2076,7 @@ library Blocks {
|
|
|
2005
2076
|
}
|
|
2006
2077
|
|
|
2007
2078
|
/// @notice Encode a RECOVER block by copying its nested witness from calldata.
|
|
2008
|
-
function
|
|
2079
|
+
function createRecoverCopy(
|
|
2009
2080
|
uint handler,
|
|
2010
2081
|
uint resources,
|
|
2011
2082
|
bytes32 recoverykey,
|
package/codec/Decoders.sol
CHANGED
|
@@ -52,6 +52,13 @@ library Decoders {
|
|
|
52
52
|
return cur.state.more();
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/// @notice Return the cursor's current absolute calldata position.
|
|
56
|
+
/// @param cur Cursor to inspect.
|
|
57
|
+
/// @return Current absolute calldata position.
|
|
58
|
+
function absolute(Cur memory cur) internal pure returns (uint) {
|
|
59
|
+
return cur.state.absolute();
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
/// @notice Validate and consume the next block from a cursor.
|
|
56
63
|
/// @param cur Cursor advanced over the complete block.
|
|
57
64
|
/// @param spec Expected block specification.
|
|
@@ -62,6 +69,18 @@ library Decoders {
|
|
|
62
69
|
cur.state = cur.state.seekAbs(end);
|
|
63
70
|
}
|
|
64
71
|
|
|
72
|
+
/// @notice Consume a matching empty block from a cursor when present.
|
|
73
|
+
/// @param cur Cursor advanced only when the matching block is empty.
|
|
74
|
+
/// @param key Expected block key.
|
|
75
|
+
/// @return Whether an empty block was consumed.
|
|
76
|
+
function tryConsumeEmpty(Cur memory cur, bytes4 key) internal pure returns (bool) {
|
|
77
|
+
(uint i, uint offset, uint size) = cur.state.decode();
|
|
78
|
+
(bytes4 current, uint len) = Blocks.peek(offset + i, offset + size);
|
|
79
|
+
if (current != key || len != 0) return false;
|
|
80
|
+
cur.state = cur.state.seek(i + Sizes.Header);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
65
84
|
/// @notice Validate and enter the payload of the next block in a cursor.
|
|
66
85
|
/// @dev The cursor remains in its existing frame so callers can decode child
|
|
67
86
|
/// blocks in place. Callers should prove complete payload consumption with
|
|
@@ -71,8 +90,38 @@ library Decoders {
|
|
|
71
90
|
/// @return abs Absolute position of the first payload byte.
|
|
72
91
|
/// @return end Absolute position immediately after the payload.
|
|
73
92
|
function enter(Cur memory cur, uint spec) internal pure returns (uint abs, uint end) {
|
|
93
|
+
return enter(cur, spec, 0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// @notice Validate a parent block and advance over a fixed payload prefix.
|
|
97
|
+
/// @dev `amount` is relative to the payload start and cannot exceed the
|
|
98
|
+
/// current parent payload. The returned `abs` remains the payload start.
|
|
99
|
+
/// @param cur Cursor advanced over the block header and fixed prefix.
|
|
100
|
+
/// @param spec Expected parent block specification.
|
|
101
|
+
/// @param amount Number of initial payload bytes to advance over.
|
|
102
|
+
/// @return abs Absolute position of the first payload byte.
|
|
103
|
+
/// @return end Absolute position immediately after the payload.
|
|
104
|
+
function enter(Cur memory cur, uint spec, uint amount) internal pure returns (uint abs, uint end) {
|
|
74
105
|
(abs, end) = Blocks.expect(cur.state.absolute(), spec);
|
|
75
|
-
|
|
106
|
+
if (amount > end - abs) revert Blocks.InvalidBlock();
|
|
107
|
+
cur.state = cur.state.seekAbs(abs + amount);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// @notice Advance a cursor by a raw byte count.
|
|
111
|
+
/// @dev No block header or schema is validated.
|
|
112
|
+
/// @param cur Cursor advanced by `amount` bytes.
|
|
113
|
+
/// @param amount Number of bytes to advance.
|
|
114
|
+
function advance(Cur memory cur, uint amount) internal pure {
|
|
115
|
+
cur.state = cur.state.advance(amount);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/// @notice Take a raw byte range from the cursor.
|
|
119
|
+
/// @dev No block header or schema is validated.
|
|
120
|
+
/// @param cur Cursor advanced by `amount` bytes.
|
|
121
|
+
/// @param amount Number of bytes to take.
|
|
122
|
+
/// @return abs Absolute position of the first taken byte.
|
|
123
|
+
function take(Cur memory cur, uint amount) internal pure returns (uint abs) {
|
|
124
|
+
(cur.state, abs) = cur.state.consume(amount);
|
|
76
125
|
}
|
|
77
126
|
|
|
78
127
|
/// @notice Require a decoder cursor to be at absolute position `abs`.
|
|
@@ -128,9 +177,7 @@ library Decoders {
|
|
|
128
177
|
/// @return len Payload length.
|
|
129
178
|
function peek(Cur memory cur, uint i) internal pure returns (bytes4 key, uint len) {
|
|
130
179
|
(, uint offset, uint size) = cur.state.decode();
|
|
131
|
-
|
|
132
|
-
(key, len) = Blocks.header(offset + i);
|
|
133
|
-
if (len > size - i - Sizes.Header) revert Blocks.MalformedBlocks();
|
|
180
|
+
return Blocks.peek(offset + i, offset + size);
|
|
134
181
|
}
|
|
135
182
|
|
|
136
183
|
/// @notice Return the relative position immediately after the current block.
|
|
@@ -161,6 +208,15 @@ library Decoders {
|
|
|
161
208
|
return Blocks.hasAt(offset + i, offset + len, key);
|
|
162
209
|
}
|
|
163
210
|
|
|
211
|
+
/// @notice Return whether the current block has `key` and an empty payload.
|
|
212
|
+
/// @param cur Cursor positioned at a block.
|
|
213
|
+
/// @param key Expected block key.
|
|
214
|
+
/// @return Whether a complete matching empty block header occurs at the current position.
|
|
215
|
+
function isEmpty(Cur memory cur, bytes4 key) internal pure returns (bool) {
|
|
216
|
+
(uint i, uint offset, uint len) = cur.state.decode();
|
|
217
|
+
return Blocks.isEmpty(offset + i, offset + len, key);
|
|
218
|
+
}
|
|
219
|
+
|
|
164
220
|
/// @notice Find `key` at or after relative position `i`.
|
|
165
221
|
/// @param cur Cursor to search.
|
|
166
222
|
/// @param i Relative search position.
|
|
@@ -210,7 +266,7 @@ library Decoders {
|
|
|
210
266
|
/// @param cur Cursor advanced past the block.
|
|
211
267
|
/// @param key Expected block key.
|
|
212
268
|
/// @return out Cursor spanning the complete encoded block.
|
|
213
|
-
function
|
|
269
|
+
function takeBlock(Cur memory cur, bytes4 key) internal pure returns (Cur memory out) {
|
|
214
270
|
uint abs = cur.state.absolute();
|
|
215
271
|
(, uint end) = consume(cur, Specs.create(key, 0, 0, 0));
|
|
216
272
|
out.state = Cursors.create(abs, end - abs, 0, 0, 0);
|
|
@@ -256,9 +312,7 @@ library Decoders {
|
|
|
256
312
|
|
|
257
313
|
/// @dev Return the next raw calldata word and advance by `size` bytes.
|
|
258
314
|
function next(Cur memory cur, uint size) private pure returns (bytes32 value) {
|
|
259
|
-
|
|
260
|
-
(cur.state, abs) = cur.state.consume(size);
|
|
261
|
-
value = Blocks.read32(abs);
|
|
315
|
+
value = Blocks.read32(take(cur, size));
|
|
262
316
|
}
|
|
263
317
|
|
|
264
318
|
/// @notice Return the next raw byte and advance the cursor by one byte.
|
package/codec/Readers.sol
CHANGED
|
@@ -45,6 +45,45 @@ library Readers {
|
|
|
45
45
|
return cur.i != cur.source.length;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/// @notice Return whether the current block has `key` and an empty payload.
|
|
49
|
+
/// @param cur Reader inspected without advancing.
|
|
50
|
+
/// @param key Expected block key.
|
|
51
|
+
/// @return Whether a complete matching empty block header occurs at the current position.
|
|
52
|
+
function isEmpty(Reader memory cur, bytes4 key) internal pure returns (bool) {
|
|
53
|
+
bytes memory source = cur.source;
|
|
54
|
+
uint i = cur.i;
|
|
55
|
+
if (i > source.length || source.length - i < Sizes.Header) return false;
|
|
56
|
+
|
|
57
|
+
uint header;
|
|
58
|
+
assembly ("memory-safe") {
|
|
59
|
+
header := mload(add(add(source, 0x20), i))
|
|
60
|
+
}
|
|
61
|
+
return bytes4(uint32(header >> 224)) == key && uint32(header >> 192) == 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// @notice Consume a matching empty block from the reader when present.
|
|
65
|
+
/// @param cur Reader advanced only when the matching block is empty.
|
|
66
|
+
/// @param key Expected block key.
|
|
67
|
+
/// @return Whether an empty block was consumed.
|
|
68
|
+
function tryConsumeEmpty(Reader memory cur, bytes4 key) internal pure returns (bool) {
|
|
69
|
+
bytes memory source = cur.source;
|
|
70
|
+
uint i = cur.i;
|
|
71
|
+
if (i > source.length || source.length - i < Sizes.Header) revert InvalidBlock();
|
|
72
|
+
|
|
73
|
+
bytes4 current;
|
|
74
|
+
uint len;
|
|
75
|
+
assembly ("memory-safe") {
|
|
76
|
+
let header := mload(add(add(source, 0x20), i))
|
|
77
|
+
current := header
|
|
78
|
+
len := and(shr(192, header), 0xffffffff)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (len > source.length - i - Sizes.Header) revert InvalidBlock();
|
|
82
|
+
if (current != key || len != 0) return false;
|
|
83
|
+
cur.i += Sizes.Header;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
48
87
|
/// @notice Validate and consume the current block, advancing `cur.i` past it.
|
|
49
88
|
/// @param cur Reader to advance.
|
|
50
89
|
/// @param key Expected block key.
|
package/codec/Schema.sol
CHANGED
|
@@ -8,24 +8,34 @@ pragma solidity ^0.8.33;
|
|
|
8
8
|
//
|
|
9
9
|
// Schema:
|
|
10
10
|
// - block aliases are published separately from payload schemas
|
|
11
|
-
// - payload schemas are `""
|
|
11
|
+
// - payload schemas are `""` or a comma-separated item sequence; one optional
|
|
12
|
+
// pair of outer braces may wrap a non-empty sequence without changing meaning
|
|
12
13
|
// - an empty schema string means the block has no structured payload
|
|
13
14
|
// - commas separate siblings at every level
|
|
14
|
-
// - braces
|
|
15
|
+
// - braces are presentation-only and do not change payload layout
|
|
15
16
|
// - command inputs are a single run when the input schema is non-empty
|
|
16
17
|
// - command state is a single active state run without trailing globals
|
|
17
18
|
// - run items may repeat at top level for batching
|
|
18
|
-
// -
|
|
19
|
-
// -
|
|
20
|
-
// -
|
|
21
|
-
//
|
|
19
|
+
// - every declared child block header is present when its parent is non-empty
|
|
20
|
+
// - any block may use a zero-length payload as its empty form
|
|
21
|
+
// - `maybe #x` hints that the onchain consumer accepts the empty form of `#x`
|
|
22
|
+
// when emptiness is not already intrinsic to the referenced block type
|
|
23
|
+
// - `many #x` alongside other items emits one generic list block containing
|
|
24
|
+
// zero or more repeated `#x` items; the list header is always present
|
|
25
|
+
// - a custom schema consisting of exactly one `many #x` item uses its custom
|
|
26
|
+
// key for the outer list block and contains repeated `#x` items directly,
|
|
27
|
+
// whether or not the item is wrapped in braces
|
|
22
28
|
// - endpoint descriptor lanes identify their top-level block key directly
|
|
23
|
-
// - `portal` fields
|
|
29
|
+
// - `portal` fields identify destination portal hosts. By convention the value
|
|
30
|
+
// is the portal implementation's host ID; core passes it through unchanged
|
|
31
|
+
// and hooks may validate or resolve it for their transport
|
|
24
32
|
// - `resources` fields are chain-specific resource words. A portal adapter
|
|
25
33
|
// interprets them for the destination runtime. EVM resources use the low
|
|
26
34
|
// 128 bits as native value.
|
|
27
35
|
// - dotted field names and aliases, e.g. `dst.portal` or `#bytes as dst.payload`,
|
|
28
36
|
// are offchain projection metadata only and do not change runtime encoding
|
|
37
|
+
// - `at N` assigns an offchain presentation position to one sibling; explicit
|
|
38
|
+
// positions are reserved first and unannotated siblings retain relative order
|
|
29
39
|
// - child blocks resolve by alias in the active schema context; unresolved aliases are invalid
|
|
30
40
|
// - schema strings describe the payload body only; the `Block` event carries the alias
|
|
31
41
|
// - items are encoded in declaration order
|
|
@@ -63,7 +73,6 @@ pragma solidity ^0.8.33;
|
|
|
63
73
|
library Schemas {
|
|
64
74
|
// Empty and reserved payloads
|
|
65
75
|
|
|
66
|
-
string constant Unit = "";
|
|
67
76
|
string constant Bytes = "";
|
|
68
77
|
string constant String = "";
|
|
69
78
|
string constant List = "";
|
|
@@ -71,47 +80,47 @@ library Schemas {
|
|
|
71
80
|
|
|
72
81
|
// One-word payloads
|
|
73
82
|
|
|
74
|
-
string constant Node = "
|
|
75
|
-
string constant Account = "
|
|
76
|
-
string constant Asset = "
|
|
77
|
-
string constant Status = "
|
|
83
|
+
string constant Node = "uint node";
|
|
84
|
+
string constant Account = "bytes32 account";
|
|
85
|
+
string constant Asset = "bytes32 asset";
|
|
86
|
+
string constant Status = "uint code";
|
|
78
87
|
|
|
79
88
|
// Two-word payloads
|
|
80
89
|
|
|
81
|
-
string constant Amount = "
|
|
82
|
-
string constant Balance = "
|
|
83
|
-
string constant AccountAsset = "
|
|
84
|
-
string constant HostAsset = "
|
|
90
|
+
string constant Amount = "bytes32 asset, uint amount";
|
|
91
|
+
string constant Balance = "bytes32 asset, uint amount";
|
|
92
|
+
string constant AccountAsset = "bytes32 account, bytes32 asset";
|
|
93
|
+
string constant HostAsset = "uint host, bytes32 asset";
|
|
85
94
|
|
|
86
95
|
// Three-word payloads
|
|
87
96
|
|
|
88
|
-
string constant Allocation = "
|
|
89
|
-
string constant Allowance = "
|
|
90
|
-
string constant Custody = "
|
|
91
|
-
string constant AccountAmount = "
|
|
92
|
-
string constant HostAmount = "
|
|
93
|
-
string constant HostAccountAsset = "
|
|
97
|
+
string constant Allocation = "uint host, bytes32 asset, uint amount";
|
|
98
|
+
string constant Allowance = "uint host, bytes32 asset, uint amount";
|
|
99
|
+
string constant Custody = "uint host, bytes32 asset, uint amount";
|
|
100
|
+
string constant AccountAmount = "bytes32 account, bytes32 asset, uint amount";
|
|
101
|
+
string constant HostAmount = "uint host, bytes32 asset, uint amount";
|
|
102
|
+
string constant HostAccountAsset = "uint host, bytes32 account, bytes32 asset";
|
|
94
103
|
|
|
95
104
|
// Four-word payloads
|
|
96
105
|
|
|
97
|
-
string constant Position = "
|
|
98
|
-
string constant Transaction = "
|
|
99
|
-
string constant HostAccountAmount = "
|
|
106
|
+
string constant Position = "bytes32 asset, uint amount, bytes32 liability, uint debt";
|
|
107
|
+
string constant Transaction = "bytes32 from, bytes32 to, bytes32 asset, uint amount";
|
|
108
|
+
string constant HostAccountAmount = "uint host, bytes32 account, bytes32 asset, uint amount";
|
|
100
109
|
|
|
101
110
|
// Composite payloads
|
|
102
111
|
|
|
103
|
-
string constant Call = "
|
|
104
|
-
string constant Step = "
|
|
105
|
-
string constant Relay = "
|
|
106
|
-
string constant Dispatch = "
|
|
107
|
-
string constant Context = "
|
|
108
|
-
string constant Recover = "
|
|
109
|
-
string constant Annotation = "
|
|
112
|
+
string constant Call = "uint target, uint resources, #bytes as payload";
|
|
113
|
+
string constant Step = "uint cmd, uint resources, #bytes as input";
|
|
114
|
+
string constant Relay = "uint portal, uint resources, #bytes as input";
|
|
115
|
+
string constant Dispatch = "uint portal, uint resources, #bytes as payload";
|
|
116
|
+
string constant Context = "bytes32 account, #bytes as state, #bytes as input";
|
|
117
|
+
string constant Recover = "uint handler, uint resources, bytes32 key, #bytes as witness";
|
|
118
|
+
string constant Annotation = "uint entity, #bytes as data";
|
|
110
119
|
|
|
111
120
|
// Annotation payloads
|
|
112
121
|
|
|
113
|
-
string constant Action = "
|
|
114
|
-
string constant Label = "
|
|
115
|
-
string constant Schema = "
|
|
122
|
+
string constant Action = "uint action";
|
|
123
|
+
string constant Label = "bytes32 namespace, #string as name";
|
|
124
|
+
string constant Schema = "uint spec, #string as body, bytes32 name";
|
|
116
125
|
}
|
|
117
126
|
|
package/codec/Writers.sol
CHANGED
|
@@ -73,6 +73,14 @@ library Writers {
|
|
|
73
73
|
// Append helpers
|
|
74
74
|
// -------------------------------------------------------------------------
|
|
75
75
|
|
|
76
|
+
/// @notice Append an empty block.
|
|
77
|
+
/// @param writer Destination writer.
|
|
78
|
+
/// @param key Block key.
|
|
79
|
+
function appendEmpty(Writer memory writer, bytes4 key) internal pure {
|
|
80
|
+
uint i = reserve(writer, Sizes.Header);
|
|
81
|
+
Blocks.writeEmpty(writer.dst, i, key);
|
|
82
|
+
}
|
|
83
|
+
|
|
76
84
|
/// @notice Append arbitrary bytes to the writer.
|
|
77
85
|
/// @param writer Destination writer; `i` is advanced by `data.length`.
|
|
78
86
|
/// @param data Bytes to append.
|