@crossecute/protocol 0.0.0 → 0.1.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/README.md +25 -1
- package/abi/Blake2b256.json +1 -0
- package/abi/Blake2bScheme.json +1 -0
- package/abi/ChainRegistry.json +1 -0
- package/abi/Commitment.json +1 -0
- package/abi/Conduits.json +1 -0
- package/abi/DivergentConduits.json +1 -0
- package/abi/DivergentTransceiver.json +1 -0
- package/abi/DivergentTransceiverExtension.json +1 -0
- package/abi/Envelope.json +1 -0
- package/abi/Erc7930.json +1 -0
- package/abi/Executor.json +1 -0
- package/abi/IBootstrapAllowlist.json +1 -0
- package/abi/ICancel.json +1 -0
- package/abi/IChainRegistryRefs.json +1 -0
- package/abi/ICommitFinalize.json +1 -0
- package/abi/ICommitmentScheme.json +1 -0
- package/abi/IConduitReceiverReport.json +1 -0
- package/abi/IConduitTransceiver.json +1 -0
- package/abi/IERC7786GatewaySource.json +1 -0
- package/abi/IERC7786Recipient.json +1 -0
- package/abi/IExecute.json +1 -0
- package/abi/ILzOftConduitFactory.json +1 -0
- package/abi/IProviderIdTable.json +1 -0
- package/abi/IProxy.json +1 -0
- package/abi/IReceiverInit.json +1 -0
- package/abi/IRefValidator.json +1 -0
- package/abi/IReportFloat.json +1 -0
- package/abi/ITransmitterInit.json +1 -0
- package/abi/IVmDeriver.json +1 -0
- package/abi/KeccakScheme.json +1 -0
- package/abi/Move.json +1 -0
- package/abi/MoveValidator.json +1 -0
- package/abi/OpStackTransmitterBase.json +1 -0
- package/abi/OutboundBase.json +1 -0
- package/abi/OwnableTransmitter.json +1 -0
- package/abi/ProviderAddress.json +1 -0
- package/abi/ProviderAttribute.json +1 -0
- package/abi/ProviderChainId.json +1 -0
- package/abi/ProviderReceiver.json +1 -0
- package/abi/ProviderTransceiver.json +1 -0
- package/abi/Proxy.json +1 -0
- package/abi/ProxyDeployer.json +1 -0
- package/abi/ProxyInitCode.json +1 -0
- package/abi/ReceiverBase.json +1 -0
- package/abi/Roles.json +1 -0
- package/abi/RolesEnumerable.json +1 -0
- package/abi/SchemeFold.json +1 -0
- package/abi/Sha256Scheme.json +1 -0
- package/abi/StarknetDerive.json +1 -0
- package/abi/StarknetValidator.json +1 -0
- package/abi/SuiDerive.json +1 -0
- package/abi/TransceiverBase.json +1 -0
- package/abi/TransceiverCore.json +1 -0
- package/abi/TransceiverExtension.json +1 -0
- package/abi/TransmitterBase.json +1 -0
- package/abi/Treasury.json +1 -0
- package/abi/TronConduits.json +1 -0
- package/abi/TronTransceiver.json +1 -0
- package/abi/TronTransceiverExtension.json +1 -0
- package/abi/VmDeriver.json +1 -0
- package/abi/ZkSyncConduits.json +1 -0
- package/abi/ZkSyncTransceiver.json +1 -0
- package/abi/ZkSyncTransceiverExtension.json +1 -0
- package/abi/index.d.ts +63 -0
- package/abi/index.js +63 -0
- package/contracts/addressing/ChainKey.sol +45 -0
- package/contracts/addressing/ChainType.sol +50 -0
- package/contracts/addressing/Erc7930.sol +209 -0
- package/contracts/addressing/Move.sol +212 -0
- package/contracts/conduit/Conduits.sol +43 -0
- package/contracts/conduit/Proxy.sol +144 -0
- package/contracts/conduit/ProxyDeployer.sol +42 -0
- package/contracts/conduit/ProxyInitCode.sol +47 -0
- package/contracts/derivation/AddressDerive.sol +326 -0
- package/contracts/derivation/BitcoinDerive.sol +33 -0
- package/contracts/derivation/Blake2b256.sol +122 -0
- package/contracts/derivation/IVmDeriver.sol +35 -0
- package/contracts/derivation/StarknetDerive.sol +93 -0
- package/contracts/derivation/SuiDerive.sol +102 -0
- package/contracts/derivation/VmDeriver.sol +291 -0
- package/contracts/messaging/Call.sol +43 -0
- package/contracts/messaging/Commitment.sol +131 -0
- package/contracts/messaging/DeliveryGas.sol +18 -0
- package/contracts/messaging/Envelope.sol +123 -0
- package/contracts/messaging/Executor.sol +52 -0
- package/contracts/messaging/IErc7786.sol +68 -0
- package/contracts/messaging/Payload.sol +90 -0
- package/contracts/messaging/Roles.sol +113 -0
- package/contracts/messaging/inbound/ReceiverBase.sol +359 -0
- package/contracts/messaging/outbound/OutboundBase.sol +221 -0
- package/contracts/messaging/outbound/OwnableTransmitter.sol +23 -0
- package/contracts/messaging/outbound/TransmitterBase.sol +604 -0
- package/contracts/messaging/transceiver/DivergentConduits.sol +92 -0
- package/contracts/messaging/transceiver/DivergentTransceiver.sol +97 -0
- package/contracts/messaging/transceiver/IBootstrapAllowlist.sol +8 -0
- package/contracts/messaging/transceiver/TransceiverBase.sol +541 -0
- package/contracts/messaging/transceiver/TransceiverCore.sol +307 -0
- package/contracts/messaging/transceiver/TransceiverExtension.sol +278 -0
- package/contracts/protocols/ProviderAddress.sol +32 -0
- package/contracts/protocols/ProviderAttribute.sol +65 -0
- package/contracts/protocols/ProviderChainId.sol +115 -0
- package/contracts/protocols/ProviderReceiver.sol +24 -0
- package/contracts/protocols/ProviderTransceiver.sol +48 -0
- package/contracts/protocols/layerzero/ILzOftConduitFactory.sol +10 -0
- package/contracts/protocols/op-stack/OpStackTransmitterBase.sol +11 -0
- package/contracts/registry/ChainRegistry.sol +667 -0
- package/contracts/registry/IChainRegistryRefs.sol +81 -0
- package/contracts/registry/ICommitmentScheme.sol +46 -0
- package/contracts/registry/IRefValidator.sol +13 -0
- package/contracts/registry/Provenance.sol +25 -0
- package/contracts/schemes/Blake2bScheme.sol +18 -0
- package/contracts/schemes/KeccakScheme.sol +19 -0
- package/contracts/schemes/Sha256Scheme.sol +15 -0
- package/contracts/treasury/Treasury.sol +76 -0
- package/contracts/validators/MoveValidator.sol +24 -0
- package/contracts/validators/StarknetValidator.sol +20 -0
- package/package.json +34 -3
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.20;
|
|
3
|
+
|
|
4
|
+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
5
|
+
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|
6
|
+
|
|
7
|
+
import {IVmDeriver} from "../derivation/IVmDeriver.sol";
|
|
8
|
+
import {AddressDerive} from "../derivation/AddressDerive.sol";
|
|
9
|
+
import {Provenance} from "./Provenance.sol";
|
|
10
|
+
import {ProviderDeployment, Status} from "./IChainRegistryRefs.sol";
|
|
11
|
+
import {IRefValidator} from "./IRefValidator.sol";
|
|
12
|
+
import {ICommitmentScheme, SchemeFold} from "./ICommitmentScheme.sol";
|
|
13
|
+
import {Erc7930} from "../addressing/Erc7930.sol";
|
|
14
|
+
import {Move} from "../addressing/Move.sol";
|
|
15
|
+
import {PROXY_DEPLOYER, proxySalt} from "../conduit/ProxyDeployer.sol";
|
|
16
|
+
|
|
17
|
+
/// @notice A provider a registry is born knowing, with the CREATE2 inputs its contracts
|
|
18
|
+
/// deploy from.
|
|
19
|
+
struct ProviderSeed {
|
|
20
|
+
string name;
|
|
21
|
+
bytes32 salt;
|
|
22
|
+
bytes32 proxyInitCodeHash;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// @notice What a registry is born knowing: enough for a transceiver on this chain to accept,
|
|
26
|
+
/// with no owner call, the bootstrap that creates its owner (the governor's conduit).
|
|
27
|
+
/// @dev Identical on every chain, so the registry lands at one CREATE2 address on each. Empty
|
|
28
|
+
/// on a chain configured by its owner from the start.
|
|
29
|
+
struct RegistrySeed {
|
|
30
|
+
/// The governor's home chain, as an ERC-7930 chain identifier.
|
|
31
|
+
bytes governorHome;
|
|
32
|
+
Provenance governorHomeGrade;
|
|
33
|
+
/// The account that deployed every seeded provider's transceiver on the home, and the
|
|
34
|
+
/// registry's initial `currentDeployer`. Required when a home and providers are seeded.
|
|
35
|
+
address deployer;
|
|
36
|
+
ProviderSeed[] providers;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// @dev One slot.
|
|
40
|
+
struct ChainSupport {
|
|
41
|
+
address deployedBy;
|
|
42
|
+
Status status;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// @title ChainRegistry
|
|
46
|
+
/// @notice One per chain, shared by every provider there: the directory of every chain this one
|
|
47
|
+
/// talks to, and of what can be known about addresses on each.
|
|
48
|
+
///
|
|
49
|
+
/// @dev It answers questions about a chain, never about a counterpart: a transceiver's
|
|
50
|
+
/// location is per provider and lives on that provider's transceiver, while how well an
|
|
51
|
+
/// address on a chain can be known is the same for every provider, so it is answered here
|
|
52
|
+
/// once.
|
|
53
|
+
///
|
|
54
|
+
/// @dev It holds a directory of chainKeys and message providers, and the per-chain policy a
|
|
55
|
+
/// transceiver consults before recording anything: `provenanceFor`, `isSuspended`,
|
|
56
|
+
/// `validateLocation`, `expectedTransceiver`, and `commitmentFor`. It holds no routes and
|
|
57
|
+
/// no counterparts, and no conduit reads it, so a compromised registry cannot misroute a
|
|
58
|
+
/// conduit's payload.
|
|
59
|
+
///
|
|
60
|
+
/// @dev Fixed: no proxy and no upgrade path, and a transceiver's pointer to it is write-once.
|
|
61
|
+
/// A chain's grade is write-once too, and so is the deployer a provider is added on a chain
|
|
62
|
+
/// under; the plugins (validator,
|
|
63
|
+
/// deriver, derive params, commitment scheme) stay rebindable so their mistakes can be
|
|
64
|
+
/// fixed, and every change waits out the owning timelock.
|
|
65
|
+
contract ChainRegistry is Ownable {
|
|
66
|
+
using EnumerableSet for EnumerableSet.Bytes32Set;
|
|
67
|
+
|
|
68
|
+
/* ================================= storage ================================= */
|
|
69
|
+
|
|
70
|
+
/// Set of keccak256(canonical ERC-7930 chain identifier).
|
|
71
|
+
EnumerableSet.Bytes32Set private _chainKeys;
|
|
72
|
+
/// chainKey => the canonical chain identifier it hashes from. Kept after removal.
|
|
73
|
+
mapping(bytes32 => bytes) private _chainIdentifier;
|
|
74
|
+
|
|
75
|
+
/// Set of keccak256(message provider name).
|
|
76
|
+
EnumerableSet.Bytes32Set private _messageProviders;
|
|
77
|
+
/// messageProvider => the name it hashes from.
|
|
78
|
+
mapping(bytes32 => string) private _messageProviderName;
|
|
79
|
+
/// messageProvider => the CREATE2 inputs its transceiver and conduits deploy from.
|
|
80
|
+
mapping(bytes32 => ProviderDeployment) private _deployment;
|
|
81
|
+
|
|
82
|
+
/// The deployer a provider added from now on is recorded under. See `setCurrentDeployer`.
|
|
83
|
+
address public currentDeployer;
|
|
84
|
+
/// chainKey => messageProvider => who deployed that provider's transceiver there, and whether
|
|
85
|
+
/// sends may reach it. Packs into one slot.
|
|
86
|
+
mapping(bytes32 => mapping(bytes32 => ChainSupport)) private _support;
|
|
87
|
+
|
|
88
|
+
/// messageProvider => the transceiver on this chain that serves it.
|
|
89
|
+
mapping(bytes32 => address) private _localTransceiver;
|
|
90
|
+
/// The reverse: which provider a transceiver on this chain serves.
|
|
91
|
+
mapping(address => bytes32) private _providerOfTransceiver;
|
|
92
|
+
|
|
93
|
+
/// chainKey => the contract that computes addresses on that chain, so callers never
|
|
94
|
+
/// branch on VM.
|
|
95
|
+
mapping(bytes32 => IVmDeriver) private _deriverOf;
|
|
96
|
+
/// chainKey => the abi-encoded `(Scheme, bytes)` its deriver expects. Stored so
|
|
97
|
+
/// `expectedTransceiver` takes no inputs.
|
|
98
|
+
mapping(bytes32 => bytes) private _deriveParams;
|
|
99
|
+
|
|
100
|
+
/// chainKey => optional value-range validator for what ERC-7930 cannot express, e.g.
|
|
101
|
+
/// Starknet felts.
|
|
102
|
+
mapping(bytes32 => IRefValidator) private _validatorOf;
|
|
103
|
+
/// chainKey => what an address claim about this chain is worth, given at registration.
|
|
104
|
+
/// @dev `Unique` for chains this contract cannot recompute: Starknet (Pedersen), and
|
|
105
|
+
/// zkSync and Tron (different CREATE2).
|
|
106
|
+
mapping(bytes32 => Provenance) private _provenanceOf;
|
|
107
|
+
/// chainKey => whether transceivers refuse it. See `setSuspended`.
|
|
108
|
+
mapping(bytes32 => bool) private _suspended;
|
|
109
|
+
|
|
110
|
+
/// chainKey => messageProvider => abi-encoded `Move.MoveQualifier` for that provider's
|
|
111
|
+
/// transceiver there.
|
|
112
|
+
/// @dev A Move call target is `address::module::function`, so the address alone does not
|
|
113
|
+
/// identify it. Advisory: only a destination executor off-chain reads it.
|
|
114
|
+
mapping(bytes32 => mapping(bytes32 => bytes)) private _qualifiers;
|
|
115
|
+
|
|
116
|
+
/// chainKey => the primitive that chain's receiver hashes commitments with.
|
|
117
|
+
/// @dev A mapping rather than the `Scheme` enum, which is compiled into every locked
|
|
118
|
+
/// transmitter and cannot grow. Mutable because nothing enforces with it: a receiver
|
|
119
|
+
/// checks its own compiled fold.
|
|
120
|
+
mapping(bytes32 => ICommitmentScheme) private _commitmentSchemeOf;
|
|
121
|
+
|
|
122
|
+
/* ================================== events ================================= */
|
|
123
|
+
|
|
124
|
+
event ChainKeyAdded(bytes32 indexed chainKey, bytes chainIdentifier, Provenance provenance);
|
|
125
|
+
event ChainKeyRemoved(bytes32 indexed chainKey);
|
|
126
|
+
event MessageProviderAdded(bytes32 indexed messageProvider, string name);
|
|
127
|
+
event MessageProviderRemoved(bytes32 indexed messageProvider);
|
|
128
|
+
event LocalTransceiverSet(bytes32 indexed messageProvider, address transceiver);
|
|
129
|
+
event ProviderDeploymentSet(bytes32 indexed messageProvider, bytes32 salt, bytes32 proxyInitCodeHash);
|
|
130
|
+
event CurrentDeployerSet(address deployer);
|
|
131
|
+
event ProviderAddedOnChain(bytes32 indexed chainKey, bytes32 indexed messageProvider, address deployedBy);
|
|
132
|
+
event PendingRekeyed(bytes32 indexed chainKey, bytes32 indexed messageProvider, address deployedBy);
|
|
133
|
+
event MarkedLive(bytes32 indexed chainKey, bytes32 indexed messageProvider);
|
|
134
|
+
event DeriverSet(bytes32 indexed chainKey, address deriver);
|
|
135
|
+
event DeriveParamsSet(bytes32 indexed chainKey, uint8 scheme, bytes32 paramsHash);
|
|
136
|
+
event ValidatorSet(bytes32 indexed chainKey, address validator);
|
|
137
|
+
event SuspendedSet(bytes32 indexed chainKey, bool suspended);
|
|
138
|
+
event QualifierSet(bytes32 indexed chainKey, bytes32 indexed messageProvider, bytes32 qualifierHash);
|
|
139
|
+
event CommitmentSchemeSet(bytes32 indexed chainKey, address scheme);
|
|
140
|
+
|
|
141
|
+
/* ================================== errors ================================= */
|
|
142
|
+
|
|
143
|
+
/// @dev A write-once value, once recorded, is fixed: a provider deployment, a chain's grade,
|
|
144
|
+
/// the deployer a provider was added on a chain under, or a Move qualifier.
|
|
145
|
+
error AlreadySet();
|
|
146
|
+
/// @dev Only an `eip155` chain can be `Predetermined`: that is the grade the EVM CREATE2
|
|
147
|
+
/// prediction trusts.
|
|
148
|
+
error NotEvmChain();
|
|
149
|
+
error NoCounterpart();
|
|
150
|
+
/// @dev No salt recorded for this provider.
|
|
151
|
+
error NoProviderDeployment();
|
|
152
|
+
error ZeroSalt();
|
|
153
|
+
error ZeroDeployedBy();
|
|
154
|
+
/// @dev The call named a deployer other than `currentDeployer`: a registry that applied a
|
|
155
|
+
/// rotation in another order refuses instead of recording a different one.
|
|
156
|
+
error DeployerMismatch(address expected, address current);
|
|
157
|
+
/// @dev The provider was never added on this chain.
|
|
158
|
+
error NotOnChain(bytes32 chainKey, bytes32 messageProvider);
|
|
159
|
+
/// @dev Only a `Pending` entry can be re-keyed or marked live.
|
|
160
|
+
error NotPending(bytes32 chainKey, bytes32 messageProvider);
|
|
161
|
+
error ZeroInitCodeHash();
|
|
162
|
+
error UnknownChainKey();
|
|
163
|
+
error UnknownMessageProvider();
|
|
164
|
+
error EmptyName();
|
|
165
|
+
error NoDeriver();
|
|
166
|
+
error NoDeriveParams();
|
|
167
|
+
error DeriverChainMismatch();
|
|
168
|
+
error SchemeNotSupported();
|
|
169
|
+
/// @dev No primitive registered for this chain. Reverting beats returning a digest the
|
|
170
|
+
/// destination might never match; see `Commitment._hash`.
|
|
171
|
+
error NoCommitmentScheme();
|
|
172
|
+
error NoQualifier();
|
|
173
|
+
|
|
174
|
+
/* =============================== constructor =============================== */
|
|
175
|
+
|
|
176
|
+
/// @param owner_ This chain's timelock.
|
|
177
|
+
/// @dev Seeding goes through the same internal setters the owner uses later, so a seeded
|
|
178
|
+
/// entry is write-once exactly like one added afterwards.
|
|
179
|
+
constructor(address owner_, RegistrySeed memory seed) Ownable(owner_) {
|
|
180
|
+
if (seed.deployer != address(0)) _setCurrentDeployer(seed.deployer);
|
|
181
|
+
bytes32 home;
|
|
182
|
+
if (seed.governorHome.length != 0) home = _addChainKey(seed.governorHome, seed.governorHomeGrade);
|
|
183
|
+
for (uint256 i; i < seed.providers.length; ++i) {
|
|
184
|
+
ProviderSeed memory p = seed.providers[i];
|
|
185
|
+
bytes32 provider = _addMessageProvider(p.name);
|
|
186
|
+
_setProviderDeployment(provider, p.salt, p.proxyInitCodeHash);
|
|
187
|
+
if (home != bytes32(0)) _addProviderOnChain(home, provider, seed.deployer, Status.Live);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* ================================ directory ================================ */
|
|
192
|
+
|
|
193
|
+
/// @notice Register a chain by its ERC-7930 chain identifier, with what an address claim
|
|
194
|
+
/// about it is worth.
|
|
195
|
+
/// @dev Takes the envelope, not a hash, so `parseStrict` rejects a non-canonical framing
|
|
196
|
+
/// before it becomes a permanent key.
|
|
197
|
+
/// @dev The grade is write-once and has no default, so whether the chain reports its
|
|
198
|
+
/// receivers is fixed when it is first registered, even across a removal. The same
|
|
199
|
+
/// grade again is a no-op.
|
|
200
|
+
/// @param identifier ERC-7930 bytes. A conduit envelope is accepted and reduced to
|
|
201
|
+
/// its chain identifier form.
|
|
202
|
+
function addChainKey(bytes calldata identifier, Provenance provenance)
|
|
203
|
+
external
|
|
204
|
+
onlyOwner
|
|
205
|
+
returns (bytes32 chainKey)
|
|
206
|
+
{
|
|
207
|
+
return _addChainKey(identifier, provenance);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function _addChainKey(bytes memory identifier, Provenance provenance) private returns (bytes32 chainKey) {
|
|
211
|
+
bytes memory canonical = Erc7930.toChainIdentifier(identifier);
|
|
212
|
+
chainKey = keccak256(canonical);
|
|
213
|
+
|
|
214
|
+
if (_chainIdentifier[chainKey].length != 0) {
|
|
215
|
+
if (_provenanceOf[chainKey] != provenance) revert AlreadySet();
|
|
216
|
+
} else {
|
|
217
|
+
if (provenance == Provenance.Predetermined && Erc7930.parseStrict(canonical).chainType != Erc7930.CT_EIP155)
|
|
218
|
+
{
|
|
219
|
+
revert NotEvmChain();
|
|
220
|
+
}
|
|
221
|
+
_chainIdentifier[chainKey] = canonical;
|
|
222
|
+
_provenanceOf[chainKey] = provenance;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (_chainKeys.add(chainKey)) emit ChainKeyAdded(chainKey, canonical, provenance);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/// @notice Drop a chain from the directory.
|
|
229
|
+
/// @dev Stops onboarding only: `validateLocation` requires membership, so no transceiver
|
|
230
|
+
/// can record a new counterpart there. Its identifier and grade stay, so transceivers
|
|
231
|
+
/// keep bootstrapping to it and accepting its reports; removal must not strand
|
|
232
|
+
/// conduits. Cutting a chain off is `setSuspended`, which still applies after removal.
|
|
233
|
+
function removeChainKey(bytes32 chainKey) external onlyOwner {
|
|
234
|
+
if (!_chainKeys.remove(chainKey)) revert UnknownChainKey();
|
|
235
|
+
emit ChainKeyRemoved(chainKey);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/// @notice Refuse a chain, or stop refusing it.
|
|
239
|
+
/// @dev Every transceiver here reads this with the grade, in `_counterpartOn`, so a
|
|
240
|
+
/// suspended chain gets no bootstrap or report and is accepted as no origin. It can only
|
|
241
|
+
/// refuse, so lifting it is as safe as setting it. Conduits already standing on the
|
|
242
|
+
/// chain still send to each other directly. Applies to a removed chain too: any chain
|
|
243
|
+
/// ever registered can be cut off.
|
|
244
|
+
function setSuspended(bytes32 chainKey, bool suspended) external onlyOwner {
|
|
245
|
+
if (_chainIdentifier[chainKey].length == 0) revert UnknownChainKey();
|
|
246
|
+
_suspended[chainKey] = suspended;
|
|
247
|
+
emit SuspendedSet(chainKey, suspended);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/// @notice Whether transceivers refuse `chainKey`.
|
|
251
|
+
function isSuspended(bytes32 chainKey) external view returns (bool) {
|
|
252
|
+
return _suspended[chainKey];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/// @notice Register a message provider by name; the key is keccak256 of the name.
|
|
256
|
+
function addMessageProvider(string calldata name) external onlyOwner returns (bytes32 messageProvider) {
|
|
257
|
+
return _addMessageProvider(name);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function _addMessageProvider(string memory name) private returns (bytes32 messageProvider) {
|
|
261
|
+
if (bytes(name).length == 0) revert EmptyName();
|
|
262
|
+
messageProvider = keccak256(bytes(name));
|
|
263
|
+
if (_messageProviders.add(messageProvider)) {
|
|
264
|
+
_messageProviderName[messageProvider] = name;
|
|
265
|
+
emit MessageProviderAdded(messageProvider, name);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function removeMessageProvider(bytes32 messageProvider) external onlyOwner {
|
|
270
|
+
if (!_messageProviders.remove(messageProvider)) revert UnknownMessageProvider();
|
|
271
|
+
delete _messageProviderName[messageProvider];
|
|
272
|
+
emit MessageProviderRemoved(messageProvider);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* ============================== configuration ============================== */
|
|
276
|
+
|
|
277
|
+
/// @notice Record the transceiver on this chain that serves one message provider. Zero
|
|
278
|
+
/// retires the provider's entry.
|
|
279
|
+
function setLocalTransceiver(bytes32 messageProvider, address transceiver_) external onlyOwner {
|
|
280
|
+
if (!_messageProviders.contains(messageProvider)) revert UnknownMessageProvider();
|
|
281
|
+
|
|
282
|
+
address prev = _localTransceiver[messageProvider];
|
|
283
|
+
if (prev != address(0)) delete _providerOfTransceiver[prev];
|
|
284
|
+
|
|
285
|
+
_localTransceiver[messageProvider] = transceiver_;
|
|
286
|
+
if (transceiver_ != address(0)) _providerOfTransceiver[transceiver_] = messageProvider;
|
|
287
|
+
|
|
288
|
+
emit LocalTransceiverSet(messageProvider, transceiver_);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/// @notice Record the CREATE2 inputs a provider's contracts share on every chain.
|
|
292
|
+
///
|
|
293
|
+
/// @dev Write-once: changing the salt or initcode hash moves the provider's transceiver on
|
|
294
|
+
/// every chain and every conduit under it. The identical record again is a no-op.
|
|
295
|
+
///
|
|
296
|
+
/// @dev Deploys nothing; it lets any chain reproduce the addresses. A record that does not
|
|
297
|
+
/// match the deployment yields predictions that match nothing.
|
|
298
|
+
function setProviderDeployment(bytes32 messageProvider, bytes32 salt, bytes32 proxyInitCodeHash)
|
|
299
|
+
external
|
|
300
|
+
onlyOwner
|
|
301
|
+
{
|
|
302
|
+
_setProviderDeployment(messageProvider, salt, proxyInitCodeHash);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function _setProviderDeployment(bytes32 messageProvider, bytes32 salt, bytes32 proxyInitCodeHash) private {
|
|
306
|
+
if (!_messageProviders.contains(messageProvider)) {
|
|
307
|
+
revert UnknownMessageProvider();
|
|
308
|
+
}
|
|
309
|
+
if (salt == bytes32(0)) revert ZeroSalt();
|
|
310
|
+
if (proxyInitCodeHash == bytes32(0)) revert ZeroInitCodeHash();
|
|
311
|
+
|
|
312
|
+
ProviderDeployment storage d = _deployment[messageProvider];
|
|
313
|
+
if (d.salt != bytes32(0)) {
|
|
314
|
+
if (d.salt != salt || d.proxyInitCodeHash != proxyInitCodeHash) revert AlreadySet();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
_deployment[messageProvider] = ProviderDeployment({salt: salt, proxyInitCodeHash: proxyInitCodeHash});
|
|
319
|
+
emit ProviderDeploymentSet(messageProvider, salt, proxyInitCodeHash);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function providerDeployment(bytes32 messageProvider) external view returns (ProviderDeployment memory) {
|
|
323
|
+
return _deployment[messageProvider];
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* ============================ deployer rotation ============================ */
|
|
327
|
+
|
|
328
|
+
/// @notice Change the deployer later `addProviderOnChain` calls must name.
|
|
329
|
+
/// @dev Touches no entry already recorded, so no existing address moves.
|
|
330
|
+
function setCurrentDeployer(address deployer) external onlyOwner {
|
|
331
|
+
_setCurrentDeployer(deployer);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function _setCurrentDeployer(address deployer) private {
|
|
335
|
+
if (deployer == address(0)) revert ZeroDeployedBy();
|
|
336
|
+
currentDeployer = deployer;
|
|
337
|
+
emit CurrentDeployerSet(deployer);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/// @notice Record that a provider's transceiver on `chainKey` is deployed by `expectedDeployer`,
|
|
341
|
+
/// `Pending` until `markLive`.
|
|
342
|
+
/// @dev Write-once. `expectedDeployer` must be `currentDeployer`, so a registry that applies
|
|
343
|
+
/// this before or after a rotation reverts instead of recording a different deployer
|
|
344
|
+
/// than its peers. The same deployer again is a no-op.
|
|
345
|
+
function addProviderOnChain(bytes32 chainKey, bytes32 messageProvider, address expectedDeployer)
|
|
346
|
+
external
|
|
347
|
+
onlyOwner
|
|
348
|
+
{
|
|
349
|
+
_addProviderOnChain(chainKey, messageProvider, expectedDeployer, Status.Pending);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function _addProviderOnChain(bytes32 chainKey, bytes32 messageProvider, address expectedDeployer, Status status)
|
|
353
|
+
private
|
|
354
|
+
{
|
|
355
|
+
if (!_chainKeys.contains(chainKey)) revert UnknownChainKey();
|
|
356
|
+
if (!_messageProviders.contains(messageProvider)) revert UnknownMessageProvider();
|
|
357
|
+
if (_deployment[messageProvider].salt == bytes32(0)) revert NoProviderDeployment();
|
|
358
|
+
if (expectedDeployer == address(0)) revert ZeroDeployedBy();
|
|
359
|
+
|
|
360
|
+
ChainSupport storage s = _support[chainKey][messageProvider];
|
|
361
|
+
if (s.status != Status.None) {
|
|
362
|
+
if (s.deployedBy != expectedDeployer) revert AlreadySet();
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (expectedDeployer != currentDeployer) revert DeployerMismatch(expectedDeployer, currentDeployer);
|
|
366
|
+
|
|
367
|
+
s.deployedBy = expectedDeployer;
|
|
368
|
+
s.status = status;
|
|
369
|
+
emit ProviderAddedOnChain(chainKey, messageProvider, expectedDeployer);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/// @notice Change the deployer a `Pending` entry is predicted under, for a chain added before
|
|
373
|
+
/// a rotation and not yet deployed.
|
|
374
|
+
/// @dev Never a `Live` entry: its transceiver exists and its address is fixed.
|
|
375
|
+
function rekeyPending(bytes32 chainKey, bytes32 messageProvider, address newDeployer) external onlyOwner {
|
|
376
|
+
ChainSupport storage s = _support[chainKey][messageProvider];
|
|
377
|
+
if (s.status != Status.Pending) revert NotPending(chainKey, messageProvider);
|
|
378
|
+
if (newDeployer == address(0)) revert ZeroDeployedBy();
|
|
379
|
+
s.deployedBy = newDeployer;
|
|
380
|
+
emit PendingRekeyed(chainKey, messageProvider, newDeployer);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/// @notice Allow sends to a provider's transceiver on `chainKey`.
|
|
384
|
+
/// @dev Call only after the deployment is checked without the deployer's help: code at the
|
|
385
|
+
/// predicted address, the implementation's code hash, and `owner()`, `chainRegistry()` and
|
|
386
|
+
/// `messageProvider()`. This contract cannot read another chain's code, so the check is
|
|
387
|
+
/// the proposers' and the timelock delay is its review window.
|
|
388
|
+
function markLive(bytes32 chainKey, bytes32 messageProvider) external onlyOwner {
|
|
389
|
+
ChainSupport storage s = _support[chainKey][messageProvider];
|
|
390
|
+
if (s.status != Status.Pending) revert NotPending(chainKey, messageProvider);
|
|
391
|
+
s.status = Status.Live;
|
|
392
|
+
emit MarkedLive(chainKey, messageProvider);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/// @notice Whether sends to `messageProvider`'s transceiver on `chainKey` are allowed.
|
|
396
|
+
function isLive(bytes32 chainKey, bytes32 messageProvider) external view returns (bool) {
|
|
397
|
+
return _support[chainKey][messageProvider].status == Status.Live;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/// @notice The state of `messageProvider` on `chainKey`.
|
|
401
|
+
function statusOf(bytes32 chainKey, bytes32 messageProvider) external view returns (Status) {
|
|
402
|
+
return _support[chainKey][messageProvider].status;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/// @notice Who deployed, or will deploy, `messageProvider`'s transceiver on `chainKey`; zero
|
|
406
|
+
/// where it was never added.
|
|
407
|
+
function deployedBy(bytes32 chainKey, bytes32 messageProvider) external view returns (address) {
|
|
408
|
+
return _support[chainKey][messageProvider].deployedBy;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* ========================= PATH 2: salted derivation ======================= */
|
|
412
|
+
|
|
413
|
+
/// @notice Where a provider's transceiver lands on `chainKey`, recomputed from
|
|
414
|
+
/// `PROXY_DEPLOYER`, the deployer recorded for that chain, and the provider's
|
|
415
|
+
/// salt and initcode hash.
|
|
416
|
+
function predictTransceiver(bytes32 chainKey, bytes32 messageProvider) public view returns (address) {
|
|
417
|
+
ProviderDeployment memory d = _deployment[messageProvider];
|
|
418
|
+
if (d.salt == bytes32(0)) revert NoProviderDeployment();
|
|
419
|
+
_requireEvmDerivable(chainKey);
|
|
420
|
+
address by = _support[chainKey][messageProvider].deployedBy;
|
|
421
|
+
if (by == address(0)) revert NotOnChain(chainKey, messageProvider);
|
|
422
|
+
return AddressDerive.create2(PROXY_DEPLOYER, proxySalt(by, d.salt), d.proxyInitCodeHash);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/// @notice Where an owner's conduit lands on `chainKey`, before it exists: the
|
|
426
|
+
/// transceiver from the provider's salt, then the conduit from the transceiver.
|
|
427
|
+
/// @dev The conduit salt must match `TransceiverCore._conduitSalt`; it is written out
|
|
428
|
+
/// rather than imported, and `test/SaltedDeployment.t.sol` asserts the two agree.
|
|
429
|
+
/// @param homeChainKey The chain the conduit is homed on, which need not be `chainKey`.
|
|
430
|
+
function predictConduit(
|
|
431
|
+
bytes32 chainKey,
|
|
432
|
+
bytes32 messageProvider,
|
|
433
|
+
address owner,
|
|
434
|
+
bytes32 salt,
|
|
435
|
+
bytes32 homeChainKey
|
|
436
|
+
) external view returns (address) {
|
|
437
|
+
ProviderDeployment memory d = _deployment[messageProvider];
|
|
438
|
+
if (d.salt == bytes32(0)) revert NoProviderDeployment();
|
|
439
|
+
|
|
440
|
+
address transceiver = predictTransceiver(chainKey, messageProvider);
|
|
441
|
+
return AddressDerive.create2(transceiver, keccak256(abi.encode(owner, salt, homeChainKey)), d.proxyInitCodeHash);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/// @dev Plain CREATE2 derivation holds only on a chain graded `Predetermined`.
|
|
445
|
+
function _requireEvmDerivable(bytes32 chainKey) private view {
|
|
446
|
+
if (!_isEvmDerivable(chainKey)) revert NoCounterpart();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function _isEvmDerivable(bytes32 chainKey) private view returns (bool) {
|
|
450
|
+
return uint8(provenanceFor(chainKey)) >= uint8(Provenance.Predetermined);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/// @notice What an address claim about `chainKey` is worth, as given at registration.
|
|
454
|
+
/// @dev Answers for a removed chain; reverts only for one never registered.
|
|
455
|
+
function provenanceFor(bytes32 chainKey) public view returns (Provenance) {
|
|
456
|
+
if (_chainIdentifier[chainKey].length == 0) revert UnknownChainKey();
|
|
457
|
+
return _provenanceOf[chainKey];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/// @notice Whether conduits on `chainKey` must report their own address home.
|
|
461
|
+
/// @dev True exactly where this contract cannot recompute addresses, so it cannot
|
|
462
|
+
/// disagree with the grades. Where a receiver landed is held by its transmitter, not
|
|
463
|
+
/// here. The home's side of `TransceiverExtension.addressesDiverge`.
|
|
464
|
+
function requiresReceiverCallback(bytes32 chainKey) external view returns (bool) {
|
|
465
|
+
return !_isEvmDerivable(chainKey);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/// @notice Check a location against everything this chain says about its addresses: the
|
|
469
|
+
/// ERC-7930 canonicity rules, that it is on `chainKey`, and the chain's validator.
|
|
470
|
+
/// @dev A transceiver calls this before recording a counterpart, so one validator per chain serves
|
|
471
|
+
/// every provider.
|
|
472
|
+
function validateLocation(bytes32 chainKey, bytes calldata interop) external view {
|
|
473
|
+
if (!_chainKeys.contains(chainKey)) revert UnknownChainKey();
|
|
474
|
+
// `parseStrict` runs inside: rejects bad versions, length mismatches, trailing
|
|
475
|
+
// bytes, and non-minimal eip155 chain references.
|
|
476
|
+
if (Erc7930.chainKey(interop) != chainKey) revert UnknownChainKey();
|
|
477
|
+
|
|
478
|
+
IRefValidator v = _validatorOf[chainKey];
|
|
479
|
+
if (address(v) != address(0)) v.validateRef(interop);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/// @notice Attach a value-range validator to a chain.
|
|
483
|
+
function setValidator(bytes32 chainKey, IRefValidator validator) external onlyOwner {
|
|
484
|
+
if (!_chainKeys.contains(chainKey)) revert UnknownChainKey();
|
|
485
|
+
_validatorOf[chainKey] = validator;
|
|
486
|
+
emit ValidatorSet(chainKey, address(validator));
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* ============================ Move qualifiers ============================= */
|
|
490
|
+
|
|
491
|
+
/// @notice Attach a qualified name to a provider's transceiver on a Move chain.
|
|
492
|
+
/// @dev Write-once: the same qualifier again is a no-op and a different one reverts
|
|
493
|
+
/// `AlreadySet`, since re-pointing a call target is re-pointing the counterpart.
|
|
494
|
+
function setQualifier(bytes32 chainKey, bytes32 messageProvider, Move.MoveQualifier calldata q) external onlyOwner {
|
|
495
|
+
bytes memory identifier = _chainIdentifier[chainKey];
|
|
496
|
+
if (identifier.length == 0) revert UnknownChainKey();
|
|
497
|
+
if (!_messageProviders.contains(messageProvider)) revert UnknownMessageProvider();
|
|
498
|
+
Move.validate(q, Erc7930.parseStrict(identifier).chainType);
|
|
499
|
+
|
|
500
|
+
bytes32 qh = Move.hash(q);
|
|
501
|
+
bytes memory existing = _qualifiers[chainKey][messageProvider];
|
|
502
|
+
if (existing.length != 0) {
|
|
503
|
+
if (Move.hash(abi.decode(existing, (Move.MoveQualifier))) != qh) revert AlreadySet();
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
_qualifiers[chainKey][messageProvider] = abi.encode(q);
|
|
507
|
+
emit QualifierSet(chainKey, messageProvider, qh);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/// @notice The qualified name a destination executor needs to build the call.
|
|
511
|
+
function qualifier(bytes32 chainKey, bytes32 messageProvider) external view returns (Move.MoveQualifier memory q) {
|
|
512
|
+
bytes memory raw = _qualifiers[chainKey][messageProvider];
|
|
513
|
+
if (raw.length == 0) revert NoQualifier();
|
|
514
|
+
q = abi.decode(raw, (Move.MoveQualifier));
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/* ========================== commitment preview ============================ */
|
|
518
|
+
|
|
519
|
+
/// @notice Teach this registry the primitive `chainKey`'s receiver hashes with.
|
|
520
|
+
/// @dev Rebindable: it redirects nothing, so a wrong primitive must be fixable. Zero
|
|
521
|
+
/// unregisters, and `commitmentFor` then reverts rather than answer wrongly.
|
|
522
|
+
function setCommitmentScheme(bytes32 chainKey, ICommitmentScheme scheme) external onlyOwner {
|
|
523
|
+
if (!_chainKeys.contains(chainKey)) revert UnknownChainKey();
|
|
524
|
+
_commitmentSchemeOf[chainKey] = scheme;
|
|
525
|
+
emit CommitmentSchemeSet(chainKey, address(scheme));
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/// @notice Preview the commitment `chainKey`'s receiver will require over `elements`.
|
|
529
|
+
/// @dev For `eth_call` by a signer checking a payload; nothing on-chain may enforce with
|
|
530
|
+
/// it. The fold is `SchemeFold`'s.
|
|
531
|
+
function commitmentFor(bytes32 chainKey, bytes[] calldata elements) external view returns (bytes32) {
|
|
532
|
+
ICommitmentScheme scheme = _commitmentSchemeOf[chainKey];
|
|
533
|
+
if (address(scheme) == address(0)) revert NoCommitmentScheme();
|
|
534
|
+
return SchemeFold.hashCalls(scheme, chainKey, elements);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/* ================= PATH 1 (uniform): per-chain derivation ================== */
|
|
538
|
+
|
|
539
|
+
/// @notice Point a chain at the contract that computes addresses on it.
|
|
540
|
+
function setDeriver(bytes32 chainKey, IVmDeriver deriver) external onlyOwner {
|
|
541
|
+
if (!_chainKeys.contains(chainKey)) revert UnknownChainKey();
|
|
542
|
+
_deriverOf[chainKey] = deriver;
|
|
543
|
+
emit DeriverSet(chainKey, address(deriver));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/// @notice Store the derivation inputs for a chain, checked against its deriver now
|
|
547
|
+
/// rather than at the first resolve.
|
|
548
|
+
/// @param params abi.encode(VmDeriver.Scheme, bytes): shape is the scheme's business.
|
|
549
|
+
function setDeriveParams(bytes32 chainKey, bytes calldata params) external onlyOwner {
|
|
550
|
+
IVmDeriver d = _deriverOf[chainKey];
|
|
551
|
+
if (address(d) == address(0)) revert NoDeriver();
|
|
552
|
+
|
|
553
|
+
uint16 ct = Erc7930.parseStrict(_chainIdentifier[chainKey]).chainType;
|
|
554
|
+
(uint8 scheme,) = abi.decode(params, (uint8, bytes));
|
|
555
|
+
if (!d.supportsScheme(ct, scheme)) revert SchemeNotSupported();
|
|
556
|
+
|
|
557
|
+
_deriveParams[chainKey] = params;
|
|
558
|
+
emit DeriveParamsSet(chainKey, scheme, keccak256(params));
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/// @notice The transceiver envelope expected on `chainKey`, recomputed now, whatever VM
|
|
562
|
+
/// that chain runs.
|
|
563
|
+
/// @dev A deriver is external code: without the chainKey re-check a wrong one could return
|
|
564
|
+
/// another chain's envelope for a transceiver to record as this chain's counterpart.
|
|
565
|
+
function expectedTransceiver(bytes32 chainKey) public view returns (bytes memory interop) {
|
|
566
|
+
IVmDeriver d = _deriverOf[chainKey];
|
|
567
|
+
if (address(d) == address(0)) revert NoDeriver();
|
|
568
|
+
bytes memory params = _deriveParams[chainKey];
|
|
569
|
+
if (params.length == 0) revert NoDeriveParams();
|
|
570
|
+
|
|
571
|
+
interop = d.deriveAddress(_chainIdentifier[chainKey], params);
|
|
572
|
+
if (Erc7930.chainKey(interop) != chainKey) revert DeriverChainMismatch();
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/// @notice Every destination at once: the expected transceiver on each registered chain.
|
|
576
|
+
/// @dev Unconfigured or underivable chains yield an empty entry rather than reverting.
|
|
577
|
+
function expectedTransceivers() external view returns (bytes32[] memory keys, bytes[] memory interops) {
|
|
578
|
+
keys = _chainKeys.values();
|
|
579
|
+
uint256 n = keys.length;
|
|
580
|
+
interops = new bytes[](n);
|
|
581
|
+
|
|
582
|
+
for (uint256 i; i < n; ++i) {
|
|
583
|
+
if (address(_deriverOf[keys[i]]) == address(0)) continue;
|
|
584
|
+
if (_deriveParams[keys[i]].length == 0) continue;
|
|
585
|
+
// forge-lint: disable-next-line(calls-loop) a view self-call; failure is caught
|
|
586
|
+
try this.expectedTransceiver(keys[i]) returns (bytes memory io) {
|
|
587
|
+
interops[i] = io;
|
|
588
|
+
} catch {
|
|
589
|
+
// Leave empty: an underivable chain is expected, not exceptional.
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/// @notice The stored derivation inputs for a chain.
|
|
595
|
+
function deriveParams(bytes32 chainKey) external view returns (bytes memory) {
|
|
596
|
+
return _deriveParams[chainKey];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/* ============================ configuration reads ========================== */
|
|
600
|
+
|
|
601
|
+
/// @notice The transceiver on this chain that serves `messageProvider`.
|
|
602
|
+
function localTransceiver(bytes32 messageProvider) external view returns (address) {
|
|
603
|
+
return _localTransceiver[messageProvider];
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/// @notice Which provider a transceiver on this chain serves.
|
|
607
|
+
function providerOfTransceiver(address transceiver_) external view returns (bytes32) {
|
|
608
|
+
return _providerOfTransceiver[transceiver_];
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function deriverOf(bytes32 chainKey) external view returns (IVmDeriver) {
|
|
612
|
+
return _deriverOf[chainKey];
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function validatorOf(bytes32 chainKey) external view returns (IRefValidator) {
|
|
616
|
+
return _validatorOf[chainKey];
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function commitmentSchemeOf(bytes32 chainKey) external view returns (ICommitmentScheme) {
|
|
620
|
+
return _commitmentSchemeOf[chainKey];
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/* ============================== directory reads ============================ */
|
|
624
|
+
|
|
625
|
+
function chainKeyCount() external view returns (uint256) {
|
|
626
|
+
return _chainKeys.length();
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function chainKeyAt(uint256 i) external view returns (bytes32) {
|
|
630
|
+
return _chainKeys.at(i);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function chainKeys() external view returns (bytes32[] memory) {
|
|
634
|
+
return _chainKeys.values();
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function hasChainKey(bytes32 chainKey) external view returns (bool) {
|
|
638
|
+
return _chainKeys.contains(chainKey);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/// @notice The canonical ERC-7930 chain identifier a `chainKey` hashes from.
|
|
642
|
+
function chainIdentifier(bytes32 chainKey) external view returns (bytes memory) {
|
|
643
|
+
if (!_chainKeys.contains(chainKey)) revert UnknownChainKey();
|
|
644
|
+
return _chainIdentifier[chainKey];
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function messageProviderCount() external view returns (uint256) {
|
|
648
|
+
return _messageProviders.length();
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function messageProviderAt(uint256 i) external view returns (bytes32) {
|
|
652
|
+
return _messageProviders.at(i);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function messageProviders() external view returns (bytes32[] memory) {
|
|
656
|
+
return _messageProviders.values();
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function hasMessageProvider(bytes32 messageProvider) external view returns (bool) {
|
|
660
|
+
return _messageProviders.contains(messageProvider);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function messageProviderName(bytes32 messageProvider) external view returns (string memory) {
|
|
664
|
+
if (!_messageProviders.contains(messageProvider)) revert UnknownMessageProvider();
|
|
665
|
+
return _messageProviderName[messageProvider];
|
|
666
|
+
}
|
|
667
|
+
}
|