-
Notifications
You must be signed in to change notification settings - Fork 71
Migrate adapter registries into src/periphery/registries #960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
claude
wants to merge
2
commits into
main
Choose a base branch
from
feat/migrate-registries
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity 0.8.28; | ||
|
|
||
| import {IMorphoMarketV1AdapterV2Factory} from "../../adapters/interfaces/IMorphoMarketV1AdapterV2Factory.sol"; | ||
| import {IMorphoMarketV1RegistryV2} from "./interfaces/IMorphoMarketV1RegistryV2.sol"; | ||
|
|
||
| contract MorphoMarketV1RegistryV2 is IMorphoMarketV1RegistryV2 { | ||
| address public immutable morphoMarketV1AdapterV2Factory; | ||
|
|
||
| constructor(address _morphoMarketV1AdapterV2Factory) { | ||
| morphoMarketV1AdapterV2Factory = _morphoMarketV1AdapterV2Factory; | ||
| } | ||
|
|
||
| function isInRegistry(address adapter) external view returns (bool) { | ||
| return IMorphoMarketV1AdapterV2Factory(morphoMarketV1AdapterV2Factory).isMorphoMarketV1AdapterV2(adapter); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity 0.8.28; | ||
|
|
||
| import {IMetaMorphoFactory} from "../../../lib/metamorpho/src/interfaces/IMetaMorphoFactory.sol"; | ||
| import {IMorphoVaultV1AdapterFactory} from "../../adapters/interfaces/IMorphoVaultV1AdapterFactory.sol"; | ||
| import {IMorphoVaultV1Adapter} from "../../adapters/interfaces/IMorphoVaultV1Adapter.sol"; | ||
| import {IMorphoVaultV1Registry} from "./interfaces/IMorphoVaultV1Registry.sol"; | ||
|
|
||
| contract MorphoVaultV1Registry is IMorphoVaultV1Registry { | ||
| address public immutable morphoVaultV1AdapterFactory; | ||
| address public immutable morphoVaultV1Factory; | ||
|
|
||
| constructor(address _morphoVaultV1AdapterFactory, address _morphoVaultV1Factory) { | ||
| morphoVaultV1AdapterFactory = _morphoVaultV1AdapterFactory; | ||
| morphoVaultV1Factory = _morphoVaultV1Factory; | ||
| } | ||
|
|
||
| function isInRegistry(address adapter) external view returns (bool) { | ||
| return IMorphoVaultV1AdapterFactory(morphoVaultV1AdapterFactory).isMorphoVaultV1Adapter(adapter) | ||
| && IMetaMorphoFactory(morphoVaultV1Factory).isMetaMorpho(IMorphoVaultV1Adapter(adapter).morphoVaultV1()); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity 0.8.28; | ||
|
|
||
| import {IRegistryList} from "./interfaces/IRegistryList.sol"; | ||
| import {IAdapterRegistry} from "../../interfaces/IAdapterRegistry.sol"; | ||
|
|
||
| contract RegistryList is IRegistryList { | ||
| address public owner; | ||
|
|
||
| /// @dev Owner controlled append-only list of registries. | ||
| /// @dev This registry is effectively "add-only" only if all sub-registries are also "add-only". | ||
| address[] public subRegistries; | ||
|
|
||
| event Constructor(address indexed owner); | ||
| event SetOwner(address indexed newOwner); | ||
| event AddSubRegistry(address indexed subRegistry); | ||
|
|
||
| function subRegistriesLength() external view returns (uint256) { | ||
| return subRegistries.length; | ||
| } | ||
|
|
||
| constructor() { | ||
| owner = msg.sender; | ||
| emit Constructor(msg.sender); | ||
| } | ||
|
|
||
| function setOwner(address newOwner) external { | ||
| require(msg.sender == owner, "Not owner"); | ||
| owner = newOwner; | ||
| emit SetOwner(newOwner); | ||
| } | ||
|
|
||
| /// @dev Adding a subRegistry that reverts or makes looping too gas consuming will make new registries uneffective | ||
| /// (vaults will not be able to validate adapters that would be validated by registries that have been added after). | ||
| function addSubRegistry(address subRegistry) external { | ||
| require(msg.sender == owner, "Not owner"); | ||
| subRegistries.push(subRegistry); | ||
| emit AddSubRegistry(subRegistry); | ||
| } | ||
|
|
||
| function isInRegistry(address adapter) public view returns (bool) { | ||
| for (uint256 i = 0; i < subRegistries.length; i++) { | ||
| if (IAdapterRegistry(subRegistries[i]).isInRegistry(adapter)) return true; | ||
| } | ||
| return false; | ||
| } | ||
| } |
9 changes: 9 additions & 0 deletions
9
src/periphery/registries/interfaces/IMorphoMarketV1RegistryV2.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity >=0.5.0; | ||
|
|
||
| import {IAdapterRegistry} from "../../../interfaces/IAdapterRegistry.sol"; | ||
|
|
||
| interface IMorphoMarketV1RegistryV2 is IAdapterRegistry { | ||
| function morphoMarketV1AdapterV2Factory() external view returns (address); | ||
| } |
10 changes: 10 additions & 0 deletions
10
src/periphery/registries/interfaces/IMorphoVaultV1Registry.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity >=0.5.0; | ||
|
|
||
| import {IAdapterRegistry} from "../../../interfaces/IAdapterRegistry.sol"; | ||
|
|
||
| interface IMorphoVaultV1Registry is IAdapterRegistry { | ||
| function morphoVaultV1AdapterFactory() external view returns (address); | ||
| function morphoVaultV1Factory() external view returns (address); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity >=0.5.0; | ||
|
|
||
| import {IAdapterRegistry} from "../../../interfaces/IAdapterRegistry.sol"; | ||
|
|
||
| interface IRegistryList is IAdapterRegistry { | ||
| function owner() external view returns (address); | ||
| function subRegistries(uint256 index) external view returns (address); | ||
| function subRegistriesLength() external view returns (uint256); | ||
| function setOwner(address newOwner) external; | ||
| function addSubRegistry(address subRegistry) external; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity ^0.8.28; | ||
|
|
||
| import {Test} from "forge-std/Test.sol"; | ||
| import {MorphoMarketV1RegistryV2} from "../../src/periphery/registries/MorphoMarketV1RegistryV2.sol"; | ||
| import {IMorphoMarketV1RegistryV2} from "../../src/periphery/registries/interfaces/IMorphoMarketV1RegistryV2.sol"; | ||
|
|
||
| contract MorphoMarketV1RegistryV2Test is Test { | ||
| IMorphoMarketV1RegistryV2 registry; | ||
| address morphoMarketV1AdapterV2Factory = address(0x1001); | ||
|
|
||
| function setUp() public { | ||
| registry = IMorphoMarketV1RegistryV2(address(new MorphoMarketV1RegistryV2(morphoMarketV1AdapterV2Factory))); | ||
| } | ||
|
|
||
| function testConstructor() public view { | ||
| assertEq(registry.morphoMarketV1AdapterV2Factory(), morphoMarketV1AdapterV2Factory); | ||
| } | ||
|
|
||
| function testIsInRegistry(address adapter, bool isMorphoMarketV1AdapterV2) public { | ||
| vm.assume(adapter != address(vm)); | ||
| vm.mockCall( | ||
| morphoMarketV1AdapterV2Factory, | ||
| abi.encodeWithSignature("isMorphoMarketV1AdapterV2(address)", adapter), | ||
| abi.encode(isMorphoMarketV1AdapterV2) | ||
| ); | ||
|
|
||
| assertEq(registry.isInRegistry(adapter), isMorphoMarketV1AdapterV2); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity ^0.8.28; | ||
|
|
||
| import {Test} from "forge-std/Test.sol"; | ||
| import {MorphoVaultV1Registry} from "../../src/periphery/registries/MorphoVaultV1Registry.sol"; | ||
| import {IMorphoVaultV1Registry} from "../../src/periphery/registries/interfaces/IMorphoVaultV1Registry.sol"; | ||
|
|
||
| contract MorphoVaultV1RegistryTest is Test { | ||
| IMorphoVaultV1Registry registry; | ||
| address morphoVaultV1Factory = address(0x1001); | ||
| address morphoVaultV1AdapterFactory = address(0x1002); | ||
|
|
||
| function setUp() public { | ||
| registry = IMorphoVaultV1Registry( | ||
| address(new MorphoVaultV1Registry(morphoVaultV1AdapterFactory, morphoVaultV1Factory)) | ||
| ); | ||
| } | ||
|
|
||
| function testConstructor() public view { | ||
| assertEq(registry.morphoVaultV1AdapterFactory(), morphoVaultV1AdapterFactory); | ||
| assertEq(registry.morphoVaultV1Factory(), morphoVaultV1Factory); | ||
| } | ||
|
|
||
| function testIsInRegistry(address adapter, address morphoVaultV1, bool isMorphoVaultV1Adapter, bool isMetaMorpho) | ||
| public | ||
| { | ||
| vm.assume(adapter != address(vm)); | ||
| vm.mockCall( | ||
| morphoVaultV1AdapterFactory, | ||
| abi.encodeWithSignature("isMorphoVaultV1Adapter(address)", adapter), | ||
| abi.encode(isMorphoVaultV1Adapter) | ||
| ); | ||
|
|
||
| if (isMorphoVaultV1Adapter) { | ||
| vm.mockCall(adapter, abi.encodeWithSignature("morphoVaultV1()"), abi.encode(morphoVaultV1)); | ||
| vm.mockCall( | ||
| morphoVaultV1Factory, | ||
| abi.encodeWithSignature("isMetaMorpho(address)", morphoVaultV1), | ||
| abi.encode(isMetaMorpho) | ||
| ); | ||
| } | ||
|
|
||
| bool expected = isMorphoVaultV1Adapter && isMetaMorpho; | ||
| assertEq(registry.isInRegistry(adapter), expected); | ||
| } | ||
|
|
||
| // check that if the adapter isn't a vault adapter, it doesn't revert (basically checks the order of execution of | ||
| // solidity). | ||
| function testNoObscureRevert(address adapter) public { | ||
| vm.mockCall( | ||
| morphoVaultV1AdapterFactory, | ||
| abi.encodeWithSignature("isMorphoVaultV1Adapter(address)", adapter), | ||
| abi.encode(false) | ||
| ); | ||
|
|
||
| registry.isInRegistry(adapter); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||
| // Copyright (c) 2026 Morpho Association | ||
| pragma solidity ^0.8.28; | ||
|
|
||
| import {Test} from "forge-std/Test.sol"; | ||
| import {RegistryList} from "../../src/periphery/registries/RegistryList.sol"; | ||
| import {IRegistryList} from "../../src/periphery/registries/interfaces/IRegistryList.sol"; | ||
|
|
||
| contract RegistryListTest is Test { | ||
| IRegistryList registry; | ||
| address user = address(0x1); | ||
|
|
||
| function setUp() public { | ||
| registry = IRegistryList(address(new RegistryList())); | ||
| } | ||
|
|
||
| function testConstructor() public view { | ||
| assertEq(registry.owner(), address(this)); | ||
| assertEq(registry.subRegistriesLength(), 0); | ||
| } | ||
|
|
||
| function testConstructorEvent() public { | ||
| vm.expectEmit(true, false, false, false); | ||
| emit RegistryList.Constructor(address(this)); | ||
| new RegistryList(); | ||
| } | ||
|
|
||
| function testSetOwner(address newOwner) public { | ||
| vm.expectEmit(true, false, false, false); | ||
| emit RegistryList.SetOwner(newOwner); | ||
|
|
||
| registry.setOwner(newOwner); | ||
| assertEq(registry.owner(), newOwner); | ||
| } | ||
|
|
||
| function testSetOwnerOnlyOwner() public { | ||
| vm.prank(user); | ||
| vm.expectRevert("Not owner"); | ||
| registry.setOwner(address(0x123)); | ||
| } | ||
|
|
||
| function testAddSubRegistry(address subRegistry) public { | ||
| vm.expectEmit(true, false, false, false); | ||
| emit RegistryList.AddSubRegistry(subRegistry); | ||
|
|
||
| registry.addSubRegistry(subRegistry); | ||
|
|
||
| assertEq(registry.subRegistriesLength(), 1); | ||
| assertEq(registry.subRegistries(0), subRegistry); | ||
| } | ||
|
|
||
| function testAddRegistrySubRegistryOnlyOwner() public { | ||
| vm.prank(user); | ||
| vm.expectRevert("Not owner"); | ||
| registry.addSubRegistry(address(0x1002)); | ||
| } | ||
|
|
||
| function testIsInRegistryWithSubRegistries(address adapter, bool subRegistry1Result, bool subRegistry2Result) | ||
| public | ||
| { | ||
| address subRegistry1 = address(0x1001); | ||
| address subRegistry2 = address(0x1002); | ||
|
|
||
| registry.addSubRegistry(subRegistry1); | ||
| registry.addSubRegistry(subRegistry2); | ||
|
|
||
| vm.mockCall( | ||
| subRegistry1, abi.encodeWithSignature("isInRegistry(address)", adapter), abi.encode(subRegistry1Result) | ||
| ); | ||
| vm.mockCall( | ||
| subRegistry2, abi.encodeWithSignature("isInRegistry(address)", adapter), abi.encode(subRegistry2Result) | ||
| ); | ||
|
|
||
| bool expected = subRegistry1Result || subRegistry2Result; | ||
| assertEq(registry.isInRegistry(adapter), expected); | ||
| } | ||
|
|
||
| function testIsInRegistryNoSubRegistries(address adapter) public view { | ||
| assertFalse(registry.isInRegistry(adapter)); | ||
| } | ||
|
|
||
| function testAddingRevertingSubRegistry(address adapter, address legitSubRegistry, address revertingSubRegistry) | ||
| public | ||
| { | ||
| assumeAddressIsNot(legitSubRegistry, AddressType.ForgeAddress); | ||
| vm.assume(legitSubRegistry != revertingSubRegistry); | ||
| vm.assume(legitSubRegistry != address(0)); | ||
|
|
||
| registry.addSubRegistry(legitSubRegistry); | ||
| registry.addSubRegistry(revertingSubRegistry); | ||
|
|
||
| vm.mockCall(legitSubRegistry, abi.encodeWithSignature("isInRegistry(address)", adapter), abi.encode(true)); | ||
|
|
||
| assertTrue(registry.isInRegistry(adapter)); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.