diff --git a/.circleci/config.yml b/.circleci/config.yml index dae0bfdf6..48a16171e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -197,6 +197,16 @@ jobs: just install forge --version forge fmt --check + forge_test: + docker: + - image: <> + steps: + - checkout + - run: + name: forge test + command: | + forge --version + forge test -vvv print_versions: docker: @@ -217,6 +227,7 @@ workflows: # Forge checks. - forge_build - forge_fmt + - forge_test # RPC endpoint checks. - check_sepolia_rpc_endpoints - check_mainnet_rpc_endpoints diff --git a/foundry.toml b/foundry.toml index f20454170..106163a04 100644 --- a/foundry.toml +++ b/foundry.toml @@ -26,3 +26,7 @@ remappings = [ [profile.ci] deny_warnings = true + +[rpc_endpoints] +localhost = "http://127.0.0.1:8545" +mainnet = "https://ethereum.publicnode.com" diff --git a/src/fps/AddressRegistry.sol b/src/fps/AddressRegistry.sol new file mode 100644 index 000000000..51270e7e3 --- /dev/null +++ b/src/fps/AddressRegistry.sol @@ -0,0 +1,184 @@ +pragma solidity 0.8.15; + +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {Test} from "forge-std/Test.sol"; +import {IAddressRegistry} from "src/fps/IAddressRegistry.sol"; +import {SUPERCHAIN_REGISTRY_PATH} from "src/fps/utils/Constants.sol"; + +/// @title Network Address Manager +/// @notice This contract provides a single source of truth for storing and retrieving addresses across multiple networks. +/// @dev Handles addresses for contracts and externally owned accounts (EOAs) while ensuring correctness and uniqueness. +contract AddressRegistry is IAddressRegistry, Test { + using EnumerableSet for EnumerableSet.UintSet; + + /// @dev Structure for reading address details from JSON files. + struct InputAddress { + /// Blockchain network identifier + address addr; + /// contract identifier (name) + string identifier; + /// Address (contract or EOA) + /// Indicates if the address is a contract + bool isContract; + } + + /// @dev Structure for storing address details in the contract. + struct RegistryEntry { + address addr; + /// Address (contract or EOA) + /// Indicates if the address is a contract + bool isContract; + } + + /// @dev Structure for reading chain list details from toml file + struct Superchain { + uint256 chainId; + string name; + } + + /// @notice Maps an identifier and l2 instance chain ID to a stored address entry. + /// All addresses will live on the same chain. + mapping(string => mapping(uint256 => RegistryEntry)) private registry; + + /// @notice Supported L2 chain IDs for this Address Registry instance. + mapping(uint256 => bool) public supportedL2ChainIds; + + /// @notice Array of supported superchains and their configurations + Superchain[] public superchains; + + /// @notice Initializes the contract by loading addresses from TOML files and configuring the supported L2 chains. + /// @param addressFolderPath The path to the folder containing chain-specific TOML address files + /// @param superchainListFilePath The path to the TOML file containing the list of supported L2 chains + constructor(string memory addressFolderPath, string memory superchainListFilePath) { + bytes memory superchainListContent = vm.parseToml(vm.readFile(superchainListFilePath), ".chains"); + superchains = abi.decode(superchainListContent, (Superchain[])); + + string memory superchainAddressesContent = vm.readFile(SUPERCHAIN_REGISTRY_PATH); + + for (uint256 i = 0; i < superchains.length; i++) { + uint256 superchainId = superchains[i].chainId; + string memory superchainName = superchains[i].name; + require(!supportedL2ChainIds[superchainId], "Duplicate chain ID in superchain config"); + require(superchainId != 0, "Invalid chain ID in superchain config"); + require(bytes(superchainName).length > 0, "Empty name in superchain config"); + + supportedL2ChainIds[superchainId] = true; + + string memory filePath = + string(abi.encodePacked(addressFolderPath, "/", vm.toString(superchainId), ".toml")); + bytes memory fileContent = vm.parseToml(vm.readFile(filePath), ".addresses"); + + InputAddress[] memory parsedAddresses = abi.decode(fileContent, (InputAddress[])); + + for (uint256 j = 0; j < parsedAddresses.length; j++) { + string memory identifier = parsedAddresses[j].identifier; + address contractAddress = parsedAddresses[j].addr; + bool isContract = parsedAddresses[j].isContract; + + require(contractAddress != address(0), "Invalid address: cannot be zero"); + require( + registry[identifier][superchainId].addr == address(0), + "Address already registered with this identifier and chain ID" + ); + + _typeCheckAddress(contractAddress, isContract); + + registry[identifier][superchainId] = RegistryEntry(contractAddress, isContract); + string memory prefixedIdentifier = + string(abi.encodePacked(vm.replace(vm.toUppercase(superchainName), " ", "_"), "_", identifier)); + vm.label(contractAddress, prefixedIdentifier); // Add label for debugging purposes + } + + string[] memory keys = + vm.parseJsonKeys(superchainAddressesContent, string.concat("$.", vm.toString(superchainId))); + + for (uint256 j = 0; j < keys.length; j++) { + string memory key = keys[j]; + address addr = vm.parseJsonAddress( + superchainAddressesContent, string.concat("$.", vm.toString(superchainId), ".", key) + ); + + require(addr != address(0), "Invalid address: cannot be zero"); + require( + registry[key][superchainId].addr == address(0), + "Address already registered with this identifier and chain ID" + ); + + registry[key][superchainId] = RegistryEntry(addr, addr.code.length > 0); + string memory prefixedIdentifier = + string(abi.encodePacked(vm.replace(vm.toUppercase(superchainName), " ", "_"), "_", key)); + vm.label(addr, prefixedIdentifier); + } + } + } + + /// @notice Retrieves an address by its identifier for a specified L2 chain + /// @param identifier The unique identifier associated with the address + /// @param l2ChainId The chain ID of the L2 network + /// @return The address associated with the given identifier on the specified chain + function getAddress(string memory identifier, uint256 l2ChainId) public view returns (address) { + _l2ChainIdSupported(l2ChainId); + + // Fetch the stored registry entry + RegistryEntry memory entry = registry[identifier][l2ChainId]; + address resolvedAddress = entry.addr; + + require(resolvedAddress != address(0), "Address not found"); + + return resolvedAddress; + } + + /// @notice Checks if an address is a contract for a given identifier and L2 chain + /// @param identifier The unique identifier associated with the address + /// @param l2ChainId The chain ID of the L2 network + /// @return True if the address is a contract, false otherwise + function isAddressContract(string memory identifier, uint256 l2ChainId) public view returns (bool) { + _l2ChainIdSupported(l2ChainId); + _checkAddressRegistered(identifier, l2ChainId); + + return registry[identifier][l2ChainId].isContract; + } + + /// @notice Checks if an address exists for a specified identifier and L2 chain + /// @param identifier The unique identifier associated with the address + /// @param l2ChainId The chain ID of the L2 network + /// @return True if the address exists, false otherwise + function isAddressRegistered(string memory identifier, uint256 l2ChainId) public view returns (bool) { + return registry[identifier][l2ChainId].addr != address(0); + } + + /// @notice Verifies that an address is registered for a given identifier and chain + /// @dev Reverts if the address is not registered + /// @param identifier The unique identifier associated with the address + /// @param l2ChainId The chain ID of the L2 network + function _checkAddressRegistered(string memory identifier, uint256 l2ChainId) private view { + require( + isAddressRegistered(identifier, l2ChainId), + string( + abi.encodePacked("Address not found for identifier ", identifier, " on chain ", vm.toString(l2ChainId)) + ) + ); + } + + /// @notice Verifies that the given L2 chain ID is supported + /// @param l2ChainId The chain ID of the L2 network to verify + function _l2ChainIdSupported(uint256 l2ChainId) private view { + require( + supportedL2ChainIds[l2ChainId], + string(abi.encodePacked("L2 Chain ID ", vm.toString(l2ChainId), " not supported")) + ); + } + + /// @notice Validates whether an address matches its expected type (contract or EOA) + /// @dev Reverts if the address type does not match the expected type + /// @param addr The address to validate + /// @param isContract True if the address should be a contract, false if it should be an EOA + function _typeCheckAddress(address addr, bool isContract) private view { + if (isContract) { + require(addr.code.length > 0, "Address must contain code"); + } else { + require(addr.code.length == 0, "Address must not contain code"); + } + } +} diff --git a/src/fps/IAddressRegistry.sol b/src/fps/IAddressRegistry.sol new file mode 100644 index 000000000..149275d2b --- /dev/null +++ b/src/fps/IAddressRegistry.sol @@ -0,0 +1,23 @@ +pragma solidity 0.8.15; + +/// @title Network Address Registry Interface +/// @notice Interface for managing and retrieving addresses across different networks. +interface IAddressRegistry { + /// @notice Retrieves an address by its identifier for a specified L2 chain + /// @param identifier The unique identifier associated with the address + /// @param l2ChainId The chain ID of the L2 network + /// @return The address associated with the given identifier on the specified chain + function getAddress(string memory identifier, uint256 l2ChainId) external view returns (address); + + /// @notice Checks if an address is a contract for a given identifier and L2 chain + /// @param identifier The unique identifier associated with the address + /// @param l2ChainId The chain ID of the L2 network + /// @return True if the address is a contract, false otherwise + function isAddressContract(string memory identifier, uint256 l2ChainId) external view returns (bool); + + /// @notice Checks if an address exists for a specified identifier and L2 chain + /// @param identifier The unique identifier associated with the address + /// @param l2ChainId The chain ID of the L2 network + /// @return True if the address exists, false otherwise + function isAddressRegistered(string memory identifier, uint256 l2ChainId) external view returns (bool); +} diff --git a/src/fps/addresses/10.toml b/src/fps/addresses/10.toml new file mode 100644 index 000000000..99f0067d9 --- /dev/null +++ b/src/fps/addresses/10.toml @@ -0,0 +1,14 @@ +[[addresses]] +addr = "0x9679E26bf0C470521DE83Ad77BB1bf1e7312f739" +identifier = "DEPLOYER_EOA" +isContract = false + +[[addresses]] +addr = "0xc0Da02939E1441F497fd74F78cE7Decb17B66529" +identifier = "COMPOUND_GOVERNOR_BRAVO" +isContract = true + +[[addresses]] +addr = "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3" +identifier = "COMPOUND_CONFIGURATOR" +isContract = true \ No newline at end of file diff --git a/src/fps/addresses/8453.toml b/src/fps/addresses/8453.toml new file mode 100644 index 000000000..99f0067d9 --- /dev/null +++ b/src/fps/addresses/8453.toml @@ -0,0 +1,14 @@ +[[addresses]] +addr = "0x9679E26bf0C470521DE83Ad77BB1bf1e7312f739" +identifier = "DEPLOYER_EOA" +isContract = false + +[[addresses]] +addr = "0xc0Da02939E1441F497fd74F78cE7Decb17B66529" +identifier = "COMPOUND_GOVERNOR_BRAVO" +isContract = true + +[[addresses]] +addr = "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3" +identifier = "COMPOUND_CONFIGURATOR" +isContract = true \ No newline at end of file diff --git a/src/fps/addresses/chainList.toml b/src/fps/addresses/chainList.toml new file mode 100644 index 000000000..20fe5373f --- /dev/null +++ b/src/fps/addresses/chainList.toml @@ -0,0 +1,7 @@ +[[chains]] + name = "OP Mainnet" + chain_id = 10 + +[[chains]] + name = "Base" + chain_id = 8453 \ No newline at end of file diff --git a/src/fps/doc/ADDRESS_REGISTRY.md b/src/fps/doc/ADDRESS_REGISTRY.md new file mode 100644 index 000000000..3c8196fba --- /dev/null +++ b/src/fps/doc/ADDRESS_REGISTRY.md @@ -0,0 +1,13 @@ +# Address Registry + +The address registry contract stores contract addresses on a single network. On construction, it reads in all of the configurations from the specified TOML configuration file. This TOML configuration file tells the address registry which L2 contracts to read in and store. As an example, if a task only touched the OP Mainnet contracts, the TOML file would only have a single entry + +```toml +[[chains]] + name = "OP Mainnet" + chain_id = 10 +``` + +## Usage + +Addresses can be fetched by calling the `getAddress(string memory identifier, uint256 l2ChainId)` function. This function will return the address of the contract with the given identifier on the given chain. If the contract does not exist, the function will revert. If the l2ChainId is unsupported by this address registry instance, the function will revert. diff --git a/src/fps/utils/Constants.sol b/src/fps/utils/Constants.sol new file mode 100644 index 000000000..d93f7ad30 --- /dev/null +++ b/src/fps/utils/Constants.sol @@ -0,0 +1,26 @@ +pragma solidity 0.8.15; + +// Mainnet Chain Ids +uint256 constant BASE_CHAIN_ID = 8453; +uint256 constant OP_CHAIN_ID = 10; +uint256 constant MODE_CHAIN_ID = 34443; +uint256 constant ORDERLY_CHAIN_ID = 291; +uint256 constant RACE_CHAIN_ID = 6805; +uint256 constant ZORA_CHAIN_ID = 7777777; +uint256 constant LYRA_CHAIN_ID = 957; +uint256 constant METAL_CHAIN_ID = 1750; +uint256 constant BINARY_CHAIN_ID = 624; + +// Testnet Chain Ids +uint256 constant BASE_SEPOLIA_CHAIN_ID = 84532; +uint256 constant OP_SEPOLIA_CHAIN_ID = 11155420; +uint256 constant MODE_SEPOLIA_CHAIN_ID = 919; +uint256 constant BASE_DEVNET_CHAIN_ID = 11763072; +uint256 constant METAL_SEPOLIA_CHAIN_ID = 1740; +uint256 constant RACE_SEPOLIA_CHAIN_ID = 6806; +uint256 constant ZORA_SEPOLIA_CHAIN_ID = 999999999; +uint256 constant OPLABS_DEVNET_CHAIN_ID = 11155421; + +uint256 constant LOCAL_CHAIN_ID = 31337; + +string constant SUPERCHAIN_REGISTRY_PATH = "lib/superchain-registry/superchain/extra/addresses/addresses.json"; diff --git a/test/AddressRegistry.t.sol b/test/AddressRegistry.t.sol new file mode 100644 index 000000000..76f3c94c1 --- /dev/null +++ b/test/AddressRegistry.t.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import {Test} from "forge-std/Test.sol"; + +import {AddressRegistry} from "src/fps/AddressRegistry.sol"; +import {BASE_CHAIN_ID, OP_CHAIN_ID} from "src/fps/utils/Constants.sol"; + +contract MainnetAddressRegistryTest is Test { + AddressRegistry private addresses; + + function setUp() public { + string memory tomlFilePath = "src/fps/addresses"; + + string memory tomlchainListPath = "src/fps/addresses/chainList.toml"; + + vm.createSelectFork("mainnet"); + + addresses = new AddressRegistry(tomlFilePath, tomlchainListPath); + } + + function testContractState() public view { + assertTrue(addresses.supportedL2ChainIds(OP_CHAIN_ID), "Optimism chain ID not supported"); + assertTrue(addresses.supportedL2ChainIds(BASE_CHAIN_ID), "Base chain ID not supported"); + } + + function testLocalAddressesLoaded() public view { + assertEq( + addresses.getAddress("DEPLOYER_EOA", OP_CHAIN_ID), + 0x9679E26bf0C470521DE83Ad77BB1bf1e7312f739, + "DEPLOYER_EOA address mismatch" + ); + assertEq( + addresses.getAddress("COMPOUND_GOVERNOR_BRAVO", OP_CHAIN_ID), + 0xc0Da02939E1441F497fd74F78cE7Decb17B66529, + "COMPOUND_GOVERNOR_BRAVO address mismatch" + ); + assertEq( + addresses.getAddress("COMPOUND_CONFIGURATOR", OP_CHAIN_ID), + 0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3, + "COMPOUND_CONFIGURATOR address mismatch" + ); + + assertTrue( + addresses.isAddressContract("COMPOUND_GOVERNOR_BRAVO", OP_CHAIN_ID), + "Address governor bravo should be a contract" + ); + assertTrue( + addresses.isAddressContract("COMPOUND_CONFIGURATOR", OP_CHAIN_ID), + "Address configurator should be a contract" + ); + assertFalse(addresses.isAddressContract("DEPLOYER_EOA", OP_CHAIN_ID), "EOA address should not be a contract"); + + assertTrue(addresses.isAddressRegistered("DEPLOYER_EOA", OP_CHAIN_ID), "DEPLOYER_EOA should be registered"); + assertTrue( + addresses.isAddressRegistered("COMPOUND_GOVERNOR_BRAVO", OP_CHAIN_ID), + "COMPOUND_GOVERNOR_BRAVO should be registered" + ); + assertTrue( + addresses.isAddressRegistered("COMPOUND_CONFIGURATOR", OP_CHAIN_ID), + "COMPOUND_CONFIGURATOR should be registered" + ); + assertFalse( + addresses.isAddressRegistered("NON_EXISTENT_ADDRESS", OP_CHAIN_ID), + "Non-existent address should not be registered" + ); + } + + function testSuperchainAddressesLoaded() public view { + assertEq( + addresses.getAddress("OptimismPortalProxy", OP_CHAIN_ID), + 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed, + "OP Portal address mismatch" + ); + assertEq( + addresses.getAddress("L1StandardBridgeProxy", OP_CHAIN_ID), + 0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1, + "OP Bridge address mismatch" + ); + assertEq( + addresses.getAddress("L1CrossDomainMessengerProxy", OP_CHAIN_ID), + 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1, + "OP Messenger address mismatch" + ); + + assertTrue(addresses.isAddressContract("OptimismPortalProxy", OP_CHAIN_ID), "OP Portal should be a contract"); + assertTrue(addresses.isAddressContract("L1StandardBridgeProxy", OP_CHAIN_ID), "OP Bridge should be a contract"); + assertTrue( + addresses.isAddressContract("L1CrossDomainMessengerProxy", OP_CHAIN_ID), "OP Messenger should be a contract" + ); + + assertTrue(addresses.isAddressRegistered("OptimismPortalProxy", OP_CHAIN_ID), "OP Portal should be registered"); + assertTrue( + addresses.isAddressRegistered("L1StandardBridgeProxy", OP_CHAIN_ID), "OP Bridge should be registered" + ); + assertTrue( + addresses.isAddressRegistered("L1CrossDomainMessengerProxy", OP_CHAIN_ID), + "OP Messenger should be registered" + ); + + assertEq( + addresses.getAddress("OptimismPortalProxy", BASE_CHAIN_ID), + 0x49048044D57e1C92A77f79988d21Fa8fAF74E97e, + "Base Portal address mismatch" + ); + assertEq( + addresses.getAddress("L1StandardBridgeProxy", BASE_CHAIN_ID), + 0x3154Cf16ccdb4C6d922629664174b904d80F2C35, + "Base Bridge address mismatch" + ); + assertEq( + addresses.getAddress("L1CrossDomainMessengerProxy", BASE_CHAIN_ID), + 0x866E82a600A1414e583f7F13623F1aC5d58b0Afa, + "Base Messenger address mismatch" + ); + + assertTrue( + addresses.isAddressContract("OptimismPortalProxy", BASE_CHAIN_ID), "Base Portal should be a contract" + ); + assertTrue( + addresses.isAddressContract("L1StandardBridgeProxy", BASE_CHAIN_ID), "Base Bridge should be a contract" + ); + assertTrue( + addresses.isAddressContract("L1CrossDomainMessengerProxy", BASE_CHAIN_ID), + "Base Messenger should be a contract" + ); + + assertTrue( + addresses.isAddressRegistered("OptimismPortalProxy", BASE_CHAIN_ID), "Base Portal should be registered" + ); + assertTrue( + addresses.isAddressRegistered("L1StandardBridgeProxy", BASE_CHAIN_ID), "Base Bridge should be registered" + ); + assertTrue( + addresses.isAddressRegistered("L1CrossDomainMessengerProxy", BASE_CHAIN_ID), + "Base Messenger should be registered" + ); + } + + function testInvalidL2ChainIdGetAddressFails() public { + vm.expectRevert("L2 Chain ID 999 not supported"); + addresses.getAddress("DEPLOYER_EOA", 999); + } + + function testGetNonExistentAddressFails() public { + vm.expectRevert("Address not found"); + addresses.getAddress("NON_EXISTENT_ADDRESS", OP_CHAIN_ID); + } + + function testInvalidL2ChainIdIsAddressContractFails() public { + vm.expectRevert("L2 Chain ID 999 not supported"); + addresses.isAddressContract("DEPLOYER_EOA", 999); + } + + function testGetIsAddressContractNonExistentAddressFails() public { + vm.expectRevert("Address not found for identifier NON_EXISTENT_ADDRESS on chain 10"); + addresses.isAddressContract("NON_EXISTENT_ADDRESS", OP_CHAIN_ID); + } + + /// Construction failure tests + + function testInvalidChainIdInSuperchainsFails() public { + string memory tomlFilePath = "src/fps/addresses"; + string memory tomlchainListPath = "test/mock/chainList1.toml"; + + vm.expectRevert("Invalid chain ID in superchain config"); + new AddressRegistry(tomlFilePath, tomlchainListPath); + } + + function testDuplicateChainIdInSuperchainsFails() public { + string memory tomlFilePath = "src/fps/addresses"; + string memory tomlchainListPath = "test/mock/chainList3.toml"; + + vm.expectRevert("Duplicate chain ID in superchain config"); + new AddressRegistry(tomlFilePath, tomlchainListPath); + } + + function testEmptyNameInSuperchainsFails() public { + string memory tomlFilePath = "src/fps/addresses"; + string memory tomlchainListPath = "test/mock/chainList2.toml"; + + vm.expectRevert("Empty name in superchain config"); + new AddressRegistry(tomlFilePath, tomlchainListPath); + } + + function testConstructionFailsIncorrectTypesEOA() public { + string memory tomlFilePath = "test/mock/data1"; + string memory tomlchainListPath = "test/mock/data1/chainList.toml"; + + vm.expectRevert("Address must contain code"); + new AddressRegistry(tomlFilePath, tomlchainListPath); + } + + function testConstructionFailsIncorrectTypesContract() public { + string memory tomlFilePath = "test/mock/data2"; + string memory tomlchainListPath = "test/mock/data2/chainList.toml"; + + vm.expectRevert("Address must not contain code"); + new AddressRegistry(tomlFilePath, tomlchainListPath); + } + + function testConstructionFailsAddressZero() public { + string memory tomlFilePath = "test/mock/data3"; + string memory tomlchainListPath = "test/mock/data3/chainList.toml"; + + vm.expectRevert("Invalid address: cannot be zero"); + new AddressRegistry(tomlFilePath, tomlchainListPath); + } + + function testConstructionFailsDuplicateAddress() public { + string memory tomlFilePath = "test/mock/data4"; + string memory tomlchainListPath = "test/mock/data4/chainList.toml"; + + vm.expectRevert("Address already registered with this identifier and chain ID"); + new AddressRegistry(tomlFilePath, tomlchainListPath); + } +} diff --git a/test/mock/chainList1.toml b/test/mock/chainList1.toml new file mode 100644 index 000000000..ac9bdc9f8 --- /dev/null +++ b/test/mock/chainList1.toml @@ -0,0 +1,7 @@ +[[chains]] + name = "OP Mainnet" + chain_id = 0 + +[[chains]] + name = "Base" + chain_id = 8453 \ No newline at end of file diff --git a/test/mock/chainList2.toml b/test/mock/chainList2.toml new file mode 100644 index 000000000..57c947ea1 --- /dev/null +++ b/test/mock/chainList2.toml @@ -0,0 +1,7 @@ +[[chains]] + name = "OP Mainnet" + chain_id = 10 + +[[chains]] + name = "" + chain_id = 8453 \ No newline at end of file diff --git a/test/mock/chainList3.toml b/test/mock/chainList3.toml new file mode 100644 index 000000000..e46419107 --- /dev/null +++ b/test/mock/chainList3.toml @@ -0,0 +1,7 @@ +[[chains]] + name = "OP Mainnet" + chain_id = 10 + +[[chains]] + name = "OP Mainnet" + chain_id = 10 \ No newline at end of file diff --git a/test/mock/data1/10.toml b/test/mock/data1/10.toml new file mode 100644 index 000000000..d23d35984 --- /dev/null +++ b/test/mock/data1/10.toml @@ -0,0 +1,14 @@ +[[addresses]] +addr = "0x9679E26bf0C470521DE83Ad77BB1bf1e7312f739" +identifier = "DEPLOYER_EOA" +isContract = true + +[[addresses]] +addr = "0xc0da02939e1441f497fd74f78ce7decb17b66529" +identifier = "COMPOUND_GOVERNOR_BRAVO" +isContract = true + +[[addresses]] +addr = "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3" +identifier = "COMPOUND_CONFIGURATOR" +isContract = true \ No newline at end of file diff --git a/test/mock/data1/chainList.toml b/test/mock/data1/chainList.toml new file mode 100644 index 000000000..d3c8114d2 --- /dev/null +++ b/test/mock/data1/chainList.toml @@ -0,0 +1,3 @@ +[[chains]] + name = "OP Mainnet" + chain_id = 10 \ No newline at end of file diff --git a/test/mock/data2/10.toml b/test/mock/data2/10.toml new file mode 100644 index 000000000..681ab9563 --- /dev/null +++ b/test/mock/data2/10.toml @@ -0,0 +1,14 @@ +[[addresses]] +addr = "0x9679E26bf0C470521DE83Ad77BB1bf1e7312f739" +identifier = "DEPLOYER_EOA" +isContract = false + +[[addresses]] +addr = "0xc0da02939e1441f497fd74f78ce7decb17b66529" +identifier = "COMPOUND_GOVERNOR_BRAVO" +isContract = false + +[[addresses]] +addr = "0x316f9708bB98af7dA9c68C1C3b5e79039cD336E3" +identifier = "COMPOUND_CONFIGURATOR" +isContract = true \ No newline at end of file diff --git a/test/mock/data2/chainList.toml b/test/mock/data2/chainList.toml new file mode 100644 index 000000000..d3c8114d2 --- /dev/null +++ b/test/mock/data2/chainList.toml @@ -0,0 +1,3 @@ +[[chains]] + name = "OP Mainnet" + chain_id = 10 \ No newline at end of file diff --git a/test/mock/data3/10.toml b/test/mock/data3/10.toml new file mode 100644 index 000000000..eed11e74d --- /dev/null +++ b/test/mock/data3/10.toml @@ -0,0 +1,4 @@ +[[addresses]] +addr = "0x0000000000000000000000000000000000000000" +identifier = "DEPLOYER_EOA" +isContract = false diff --git a/test/mock/data3/chainList.toml b/test/mock/data3/chainList.toml new file mode 100644 index 000000000..d3c8114d2 --- /dev/null +++ b/test/mock/data3/chainList.toml @@ -0,0 +1,3 @@ +[[chains]] + name = "OP Mainnet" + chain_id = 10 \ No newline at end of file diff --git a/test/mock/data4/10.toml b/test/mock/data4/10.toml new file mode 100644 index 000000000..a7336d5cd --- /dev/null +++ b/test/mock/data4/10.toml @@ -0,0 +1,9 @@ +[[addresses]] +addr = "0x9679E26bf0C470521DE83Ad77BB1bf1e7312f739" +identifier = "DEPLOYER_EOA" +isContract = false + +[[addresses]] +addr = "0x9679E26bf0C470521DE83Ad77BB1bf1e7312f739" +identifier = "DEPLOYER_EOA" +isContract = false diff --git a/test/mock/data4/chainList.toml b/test/mock/data4/chainList.toml new file mode 100644 index 000000000..d3c8114d2 --- /dev/null +++ b/test/mock/data4/chainList.toml @@ -0,0 +1,3 @@ +[[chains]] + name = "OP Mainnet" + chain_id = 10 \ No newline at end of file