@rootzero/contracts 1.3.0 → 1.5.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 +37 -0
- package/Endpoints.sol +4 -3
- package/Events.sol +3 -3
- package/README.md +58 -31
- package/Utils.sol +4 -3
- package/blocks/Cursors.sol +83 -143
- package/blocks/Keys.sol +15 -15
- package/blocks/Schema.sol +27 -28
- package/blocks/Writers.sol +26 -33
- package/commands/Base.sol +2 -2
- package/commands/Burn.sol +3 -4
- package/commands/Credit.sol +3 -4
- package/commands/Debit.sol +4 -5
- package/commands/Deposit.sol +8 -10
- package/commands/Payout.sol +3 -6
- package/commands/Withdraw.sol +3 -4
- package/commands/admin/AllowAssets.sol +5 -6
- package/commands/admin/Allowance.sol +3 -4
- package/commands/admin/DenyAssets.sol +5 -6
- package/commands/admin/Execute.sol +2 -2
- package/core/Access.sol +2 -2
- package/core/Balances.sol +10 -11
- package/core/Calls.sol +7 -7
- package/core/Host.sol +2 -2
- package/core/Runtime.sol +3 -3
- package/core/Types.sol +0 -14
- package/docs/Schema.md +29 -10
- package/events/Asset.sol +17 -3
- package/events/Balance.sol +2 -3
- package/events/Commander.sol +19 -0
- package/events/Labeled.sol +6 -6
- package/events/Locked.sol +2 -3
- package/events/Position.sol +2 -3
- package/events/Received.sol +2 -3
- package/events/Route.sol +18 -0
- package/events/Spent.sol +2 -3
- package/events/Unlocked.sol +2 -3
- package/guards/Base.sol +4 -4
- package/package.json +1 -1
- package/peer/AllowAssets.sol +3 -3
- package/peer/Allowance.sol +2 -2
- package/peer/Base.sol +4 -4
- package/peer/Credit.sol +10 -10
- package/peer/Debit.sol +10 -10
- package/peer/DenyAssets.sol +3 -3
- package/peer/Recover.sol +51 -0
- package/peer/Redeem.sol +48 -0
- package/peer/Settle.sol +3 -3
- package/queries/Assets.sol +7 -8
- package/queries/Balances.sol +8 -9
- package/queries/Base.sol +4 -4
- package/queries/Positions.sol +4 -6
- package/utils/Accounts.sol +76 -58
- package/utils/Actions.sol +1 -0
- package/utils/Assets.sol +55 -115
- package/utils/Ids.sol +33 -233
- package/utils/Layout.sol +11 -17
- package/utils/Nodes.sol +263 -0
- package/utils/Utils.sol +9 -24
- package/events/Chain.sol +0 -19
- package/events/Transfer.sol +0 -22
- package/peer/BalancePull.sol +0 -49
package/utils/Assets.sol
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
4
|
import {Layout} from "./Layout.sol";
|
|
5
|
-
import {
|
|
5
|
+
import {Ids} from "./Ids.sol";
|
|
6
|
+
import {ensureAddr, isFamily, matchesBase, toLocalBase} from "./Utils.sol";
|
|
6
7
|
|
|
7
8
|
/// @title Assets
|
|
8
9
|
/// @notice Encoding and decoding helpers for 256-bit asset identifiers.
|
|
@@ -10,8 +11,12 @@ import {matchesBase, toLocalBase} from "./Utils.sol";
|
|
|
10
11
|
/// Asset IDs embed a 4-byte type tag in bits [255:224]:
|
|
11
12
|
/// - `Native` - native chain coin/token; no address payload
|
|
12
13
|
/// - `Erc20` - ERC-20 token; contract address in bits [191:32]
|
|
13
|
-
///
|
|
14
|
-
///
|
|
14
|
+
///
|
|
15
|
+
/// If the first byte is zero, the asset is an opaque
|
|
16
|
+
/// `0x00 || bytes31(hash)` ID. The full asset metadata must be supplied by
|
|
17
|
+
/// lookup or witness data when native token handling needs it.
|
|
18
|
+
///
|
|
19
|
+
/// The helpers in this library validate and deconstruct structured asset IDs.
|
|
15
20
|
///
|
|
16
21
|
/// All asset IDs are chain-local (include `block.chainid` in bits [223:192]).
|
|
17
22
|
library Assets {
|
|
@@ -20,28 +25,21 @@ library Assets {
|
|
|
20
25
|
/// @dev Thrown when an asset is not authorized for the requested operation.
|
|
21
26
|
error UnauthorizedAsset();
|
|
22
27
|
|
|
28
|
+
/// @dev 24-bit family tag shared by all EVM-backed asset types.
|
|
29
|
+
uint24 constant Family = (uint24(Layout.Evm) << 8) | uint24(Layout.Asset);
|
|
23
30
|
/// @dev Full 4-byte type prefix for the native chain coin/token asset.
|
|
24
|
-
uint32 constant Native = (uint32(Layout.
|
|
31
|
+
uint32 constant Native = (uint32(Layout.Evm) << 16) | (uint32(Layout.Asset) << 8) | uint32(Layout.Native);
|
|
25
32
|
/// @dev Full 4-byte type prefix for ERC-20 assets.
|
|
26
|
-
uint32 constant Erc20 = (uint32(Layout.
|
|
27
|
-
/// @dev Full 4-byte type prefix for ERC-721 assets.
|
|
28
|
-
uint32 constant Erc721 = (uint32(Layout.Evm64) << 16) | (uint32(Layout.Asset) << 8) | uint32(Layout.Erc721);
|
|
29
|
-
/// @dev Full 4-byte type prefix for ERC-1155 assets.
|
|
30
|
-
uint32 constant Erc1155 = (uint32(Layout.Evm64) << 16) | (uint32(Layout.Asset) << 8) | uint32(Layout.Erc1155);
|
|
31
|
-
|
|
32
|
-
/// @notice Return true if `asset` uses the Asset category tag in the type field.
|
|
33
|
-
function isAsset(bytes32 asset) internal pure returns (bool) {
|
|
34
|
-
return uint8(uint(asset) >> 232) == Layout.Asset;
|
|
35
|
-
}
|
|
33
|
+
uint32 constant Erc20 = (uint32(Layout.Evm) << 16) | (uint32(Layout.Asset) << 8) | uint32(Layout.Erc20);
|
|
36
34
|
|
|
37
|
-
/// @notice Return true if `asset`
|
|
38
|
-
function
|
|
39
|
-
return
|
|
35
|
+
/// @notice Return true if `asset` belongs to the EVM asset family.
|
|
36
|
+
function isEvm(bytes32 asset) internal pure returns (bool) {
|
|
37
|
+
return isFamily(uint(asset), Family);
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
/// @notice Return true if `asset`
|
|
43
|
-
function
|
|
44
|
-
return
|
|
40
|
+
/// @notice Return true if `asset` is opaque.
|
|
41
|
+
function isOpaque(bytes32 asset) internal pure returns (bool) {
|
|
42
|
+
return Ids.isOpaque(asset);
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
/// @notice Return true if `asset` is the local native chain coin/token asset.
|
|
@@ -54,46 +52,36 @@ library Assets {
|
|
|
54
52
|
return matchesBase(asset, toLocalBase(Erc20));
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
/// @notice
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
function isErc1155(bytes32 asset) internal view returns (bool) {
|
|
64
|
-
return matchesBase(asset, toLocalBase(Erc1155));
|
|
55
|
+
/// @notice Assert that `value` belongs to the EVM asset family and return it unchanged.
|
|
56
|
+
/// @param value Asset identifier to validate.
|
|
57
|
+
/// @return asset The same `value` if it is an EVM asset.
|
|
58
|
+
function evm(bytes32 value) internal pure returns (bytes32 asset) {
|
|
59
|
+
if (!isEvm(value)) revert InvalidAsset();
|
|
60
|
+
return value;
|
|
65
61
|
}
|
|
66
62
|
|
|
67
|
-
/// @notice Assert that `
|
|
68
|
-
/// @param
|
|
69
|
-
/// @return asset The same `
|
|
70
|
-
function
|
|
71
|
-
if (!
|
|
72
|
-
return
|
|
63
|
+
/// @notice Assert that `value` is an opaque asset and return it unchanged.
|
|
64
|
+
/// @param value Asset identifier to validate.
|
|
65
|
+
/// @return asset The same `value` if it is opaque.
|
|
66
|
+
function opaque(bytes32 value) internal pure returns (bytes32 asset) {
|
|
67
|
+
if (!Ids.isOpaque(value)) revert InvalidAsset();
|
|
68
|
+
return value;
|
|
73
69
|
}
|
|
74
70
|
|
|
75
|
-
/// @notice Assert that `
|
|
76
|
-
/// @param
|
|
77
|
-
/// @return asset The same `
|
|
78
|
-
function
|
|
79
|
-
if (!
|
|
80
|
-
return
|
|
71
|
+
/// @notice Assert that `value` is the local native chain coin/token asset and return it unchanged.
|
|
72
|
+
/// @param value Asset identifier to validate.
|
|
73
|
+
/// @return asset The same `value` if it is the local native asset.
|
|
74
|
+
function native(bytes32 value) internal view returns (bytes32 asset) {
|
|
75
|
+
if (!isNative(value)) revert InvalidAsset();
|
|
76
|
+
return value;
|
|
81
77
|
}
|
|
82
78
|
|
|
83
|
-
/// @notice Assert that `
|
|
84
|
-
/// @param
|
|
85
|
-
/// @return asset The same `
|
|
86
|
-
function
|
|
87
|
-
if (!
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/// @notice Assert that `input` is a local ERC-1155 asset and return it unchanged.
|
|
92
|
-
/// @param input Asset identifier to validate.
|
|
93
|
-
/// @return asset The same `input` if it is a local ERC-1155 asset.
|
|
94
|
-
function erc1155(bytes32 input) internal view returns (bytes32 asset) {
|
|
95
|
-
if (!isErc1155(input)) revert InvalidAsset();
|
|
96
|
-
return input;
|
|
79
|
+
/// @notice Assert that `value` is a local ERC-20 asset and return it unchanged.
|
|
80
|
+
/// @param value Asset identifier to validate.
|
|
81
|
+
/// @return asset The same `value` if it is a local ERC-20 asset.
|
|
82
|
+
function erc20(bytes32 value) internal view returns (bytes32 asset) {
|
|
83
|
+
if (!isErc20(value)) revert InvalidAsset();
|
|
84
|
+
return value;
|
|
97
85
|
}
|
|
98
86
|
|
|
99
87
|
/// @notice Create a chain-local native coin/token asset ID.
|
|
@@ -109,18 +97,20 @@ library Assets {
|
|
|
109
97
|
return bytes32(toLocalBase(Erc20) | (uint(uint160(addr)) << 32));
|
|
110
98
|
}
|
|
111
99
|
|
|
112
|
-
/// @notice
|
|
113
|
-
/// @param
|
|
114
|
-
/// @return
|
|
115
|
-
function
|
|
116
|
-
return
|
|
100
|
+
/// @notice Derive an opaque asset ID from a keccak preimage.
|
|
101
|
+
/// @param preimage Preimage whose first byte is `0x01`.
|
|
102
|
+
/// @return asset `0x00 || bytes31(keccak256(preimage))`.
|
|
103
|
+
function toKeccak(bytes memory preimage) internal pure returns (bytes32 asset) {
|
|
104
|
+
return Ids.toKeccak(preimage);
|
|
117
105
|
}
|
|
118
106
|
|
|
119
|
-
/// @notice
|
|
120
|
-
/// @param
|
|
121
|
-
/// @
|
|
122
|
-
|
|
123
|
-
|
|
107
|
+
/// @notice Assert that `asset` matches the opaque keccak ID for `preimage`.
|
|
108
|
+
/// @param asset Opaque asset ID to validate.
|
|
109
|
+
/// @param preimage Preimage whose first byte is `0x01`.
|
|
110
|
+
/// @return The same `asset` value if it matches.
|
|
111
|
+
function matchKeccak(bytes32 asset, bytes memory preimage) internal pure returns (bytes32) {
|
|
112
|
+
if (asset != Ids.toKeccak(preimage)) revert InvalidAsset();
|
|
113
|
+
return asset;
|
|
124
114
|
}
|
|
125
115
|
|
|
126
116
|
/// @notice Extract the ERC-20 contract address from an asset ID.
|
|
@@ -128,7 +118,7 @@ library Assets {
|
|
|
128
118
|
/// @param asset ERC-20 asset identifier.
|
|
129
119
|
/// @return Token contract address embedded in bits [191:32].
|
|
130
120
|
function erc20Addr(bytes32 asset) internal view returns (address) {
|
|
131
|
-
return address(uint160(uint(erc20(asset)) >> 32));
|
|
121
|
+
return ensureAddr(address(uint160(uint(erc20(asset)) >> 32)));
|
|
132
122
|
}
|
|
133
123
|
|
|
134
124
|
/// @notice Assert that `asset` is a local ERC-20 for `token` and return it unchanged.
|
|
@@ -141,56 +131,6 @@ library Assets {
|
|
|
141
131
|
return asset;
|
|
142
132
|
}
|
|
143
133
|
|
|
144
|
-
/// @notice Extract the ERC-721 collection address from an asset ID.
|
|
145
|
-
/// Reverts if `asset` is not a local ERC-721 asset.
|
|
146
|
-
/// @param asset ERC-721 asset identifier.
|
|
147
|
-
/// @return Collection contract address embedded in bits [191:32].
|
|
148
|
-
function erc721Collection(bytes32 asset) internal view returns (address) {
|
|
149
|
-
return address(uint160(uint(erc721(asset)) >> 32));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/// @notice Assert that `asset` is a local ERC-721 for `collection` and return it unchanged.
|
|
153
|
-
/// Reverts if `asset` is not a local ERC-721 asset or if its collection address differs.
|
|
154
|
-
/// @param asset ERC-721 asset identifier.
|
|
155
|
-
/// @param collection Expected ERC-721 collection address.
|
|
156
|
-
/// @return The same `asset` value if valid.
|
|
157
|
-
function matchErc721(bytes32 asset, address collection) internal view returns (bytes32) {
|
|
158
|
-
if (erc721Collection(asset) != collection) revert InvalidAsset();
|
|
159
|
-
return asset;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/// @notice Extract the ERC-1155 collection address from an asset ID.
|
|
163
|
-
/// Reverts if `asset` is not a local ERC-1155 asset.
|
|
164
|
-
/// @param asset ERC-1155 asset identifier.
|
|
165
|
-
/// @return Collection contract address embedded in bits [191:32].
|
|
166
|
-
function erc1155Collection(bytes32 asset) internal view returns (address) {
|
|
167
|
-
return address(uint160(uint(erc1155(asset)) >> 32));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/// @notice Assert that `asset` is a local ERC-1155 for `collection` and return it unchanged.
|
|
171
|
-
/// Reverts if `asset` is not a local ERC-1155 asset or if its collection address differs.
|
|
172
|
-
/// @param asset ERC-1155 asset identifier.
|
|
173
|
-
/// @param collection Expected ERC-1155 collection address.
|
|
174
|
-
/// @return The same `asset` value if valid.
|
|
175
|
-
function matchErc1155(bytes32 asset, address collection) internal view returns (bytes32) {
|
|
176
|
-
if (erc1155Collection(asset) != collection) revert InvalidAsset();
|
|
177
|
-
return asset;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/// @notice Derive a storage slot for an (asset, meta) pair.
|
|
181
|
-
/// For 32-byte assets (no meta), the slot is the asset ID itself.
|
|
182
|
-
/// For assets with metadata (e.g. ERC-721 or ERC-1155 token IDs), the slot is
|
|
183
|
-
/// `keccak256(asset ++ meta)`.
|
|
184
|
-
/// Reverts only if `asset` is zero.
|
|
185
|
-
/// For 32-byte assets, `meta` is ignored and does not affect the derived slot.
|
|
186
|
-
/// @param asset Asset identifier.
|
|
187
|
-
/// @param meta Asset metadata slot (e.g. token ID context).
|
|
188
|
-
/// @return Storage slot for the (asset, meta) combination.
|
|
189
|
-
function slot(bytes32 asset, bytes32 meta) internal pure returns (bytes32) {
|
|
190
|
-
if (is32(asset)) return asset;
|
|
191
|
-
if (meta == 0 || !is64(asset)) revert InvalidAsset();
|
|
192
|
-
return keccak256(bytes.concat(asset, meta));
|
|
193
|
-
}
|
|
194
134
|
}
|
|
195
135
|
|
|
196
136
|
/// @title Amounts
|
package/utils/Ids.sol
CHANGED
|
@@ -1,250 +1,50 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
pragma solidity ^0.8.33;
|
|
3
3
|
|
|
4
|
-
import {Layout} from "./Layout.sol";
|
|
5
|
-
import {isLocalFamily, matchesBase, toLocalBase} from "./Utils.sol";
|
|
6
|
-
|
|
7
4
|
/// @title Ids
|
|
8
|
-
/// @notice
|
|
5
|
+
/// @notice Shared helpers for the protocol-wide 256-bit ID convention.
|
|
6
|
+
///
|
|
7
|
+
/// IDs whose first byte is zero are opaque:
|
|
8
|
+
/// `[0x00][bytes31 truncated hash]`
|
|
9
9
|
///
|
|
10
|
-
///
|
|
11
|
-
///
|
|
12
|
-
/// - bits [223:192] — current `block.chainid` (makes IDs chain-local)
|
|
13
|
-
/// - bits [191:160] — 4-byte ABI selector (commands and peers only)
|
|
14
|
-
/// - bits [159:0] — 160-bit EVM contract address
|
|
10
|
+
/// Opaque keccak preimages start with `0x01`, and the ID is derived as:
|
|
11
|
+
/// `0x00 || bytes31(keccak256(preimage))`
|
|
15
12
|
library Ids {
|
|
16
|
-
/// @dev Thrown when an ID does not match the expected
|
|
13
|
+
/// @dev Thrown when an ID does not match the expected convention.
|
|
17
14
|
error InvalidId();
|
|
15
|
+
/// @dev Thrown when an opaque ID preimage is missing or uses an unsupported format/hash tag.
|
|
16
|
+
error InvalidPreimage();
|
|
18
17
|
|
|
19
|
-
/// @dev
|
|
20
|
-
|
|
21
|
-
/// @dev Full 4-byte type prefix for chain/domain nodes.
|
|
22
|
-
uint32 constant Chain = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Chain);
|
|
23
|
-
/// @dev Full 4-byte type prefix for host nodes.
|
|
24
|
-
uint32 constant Host = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Host);
|
|
25
|
-
/// @dev Full 4-byte type prefix for command nodes.
|
|
26
|
-
uint32 constant Command = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Command);
|
|
27
|
-
/// @dev Full 4-byte type prefix for peer nodes.
|
|
28
|
-
uint32 constant Peer = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Peer);
|
|
29
|
-
/// @dev Full 4-byte type prefix for query nodes.
|
|
30
|
-
uint32 constant Query = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Query);
|
|
31
|
-
/// @dev Full 4-byte type prefix for guard action nodes.
|
|
32
|
-
uint32 constant Guard = (uint32(Layout.Evm32) << 16) | (uint32(Layout.Node) << 8) | uint32(Layout.Guard);
|
|
33
|
-
|
|
34
|
-
/// @notice Return true if `id` is a host node ID.
|
|
35
|
-
function isHost(uint id) internal pure returns (bool) {
|
|
36
|
-
return uint32(id >> 224) == Host;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/// @notice Return true if `id` is a command node ID.
|
|
40
|
-
function isCommand(uint id) internal pure returns (bool) {
|
|
41
|
-
return uint32(id >> 224) == Command;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/// @notice Return true if `id` is a peer node ID.
|
|
45
|
-
function isPeer(uint id) internal pure returns (bool) {
|
|
46
|
-
return uint32(id >> 224) == Peer;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/// @notice Return true if `id` is a query node ID.
|
|
50
|
-
function isQuery(uint id) internal pure returns (bool) {
|
|
51
|
-
return uint32(id >> 224) == Query;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/// @notice Return true if `id` is a guard action node ID.
|
|
55
|
-
function isGuard(uint id) internal pure returns (bool) {
|
|
56
|
-
return uint32(id >> 224) == Guard;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/// @notice Return true if `id` is a local node ID for this contract.
|
|
60
|
-
function isLocalNode(uint id) internal view returns (bool) {
|
|
61
|
-
return uint32(id >> 224) != Chain && isLocalFamily(id, Node) && address(uint160(id)) == address(this);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/// @notice Assert that `id` is a command ID and return it unchanged.
|
|
65
|
-
/// @param id Node ID to validate.
|
|
66
|
-
/// @return cid The same `id` value if it is a command.
|
|
67
|
-
function command(uint id) internal pure returns (uint cid) {
|
|
68
|
-
if (!isCommand(id)) revert InvalidId();
|
|
69
|
-
return id;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/// @notice Assert that `id` is a peer ID and return it unchanged.
|
|
73
|
-
/// @param id Node ID to validate.
|
|
74
|
-
/// @return pid The same `id` value if it is a peer.
|
|
75
|
-
function peer(uint id) internal pure returns (uint pid) {
|
|
76
|
-
if (!isPeer(id)) revert InvalidId();
|
|
77
|
-
return id;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/// @notice Assert that `id` is a query ID and return it unchanged.
|
|
81
|
-
/// @param id Node ID to validate.
|
|
82
|
-
/// @return queryId The same `id` value if it is a query.
|
|
83
|
-
function query(uint id) internal pure returns (uint queryId) {
|
|
84
|
-
if (!isQuery(id)) revert InvalidId();
|
|
85
|
-
return id;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/// @notice Assert that `id` is a guard action ID and return it unchanged.
|
|
89
|
-
/// @param id Node ID to validate.
|
|
90
|
-
/// @return guardId The same `id` value if it is a guard action.
|
|
91
|
-
function guard(uint id) internal pure returns (uint guardId) {
|
|
92
|
-
if (!isGuard(id)) revert InvalidId();
|
|
93
|
-
return id;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/// @notice Assert that `id` is a command ID and return its embedded ABI selector.
|
|
97
|
-
/// @param id Node ID to validate.
|
|
98
|
-
/// @return selector 4-byte command selector stored in bits [191:160].
|
|
99
|
-
function commandSelector(uint id) internal pure returns (bytes4 selector) {
|
|
100
|
-
return bytes4(uint32(command(id) >> 160));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/// @notice Assert that `id` is a peer ID and return its embedded ABI selector.
|
|
104
|
-
/// @param id Node ID to validate.
|
|
105
|
-
/// @return selector 4-byte peer selector stored in bits [191:160].
|
|
106
|
-
function peerSelector(uint id) internal pure returns (bytes4 selector) {
|
|
107
|
-
return bytes4(uint32(peer(id) >> 160));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/// @notice Assert that `id` is a query ID and return its embedded ABI selector.
|
|
111
|
-
/// @param id Node ID to validate.
|
|
112
|
-
/// @return selector 4-byte query selector stored in bits [191:160].
|
|
113
|
-
function querySelector(uint id) internal pure returns (bytes4 selector) {
|
|
114
|
-
return bytes4(uint32(query(id) >> 160));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/// @notice Assert that `id` is a guard action ID and return its embedded ABI selector.
|
|
118
|
-
/// @param id Node ID to validate.
|
|
119
|
-
/// @return selector 4-byte guard selector stored in bits [191:160].
|
|
120
|
-
function guardSelector(uint id) internal pure returns (bytes4 selector) {
|
|
121
|
-
return bytes4(uint32(guard(id) >> 160));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/// @notice Assert that `id` is the host ID of `addr` on the current chain.
|
|
125
|
-
/// @param id Node ID to validate.
|
|
126
|
-
/// @param addr Expected host contract address.
|
|
127
|
-
/// @return hid The same `id` value if it matches `addr`.
|
|
128
|
-
function matchHost(uint id, address addr) internal view returns (uint hid) {
|
|
129
|
-
if (id != toHost(addr)) revert InvalidId();
|
|
130
|
-
return id;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/// @notice Build the chain node ID for the current chain.
|
|
134
|
-
/// @return Chain node ID with the Chain prefix and `block.chainid` payload.
|
|
135
|
-
function localChain() internal view returns (uint) {
|
|
136
|
-
uint id = block.chainid;
|
|
137
|
-
if (id >> 224 != 0) revert InvalidId();
|
|
138
|
-
return (uint(Chain) << 224) | id;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/// @notice Build a chain-local host ID for `target`.
|
|
142
|
-
/// @param target Host contract address.
|
|
143
|
-
/// @return Host node ID on the current chain.
|
|
144
|
-
function toHost(address target) internal view returns (uint) {
|
|
145
|
-
return toLocalBase(Host) | uint(uint160(target));
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/// @notice Build a chain-local command ID for the given selector and contract.
|
|
149
|
-
/// @param selector 4-byte ABI selector of the command entry point.
|
|
150
|
-
/// @param target Command contract address.
|
|
151
|
-
/// @return Command node ID embedding both the selector and address.
|
|
152
|
-
function toCommand(bytes4 selector, address target) internal view returns (uint) {
|
|
153
|
-
uint id = toLocalBase(Command) | uint(uint160(target));
|
|
154
|
-
id |= uint(uint32(selector)) << 160;
|
|
155
|
-
return id;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/// @notice Build a chain-local peer ID for the given selector and contract.
|
|
159
|
-
/// @param selector 4-byte ABI selector of the peer entry point.
|
|
160
|
-
/// @param target Peer contract address.
|
|
161
|
-
/// @return Peer node ID embedding both the selector and address.
|
|
162
|
-
function toPeer(bytes4 selector, address target) internal view returns (uint) {
|
|
163
|
-
uint id = toLocalBase(Peer) | uint(uint160(target));
|
|
164
|
-
id |= uint(uint32(selector)) << 160;
|
|
165
|
-
return id;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/// @notice Build a chain-local query ID for the given selector and contract.
|
|
169
|
-
/// @param selector 4-byte ABI selector of the query entry point.
|
|
170
|
-
/// @param target Query contract address.
|
|
171
|
-
/// @return Query node ID embedding both the selector and address.
|
|
172
|
-
function toQuery(bytes4 selector, address target) internal view returns (uint) {
|
|
173
|
-
uint id = toLocalBase(Query) | uint(uint160(target));
|
|
174
|
-
id |= uint(uint32(selector)) << 160;
|
|
175
|
-
return id;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/// @notice Build a chain-local guard action ID for the given selector and contract.
|
|
179
|
-
/// @param selector 4-byte ABI selector of the guard action entry point.
|
|
180
|
-
/// @param target Guard action contract address.
|
|
181
|
-
/// @return Guard action node ID embedding both the selector and address.
|
|
182
|
-
function toGuard(bytes4 selector, address target) internal view returns (uint) {
|
|
183
|
-
uint id = toLocalBase(Guard) | uint(uint160(target));
|
|
184
|
-
id |= uint(uint32(selector)) << 160;
|
|
185
|
-
return id;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/// @notice Extract the contract address from any local node ID.
|
|
189
|
-
/// Reverts if `id` does not belong to the local node family.
|
|
190
|
-
/// @param id Node ID (host, command, or peer).
|
|
191
|
-
/// @return Contract address in the lower 160 bits of `id`.
|
|
192
|
-
function nodeAddr(uint id) internal view returns (address) {
|
|
193
|
-
if (uint32(id >> 224) == Chain || !isLocalFamily(id, Node)) revert InvalidId();
|
|
194
|
-
return address(uint160(id));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/// @notice Extract the contract address from a local host ID.
|
|
198
|
-
/// Reverts if `id` does not match the local host base.
|
|
199
|
-
/// @param id Host node ID.
|
|
200
|
-
/// @return Host contract address in the lower 160 bits of `id`.
|
|
201
|
-
function hostAddr(uint id) internal view returns (address) {
|
|
202
|
-
if (!matchesBase(bytes32(id), toLocalBase(Host))) revert InvalidId();
|
|
203
|
-
return address(uint160(id));
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/// @title Selectors
|
|
208
|
-
/// @notice ABI-selector derivation helpers for command, peer, and query dispatch.
|
|
209
|
-
library Selectors {
|
|
210
|
-
/// @dev ABI argument encoding for command entry points: `((bytes32,bytes,bytes))`.
|
|
211
|
-
string constant CommandArgs = "((bytes32,bytes,bytes))";
|
|
212
|
-
/// @dev ABI argument encoding for peer entry points: `(bytes)`.
|
|
213
|
-
string constant PeerArgs = "(bytes)";
|
|
214
|
-
/// @dev ABI argument encoding for query entry points: `(bytes)`.
|
|
215
|
-
string constant QueryArgs = "(bytes)";
|
|
216
|
-
/// @dev ABI argument encoding for guard action entry points: `(bytes)`.
|
|
217
|
-
string constant GuardArgs = "(bytes)";
|
|
18
|
+
/// @dev Preimage format/hash tag for keccak256-derived opaque IDs.
|
|
19
|
+
uint8 constant Keccak = 0x01;
|
|
218
20
|
|
|
219
|
-
/// @notice
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
/// @return 4-byte selector.
|
|
223
|
-
function command(string memory name) internal pure returns (bytes4) {
|
|
224
|
-
return bytes4(keccak256(bytes.concat(bytes(name), bytes(CommandArgs))));
|
|
21
|
+
/// @notice Return true if `id` is opaque.
|
|
22
|
+
function isOpaque(bytes32 id) internal pure returns (bool) {
|
|
23
|
+
return uint8(uint(id) >> 248) == 0;
|
|
225
24
|
}
|
|
226
25
|
|
|
227
|
-
/// @notice
|
|
228
|
-
///
|
|
229
|
-
/// @
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return
|
|
26
|
+
/// @notice Assert that `value` is opaque and return it unchanged.
|
|
27
|
+
/// @param value ID to validate.
|
|
28
|
+
/// @return id The same `value` if it is opaque.
|
|
29
|
+
function opaque(bytes32 value) internal pure returns (bytes32 id) {
|
|
30
|
+
if (!isOpaque(value)) revert InvalidId();
|
|
31
|
+
return value;
|
|
233
32
|
}
|
|
234
33
|
|
|
235
|
-
/// @notice Derive
|
|
236
|
-
///
|
|
237
|
-
/// @
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
return
|
|
34
|
+
/// @notice Derive an opaque ID from a keccak preimage.
|
|
35
|
+
/// @param preimage Preimage whose first byte is `0x01`.
|
|
36
|
+
/// @return id `0x00 || bytes31(keccak256(preimage))`.
|
|
37
|
+
function toKeccak(bytes memory preimage) internal pure returns (bytes32 id) {
|
|
38
|
+
if (preimage.length == 0 || uint8(preimage[0]) != Keccak) revert InvalidPreimage();
|
|
39
|
+
return bytes32(uint(keccak256(preimage)) >> 8);
|
|
241
40
|
}
|
|
242
41
|
|
|
243
|
-
/// @notice
|
|
244
|
-
///
|
|
245
|
-
/// @param
|
|
246
|
-
/// @return
|
|
247
|
-
function
|
|
248
|
-
|
|
42
|
+
/// @notice Assert that `value` matches the opaque keccak ID for `preimage`.
|
|
43
|
+
/// @param value Opaque ID to validate.
|
|
44
|
+
/// @param preimage Preimage whose first byte is `0x01`.
|
|
45
|
+
/// @return id The same `value` if it matches.
|
|
46
|
+
function matchKeccak(bytes32 value, bytes memory preimage) internal pure returns (bytes32 id) {
|
|
47
|
+
if (value != toKeccak(preimage)) revert InvalidId();
|
|
48
|
+
return value;
|
|
249
49
|
}
|
|
250
50
|
}
|
package/utils/Layout.sol
CHANGED
|
@@ -7,23 +7,21 @@ pragma solidity ^0.8.33;
|
|
|
7
7
|
///
|
|
8
8
|
/// IDs are structured as:
|
|
9
9
|
/// `[uint32 type][uint32 chainid][192-bit payload]`
|
|
10
|
-
/// where `type` is `[
|
|
10
|
+
/// where `type` is `[uint16 representation][uint8 category][uint8 subtype]`.
|
|
11
|
+
///
|
|
12
|
+
/// Values whose first byte is zero are opaque IDs:
|
|
13
|
+
/// `[0x00][bytes31 truncated hash]`
|
|
14
|
+
/// They require lookup or witness data when the native preimage is needed.
|
|
15
|
+
/// Opaque preimages start with a one-byte format/hash tag. `0x01` means the ID
|
|
16
|
+
/// is `0x00 || bytes31(keccak256(preimage))`; remaining bytes are host/domain-specific.
|
|
17
|
+
/// Values whose first byte is nonzero follow the structured layout above.
|
|
11
18
|
library Layout {
|
|
12
19
|
// -------------------------------------------------------------------------
|
|
13
|
-
//
|
|
20
|
+
// Representation tags (top 2 bytes of the ID type field)
|
|
14
21
|
// -------------------------------------------------------------------------
|
|
15
22
|
|
|
16
|
-
/// @dev EVM-compatible
|
|
17
|
-
|
|
18
|
-
/// @dev 32-byte ID; no paired metadata word is required.
|
|
19
|
-
uint8 constant Width32 = 0x20;
|
|
20
|
-
/// @dev 64-byte ID; a paired metadata word completes the identity.
|
|
21
|
-
uint8 constant Width64 = 0x40;
|
|
22
|
-
|
|
23
|
-
/// @dev 32-byte EVM-compatible value; lower 20 bytes hold an address.
|
|
24
|
-
uint16 constant Evm32 = (uint16(Evm) << 8) | uint16(Width32);
|
|
25
|
-
/// @dev 64-byte EVM-compatible value; used when a paired metadata word completes the identity.
|
|
26
|
-
uint16 constant Evm64 = (uint16(Evm) << 8) | uint16(Width64);
|
|
23
|
+
/// @dev EVM-compatible ID; lower 20 payload bytes hold an address when present.
|
|
24
|
+
uint16 constant Evm = 0x0120;
|
|
27
25
|
|
|
28
26
|
// -------------------------------------------------------------------------
|
|
29
27
|
// Category tags (uint8, third byte of the ID type field)
|
|
@@ -71,8 +69,4 @@ library Layout {
|
|
|
71
69
|
uint8 constant Native = 0x01;
|
|
72
70
|
/// @dev ERC-20 fungible token; lower 20 bytes of the ID hold the contract address.
|
|
73
71
|
uint8 constant Erc20 = 0x02;
|
|
74
|
-
/// @dev ERC-721 non-fungible token; lower 20 bytes of the ID hold the collection address.
|
|
75
|
-
uint8 constant Erc721 = 0x03;
|
|
76
|
-
/// @dev ERC-1155 multi-token asset; lower 20 bytes of the ID hold the collection address.
|
|
77
|
-
uint8 constant Erc1155 = 0x04;
|
|
78
72
|
}
|