From f43b764ec0cd38723cac36737b4756a55e2c7267 Mon Sep 17 00:00:00 2001 From: erhant Date: Tue, 24 Dec 2024 21:21:53 +0300 Subject: [PATCH] better foundry profile & faster tests --- .vscode/settings.json | 7 -- README.md | 6 +- docs/src/README.md | 113 ++++++++++++------ .../contract.LLMOracleCoordinator.md | 2 +- .../abstract.LLMOracleManager.md | 2 +- .../contract.LLMOracleRegistry.md | 2 +- .../enum.LLMOracleKind.md | 2 +- .../interface.LLMOracleTask.md | 2 +- .../struct.LLMOracleTaskParameters.md | 2 +- .../src/Statistics.sol/library.Statistics.md | 2 +- .../src/Whitelist.sol/abstract.Whitelist.md | 2 +- foundry.toml | 9 ++ script/Deploy.s.sol | 11 +- test/LLMOracleCoordinator.t.sol | 21 ++-- test/LLMOracleRegistry.t.sol | 8 +- test/script/Deploy.t.sol | 55 --------- 16 files changed, 112 insertions(+), 134 deletions(-) delete mode 100644 test/script/Deploy.t.sol diff --git a/.vscode/settings.json b/.vscode/settings.json index 4ece872..14ee507 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,13 +8,6 @@ }, "solidity.formatter": "forge", "solidity.defaultCompiler": "localFile", - // remappings.txt here fixes random errors - "solidity.remappingsUnix": [ - "forge-std/=lib/forge-std/src/", - "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/", - "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", - "@openzeppelin/foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/" - ], "material-icon-theme.files.associations": { ".gas-snapshot": "bench-ts" } diff --git a/README.md b/README.md index 6f67b0f..afb294e 100644 --- a/README.md +++ b/README.md @@ -187,16 +187,16 @@ forge script ./script/Deploy.s.sol:Upgrade \ Run tests on local network: ```sh -forge test +FOUNDRY_PROFILE=test forge test # or -vvv to show reverts in detail -forge test -vvv +FOUNDRY_PROFILE=test forge test -vvv ``` or fork an existing chain and run the tests on it: ```sh -forge test --rpc-url +FOUNDRY_PROFILE=test forge test --rpc-url ``` ### Code Coverage diff --git a/docs/src/README.md b/docs/src/README.md index 56ad6b0..afb294e 100644 --- a/docs/src/README.md +++ b/docs/src/README.md @@ -45,24 +45,28 @@ forge install Compile the contracts with: ```sh -forge clean && forge build +forge build ``` -### Upgradability - -We are using [openzeppelin-foundry-upgrades](https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades) library. To make sure upgrades are **safe**, you must do one of the following (as per their [docs](https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades?tab=readme-ov-file#before-running)) before you run `forge script` or `forge test`: - -- `forge clean` beforehand, e.g. `forge clean && forge test` -- include `--force` option when running, e.g. `forge test --force` - > [!NOTE] > -> Note that for some users this may fail (see [issue](https://github.com/firstbatchxyz/dria-oracle-contracts/issues/16)) due to a missing NPM package called `@openzeppelin/upgrades-core`. To fix it, do: +> We are using [openzeppelin-foundry-upgrades](https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades) library, which [requires](https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades?tab=readme-ov-file#before-running) clean-up per compilation to ensure upgrades are done safely. We use `force = true` option in `foundry.toml` for this, which may increase build times. +> +> Note that for some users this may fail (see [issue](https://github.com/firstbatchxyz/dria-oracle-contracts/issues/16)) due to a missing NPM package called `@openzeppelin/upgrades-core`. To fix it, you can install the package manually: > > ```sh > npm install @openzeppelin/upgrades-core@latest -g > ``` +> [!TIP] +> +> If at any point the submodules become "dirty" (e.g. there are local changes that you are unaware of) you can do: +> +> ```sh +> git submodule deinit -f . +> git submodule update --init --recursive --checkout +> ``` + ### Updates To update contracts to the latest library versions, use: @@ -75,7 +79,10 @@ forge update ### Setup -To be able to use our contracts, we need an [Ethereum Wallet](#create-wallet), and an [RPC endpoint](#prepare-rpc-endpoint). +To be able to deploy & use our contracts, we need two things: + +- [Ethereum Wallet](#create-wallet) +- [RPC endpoint](#prepare-rpc-endpoint) ### Create Wallet @@ -107,23 +114,37 @@ To interact with the blockchain, we require an RPC endpoint. You can get one fro You will use this endpoint for the commands that interact with the blockchain, such as deploying and upgrading; or while doing fork tests. -### Deploy & Verify Contract +### Deploy Contract Deploy the contract with: ```sh -forge clean && forge script ./script/Deploy.s.sol:Deploy \ +forge script ./script/Deploy.s.sol:Deploy \ --rpc-url \ --account \ --broadcast ``` -You can see deployed contract addresses under the `deployment/.json` +You can see deployed contract addresses under the [`deployments/.json`](./deployments/) folder. -You can verify the contract during deployment by adding the verification arguments as well: +You will need the contract ABIs to interact with them as well, thankfully there is a nice short-hand command to export that: ```sh -forge clean && forge script ./script/Deploy.s.sol:Deploy \ +forge inspect abi > ./deployments/abis/.json +``` + +### Verify Contract + +Verification requires the following values, based on which provider you are using: + +- **Provider**: can accept any of `etherscan`, `blockscout`, `sourcify`, `oklink` or `custom` for more fine-grained stuff. +- **URL**: based on the chosen provider, we require its URL as well, e.g. `https://base-sepolia.blockscout.com/api/` for `blockscout` on Base Sepolia +- **API Key**: an API key from the chosen provider, must be stored as `ETHERSCAN_API_KEY` in environment no matter whicih provider it is!. + +You can actually verify the contract during deployment by adding the verification arguments as well: + +```sh +forge script ./script/Deploy.s.sol:Deploy \ --rpc-url \ --account \ --broadcast \ @@ -131,37 +152,51 @@ forge clean && forge script ./script/Deploy.s.sol:Deploy \ --verifier-url ``` -You can verify an existing contract with: +Alternatively, you can verify an existing contract (perhaps deployed from a factory) with: ```sh -forge verify-contract src/.sol: \ ---verifier blockscout \ ---verifier-url +forge verify-contract ./src/.sol: \ +--verifier blockscout --verifier-url ``` -Note that the `--verifier-url` value should be the target explorer's homepage URL. Foundry will read your `ETHERSCAN_API_KEY` from environment already, so this does not have to be within your URL. +### Upgrade Contract -`https://base-sepolia.blockscout.com/api/` for `Base Sepolia Network` +Upgrading an existing contract is done as per the instructions in [openzeppelin-foundry-upgrades](https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades) repository. + +First, we create a new contract with its name as `ContractNameV2`, and then we execute the following command: + +```sh +forge script ./script/Deploy.s.sol:Upgrade \ +--rpc-url \ +--account --broadcast \ +--sender \ +--verify --verifier blockscout \ +--verifier-url +``` > [!NOTE] > -> The `--verifier` can accept any of the following: `etherscan`, `blockscout`, `sourcify`; but we are using Blockscout most of the time. +> The `--sender
` field is mandatory when deploying a contract, it can be obtained with the command below, which will prompt for keystore password: +> +> ```sh +> cast wallet address --account +> ``` ## Testing & Diagnostics Run tests on local network: ```sh -forge clean && forge test +FOUNDRY_PROFILE=test forge test # or -vvv to show reverts in detail -forge clean && forge test -vvv +FOUNDRY_PROFILE=test forge test -vvv ``` or fork an existing chain and run the tests on it: ```sh -forge clean && forge test --rpc-url +FOUNDRY_PROFILE=test forge test --rpc-url ``` ### Code Coverage @@ -169,34 +204,38 @@ forge clean && forge test --rpc-url We have a script that generates the coverage information as an HTML page. This script requires [`lcov`](https://linux.die.net/man/1/lcov) and [`genhtml`](https://linux.die.net/man/1/genhtml) command line tools. To run, do: ```sh -forge clean && ./coverage.sh +./coverage.sh ``` Alternatively, you can see a summarized text-only output as well: ```sh -forge clean && forge coverage --no-match-coverage "(test|mock|script)" +forge coverage --no-match-coverage "(test|mock|script)" ``` -### Storage Layout +### Gas Snapshot -Get storage layout with: +You can examine the gas usage metrics using the command: ```sh -forge clean && ./storage.sh +forge snapshot --snap ./test/.gas-snapshot ``` -You can see storage layouts under the storage directory. +You can see the snapshot `.gas-snapshot` file in the current directory. -### Gas Snapshot +### Styling -Take the gas snapshot with: +You can format the contracts with: ```sh -forge clean && forge snapshot +forge fmt ./src/**/*.sol ./script/**/*.sol ``` -You can see the snapshot `.gas-snapshot` file in the current directory. +If you have solhint installed, you can lint all contracts with: + +```sh +solhint 'src/**/*.sol' 'script/**/*.sol' +``` ## Documentation @@ -205,10 +244,10 @@ We have auto-generated MDBook documentations under the [`docs`](./docs) folder, ```sh forge doc -# servers the book as well +# serves the book as well forge doc --serve ``` ## License -We are using Apache-2.0 license. +We are using [Apache-2.0](./LICENSE) license. diff --git a/docs/src/src/LLMOracleCoordinator.sol/contract.LLMOracleCoordinator.md b/docs/src/src/LLMOracleCoordinator.sol/contract.LLMOracleCoordinator.md index de8c959..8444e29 100644 --- a/docs/src/src/LLMOracleCoordinator.sol/contract.LLMOracleCoordinator.md +++ b/docs/src/src/LLMOracleCoordinator.sol/contract.LLMOracleCoordinator.md @@ -1,5 +1,5 @@ # LLMOracleCoordinator -[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/4083e0e4f3f5849460fbea5040ecc77651509d1c/src/LLMOracleCoordinator.sol) +[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/84413650904832c21815ffefb6eee8517ceb0ffc/src/LLMOracleCoordinator.sol) **Inherits:** [LLMOracleTask](/src/LLMOracleTask.sol/interface.LLMOracleTask.md), [LLMOracleManager](/src/LLMOracleManager.sol/abstract.LLMOracleManager.md), UUPSUpgradeable diff --git a/docs/src/src/LLMOracleManager.sol/abstract.LLMOracleManager.md b/docs/src/src/LLMOracleManager.sol/abstract.LLMOracleManager.md index eb279dc..3b47d63 100644 --- a/docs/src/src/LLMOracleManager.sol/abstract.LLMOracleManager.md +++ b/docs/src/src/LLMOracleManager.sol/abstract.LLMOracleManager.md @@ -1,5 +1,5 @@ # LLMOracleManager -[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/4083e0e4f3f5849460fbea5040ecc77651509d1c/src/LLMOracleManager.sol) +[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/84413650904832c21815ffefb6eee8517ceb0ffc/src/LLMOracleManager.sol) **Inherits:** OwnableUpgradeable diff --git a/docs/src/src/LLMOracleRegistry.sol/contract.LLMOracleRegistry.md b/docs/src/src/LLMOracleRegistry.sol/contract.LLMOracleRegistry.md index 1600ec2..983adb9 100644 --- a/docs/src/src/LLMOracleRegistry.sol/contract.LLMOracleRegistry.md +++ b/docs/src/src/LLMOracleRegistry.sol/contract.LLMOracleRegistry.md @@ -1,5 +1,5 @@ # LLMOracleRegistry -[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/4083e0e4f3f5849460fbea5040ecc77651509d1c/src/LLMOracleRegistry.sol) +[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/84413650904832c21815ffefb6eee8517ceb0ffc/src/LLMOracleRegistry.sol) **Inherits:** [Whitelist](/src/Whitelist.sol/abstract.Whitelist.md), UUPSUpgradeable diff --git a/docs/src/src/LLMOracleRegistry.sol/enum.LLMOracleKind.md b/docs/src/src/LLMOracleRegistry.sol/enum.LLMOracleKind.md index 51078bd..3b86dfa 100644 --- a/docs/src/src/LLMOracleRegistry.sol/enum.LLMOracleKind.md +++ b/docs/src/src/LLMOracleRegistry.sol/enum.LLMOracleKind.md @@ -1,5 +1,5 @@ # LLMOracleKind -[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/4083e0e4f3f5849460fbea5040ecc77651509d1c/src/LLMOracleRegistry.sol) +[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/84413650904832c21815ffefb6eee8517ceb0ffc/src/LLMOracleRegistry.sol) The type of Oracle. diff --git a/docs/src/src/LLMOracleTask.sol/interface.LLMOracleTask.md b/docs/src/src/LLMOracleTask.sol/interface.LLMOracleTask.md index 50e3fba..1b01245 100644 --- a/docs/src/src/LLMOracleTask.sol/interface.LLMOracleTask.md +++ b/docs/src/src/LLMOracleTask.sol/interface.LLMOracleTask.md @@ -1,5 +1,5 @@ # LLMOracleTask -[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/4083e0e4f3f5849460fbea5040ecc77651509d1c/src/LLMOracleTask.sol) +[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/84413650904832c21815ffefb6eee8517ceb0ffc/src/LLMOracleTask.sol) An umbrella interface that captures task-related structs and enums. diff --git a/docs/src/src/LLMOracleTask.sol/struct.LLMOracleTaskParameters.md b/docs/src/src/LLMOracleTask.sol/struct.LLMOracleTaskParameters.md index 909e8e8..ef315cd 100644 --- a/docs/src/src/LLMOracleTask.sol/struct.LLMOracleTaskParameters.md +++ b/docs/src/src/LLMOracleTask.sol/struct.LLMOracleTaskParameters.md @@ -1,5 +1,5 @@ # LLMOracleTaskParameters -[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/4083e0e4f3f5849460fbea5040ecc77651509d1c/src/LLMOracleTask.sol) +[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/84413650904832c21815ffefb6eee8517ceb0ffc/src/LLMOracleTask.sol) Collection of oracle task-related parameters. diff --git a/docs/src/src/Statistics.sol/library.Statistics.md b/docs/src/src/Statistics.sol/library.Statistics.md index 86d52d8..e3111cd 100644 --- a/docs/src/src/Statistics.sol/library.Statistics.md +++ b/docs/src/src/Statistics.sol/library.Statistics.md @@ -1,5 +1,5 @@ # Statistics -[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/4083e0e4f3f5849460fbea5040ecc77651509d1c/src/Statistics.sol) +[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/84413650904832c21815ffefb6eee8517ceb0ffc/src/Statistics.sol) Simple statistic library for uint256 arrays. diff --git a/docs/src/src/Whitelist.sol/abstract.Whitelist.md b/docs/src/src/Whitelist.sol/abstract.Whitelist.md index 43e0a5d..9134ce2 100644 --- a/docs/src/src/Whitelist.sol/abstract.Whitelist.md +++ b/docs/src/src/Whitelist.sol/abstract.Whitelist.md @@ -1,5 +1,5 @@ # Whitelist -[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/4083e0e4f3f5849460fbea5040ecc77651509d1c/src/Whitelist.sol) +[Git Source](https://github.com/firstbatchxyz/dria-oracle-contracts/blob/84413650904832c21815ffefb6eee8517ceb0ffc/src/Whitelist.sol) **Inherits:** OwnableUpgradeable diff --git a/foundry.toml b/foundry.toml index 9e34a2d..f064478 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,6 +7,7 @@ script = 'script' cache_path = 'cache' optimizer = true + # required by upgradability # see: https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades ffi = true @@ -17,6 +18,14 @@ extra_output = ["storageLayout"] # forces recompilation, required by Upgradable contracts force = true +# testing does not care about the upgrade checks above +# so we disable them with +[profile.test] +ffi = false +ast = false +build_info = false +force = false + # fs permissions for deployment (false by default) fs_permissions = [ { access = "read", path = "out" }, diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 0e38815..98cd337 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {Upgrades, UnsafeUpgrades, Options} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; +import {Upgrades, Options} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; import {Script} from "forge-std/Script.sol"; import {Vm} from "forge-std/Vm.sol"; @@ -48,15 +48,6 @@ contract DeployLLMOracleRegistry is Script { impl = Upgrades.getImplementationAddress(proxy); } - - function deployUnsafe(address impl) external returns (address proxy) { - proxy = UnsafeUpgrades.deployUUPSProxy( - impl, - abi.encodeCall( - LLMOracleRegistry.initialize, (stakes.generator, stakes.validator, token, minRegistrationTimeSec) - ) - ); - } } contract DeployLLMOracleCoordinator is Script { diff --git a/test/LLMOracleCoordinator.t.sol b/test/LLMOracleCoordinator.t.sol index 0143e03..2469670 100644 --- a/test/LLMOracleCoordinator.t.sol +++ b/test/LLMOracleCoordinator.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {Upgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; +import {UnsafeUpgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; import {LLMOracleTask, LLMOracleTaskParameters} from "../src/LLMOracleTask.sol"; import {LLMOracleRegistry, LLMOracleKind} from "../src/LLMOracleRegistry.sol"; @@ -18,19 +18,20 @@ contract LLMOracleCoordinatorTest is Helper { modifier deployment() { vm.startPrank(dria); - address registryProxy = Upgrades.deployUUPSProxy( - "LLMOracleRegistry.sol", - abi.encodeCall( - LLMOracleRegistry.initialize, (stakes.generator, stakes.validator, address(token), minRegistrationTime) + + oracleRegistry = LLMOracleRegistry( + UnsafeUpgrades.deployUUPSProxy( + address(new LLMOracleRegistry()), + abi.encodeCall( + LLMOracleRegistry.initialize, + (stakes.generator, stakes.validator, address(token), minRegistrationTime) + ) ) ); - // wrap proxy with the LLMOracleRegistry contract to use in tests easily - oracleRegistry = LLMOracleRegistry(registryProxy); - // deploy coordinator contract - address coordinatorProxy = Upgrades.deployUUPSProxy( - "LLMOracleCoordinator.sol", + address coordinatorProxy = UnsafeUpgrades.deployUUPSProxy( + address(new LLMOracleCoordinator()), abi.encodeCall( LLMOracleCoordinator.initialize, ( diff --git a/test/LLMOracleRegistry.t.sol b/test/LLMOracleRegistry.t.sol index 62bba23..ba36285 100644 --- a/test/LLMOracleRegistry.t.sol +++ b/test/LLMOracleRegistry.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {Upgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; +import {UnsafeUpgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; import {LLMOracleRegistry, LLMOracleKind} from "../src/LLMOracleRegistry.sol"; @@ -26,8 +26,8 @@ contract LLMOracleRegistryTest is Helper { assertEq(address(token), targetAddr); vm.startPrank(dria); - address registryProxy = Upgrades.deployUUPSProxy( - "LLMOracleRegistry.sol", + address registryProxy = UnsafeUpgrades.deployUUPSProxy( + address(new LLMOracleRegistry()), abi.encodeCall( LLMOracleRegistry.initialize, (stakes.generator, stakes.validator, address(token), minRegistrationTime) ) @@ -52,7 +52,7 @@ contract LLMOracleRegistryTest is Helper { _; } - /// @notice fund the oracle and dria + /// fund the oracle and dria modifier fund() { deal(address(token), dria, 1 ether); deal(address(token), oracle, totalStakeAmount); diff --git a/test/script/Deploy.t.sol b/test/script/Deploy.t.sol deleted file mode 100644 index 53908bd..0000000 --- a/test/script/Deploy.t.sol +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.20; - -import {UnsafeUpgrades} from "@openzeppelin/foundry-upgrades/Upgrades.sol"; -import {Test} from "forge-std/Test.sol"; -import {Vm} from "forge-std/Vm.sol"; - -import {Helper} from "../../script/Helper.s.sol"; - -import {DeployLLMOracleCoordinator, DeployLLMOracleRegistry} from "../../script/Deploy.s.sol"; -import {LLMOracleRegistry} from "../../src/LLMOracleRegistry.sol"; -import {LLMOracleCoordinator} from "../../src/LLMOracleCoordinator.sol"; - -contract DeployTest is Test { - DeployLLMOracleCoordinator deployLLMOracleCoordinator; - DeployLLMOracleRegistry deployLLMOracleRegistry; - - address llmOracleCoordinatorProxy; - address llmOracleCoordinatorImpl; - - address llmOracleRegistryProxy; - address llmOracleRegistryImpl; - - function setUp() external { - deployLLMOracleRegistry = new DeployLLMOracleRegistry(); - (llmOracleRegistryProxy, llmOracleRegistryImpl) = deployLLMOracleRegistry.deploy(); - - deployLLMOracleCoordinator = new DeployLLMOracleCoordinator(); - (llmOracleCoordinatorProxy, llmOracleCoordinatorImpl) = - deployLLMOracleCoordinator.deploy(llmOracleRegistryProxy); - } - - modifier deployed() { - // check deployed addresses are not zero - require(llmOracleRegistryProxy != address(0), "LLMOracleRegistry not deployed"); - require(llmOracleRegistryImpl != address(0), "LLMOracleRegistry implementation not deployed"); - - require(llmOracleCoordinatorProxy != address(0), "LLMOracleCoordinator not deployed"); - require(llmOracleCoordinatorImpl != address(0), "LLMOracleCoordinator implementation not deployed"); - - // check if implementations are correct - address expectedRegistryImpl = UnsafeUpgrades.getImplementationAddress(llmOracleRegistryProxy); - address expectedCoordinatorImpl = UnsafeUpgrades.getImplementationAddress(llmOracleCoordinatorProxy); - - require(llmOracleRegistryImpl == expectedRegistryImpl, "LLMOracleRegistry implementation mismatch"); - require(llmOracleCoordinatorImpl == expectedCoordinatorImpl, "LLMOracleCoordinator implementation mismatch"); - require( - address(LLMOracleCoordinator(llmOracleCoordinatorProxy).registry()) == llmOracleRegistryProxy, - "LLMOracleCoordinator registry mismatch" - ); - _; - } - - function test_Deploy() external deployed {} -}