-
Notifications
You must be signed in to change notification settings - Fork 112
feat: Add V4 Addresses Provider #1310
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
a57e24a
a826a62
a82f500
c012fac
80e400b
8e0bf2a
b55faac
d0631c3
6a1614a
626b556
d7e3340
5650778
efa03cc
e7c9097
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| // SPDX-License-Identifier: LicenseRef-BUSL | ||
| pragma solidity 0.8.28; | ||
|
|
||
| import {Ownable2StepUpgradeable} from 'src/dependencies/openzeppelin-upgradeable/Ownable2StepUpgradeable.sol'; | ||
| import {EnumerableSet} from 'src/dependencies/openzeppelin/EnumerableSet.sol'; | ||
| import {V4AddressesProviderStorage} from 'src/addresses-provider/V4AddressesProviderStorage.sol'; | ||
| import {IV4AddressesProvider} from 'src/addresses-provider/interfaces/IV4AddressesProvider.sol'; | ||
|
|
||
| /// @title V4AddressesProvider | ||
| /// @author Aave Labs | ||
| /// @notice Main registry of Aave V4 contract addresses. | ||
| abstract contract V4AddressesProvider is | ||
| V4AddressesProviderStorage, | ||
| Ownable2StepUpgradeable, | ||
| IV4AddressesProvider | ||
| { | ||
| using EnumerableSet for *; | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| string public constant CANONICAL_HUB_TAG = 'CANONICAL_HUB'; | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| string public constant CANONICAL_SPOKE_TAG = 'CANONICAL_SPOKE'; | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| string public constant TOKENIZATION_SPOKE_TAG = 'TOKENIZATION_SPOKE'; | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| string public constant TREASURY_SPOKE_TAG = 'TREASURY_SPOKE'; | ||
|
|
||
| /// @dev To be overridden by the inheriting V4AddressesProvider instance contract. | ||
| function initialize(address owner) external virtual; | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function setAddress( | ||
| string memory name, | ||
| string memory tag, | ||
| address newAddress | ||
| ) external onlyOwner { | ||
| _setAddress({name: name, tag: tag, newAddress: newAddress}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function setCanonicalHub(string memory name, address hub) external onlyOwner { | ||
| _setAddress({name: name, tag: CANONICAL_HUB_TAG, newAddress: hub}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function setCanonicalSpoke(string memory name, address spoke) external onlyOwner { | ||
| _setAddress({name: name, tag: CANONICAL_SPOKE_TAG, newAddress: spoke}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function setTokenizationSpoke(string memory name, address spoke) external onlyOwner { | ||
| _setAddress({name: name, tag: TOKENIZATION_SPOKE_TAG, newAddress: spoke}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function setTreasurySpoke(string memory name, address spoke) external onlyOwner { | ||
| _setAddress({name: name, tag: TREASURY_SPOKE_TAG, newAddress: spoke}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getAddressEntry(bytes32 id) external view returns (AddressEntry memory) { | ||
| return _addressEntries[id]; | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getIds(string memory tag) external view returns (bytes32[] memory) { | ||
| return _taggedIds[tag].values(); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. annoyingly we might need to overload with index and length methods instead of this bc we'll get a finding says array size can make inflate over gas limit (unlikely), we've done this way already elsewhere with array getters in the codebase
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes true, we should do this
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getTags() external view returns (string[] memory) { | ||
| return _tags.values(); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getCanonicalHub(string memory name) external view returns (address) { | ||
|
DhairyaSethi marked this conversation as resolved.
Outdated
|
||
| return getAddress({name: name, tag: CANONICAL_HUB_TAG}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getCanonicalHubs() external view returns (address[] memory) { | ||
| return getAddresses(CANONICAL_HUB_TAG); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getCanonicalSpoke(string memory name) external view returns (address) { | ||
| return getAddress({name: name, tag: CANONICAL_SPOKE_TAG}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getCanonicalSpokes() external view returns (address[] memory) { | ||
| return getAddresses(CANONICAL_SPOKE_TAG); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getTokenizationSpoke(string memory name) external view returns (address) { | ||
| return getAddress({name: name, tag: TOKENIZATION_SPOKE_TAG}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getTokenizationSpokes() external view returns (address[] memory) { | ||
| return getAddresses(TOKENIZATION_SPOKE_TAG); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getTreasurySpoke(string memory name) external view returns (address) { | ||
| return getAddress({name: name, tag: TREASURY_SPOKE_TAG}); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getTreasurySpokes() external view returns (address[] memory) { | ||
| return getAddresses(TREASURY_SPOKE_TAG); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getAddress(bytes32 id) public view returns (address) { | ||
| return _addressEntries[id].addr; | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getAddress(string memory name, string memory tag) public view returns (address) { | ||
| return getAddress(getId({name: name, tag: tag})); | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getAddresses(string memory tag) public view returns (address[] memory) { | ||
| bytes32[] memory ids = _taggedIds[tag].values(); | ||
| address[] memory addresses = new address[](ids.length); | ||
| for (uint256 i = 0; i < ids.length; i++) { | ||
| addresses[i] = _addressEntries[ids[i]].addr; | ||
| } | ||
| return addresses; | ||
| } | ||
|
|
||
| /// @inheritdoc IV4AddressesProvider | ||
| function getId(string memory name, string memory tag) public pure returns (bytes32) { | ||
| return keccak256(bytes(string.concat(name, '_', tag))); | ||
| } | ||
|
|
||
| function _setAddress(string memory name, string memory tag, address newAddress) internal { | ||
| require(bytes(name).length > 0, InvalidName()); | ||
| require(bytes(tag).length > 0, InvalidTag()); | ||
|
|
||
| bytes32 id = getId({name: name, tag: tag}); | ||
| AddressEntry memory oldEntry = _addressEntries[id]; | ||
|
|
||
| if (newAddress == address(0)) { | ||
| require(oldEntry.addr != address(0), AddressNotSet(id)); | ||
| _taggedIds[oldEntry.tag].remove(id); | ||
| if (_taggedIds[oldEntry.tag].length() == 0) { | ||
| _tags.remove(oldEntry.tag); | ||
| } | ||
| delete _addressEntries[id]; | ||
| } else { | ||
| require(oldEntry.addr == address(0), AddressAlreadySet(id)); | ||
| _addressEntries[id] = AddressEntry({addr: newAddress, tag: tag}); | ||
| _taggedIds[tag].add(id); | ||
| _tags.add(tag); | ||
| } | ||
|
|
||
| emit AddressSet(id, name, tag, oldEntry.addr, newAddress); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // SPDX-License-Identifier: LicenseRef-BUSL | ||
| pragma solidity 0.8.28; | ||
|
|
||
| import {EnumerableSet} from 'src/dependencies/openzeppelin/EnumerableSet.sol'; | ||
| import {IV4AddressesProvider} from 'src/addresses-provider/interfaces/IV4AddressesProvider.sol'; | ||
|
|
||
| /// @title V4AddressesProviderStorage | ||
| /// @author Aave Labs | ||
| /// @notice Storage layout for the V4AddressesProvider contract. | ||
| /// @dev This contract defines all storage variables used by the V4AddressesProvider. | ||
| abstract contract V4AddressesProviderStorage { | ||
| /// @dev Map of entry identifiers to address entries. | ||
| mapping(bytes32 id => IV4AddressesProvider.AddressEntry) internal _addressEntries; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i d follow the same conventions we used as for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| /// @dev Map of tags to set of entry identifiers. | ||
| mapping(string tag => EnumerableSet.Bytes32Set ids) internal _taggedIds; | ||
|
|
||
| /// @dev Set of all tags with at least one registered entry. | ||
| EnumerableSet.StringSet internal _tags; | ||
|
|
||
| /// @dev Reserved storage space to allow for future layout updates. | ||
| uint256[50] private __gap; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // SPDX-License-Identifier: LicenseRef-BUSL | ||
| pragma solidity 0.8.28; | ||
|
|
||
| import {V4AddressesProvider} from 'src/addresses-provider/V4AddressesProvider.sol'; | ||
|
|
||
| /// @title V4AddressesProviderInstance | ||
| /// @author Aave Labs | ||
| /// @notice Implementation contract for the V4AddressesProvider. | ||
| contract V4AddressesProviderInstance is V4AddressesProvider { | ||
| uint64 public constant ADDRESSES_PROVIDER_REVISION = 1; | ||
|
|
||
| /// @dev Constructor. | ||
| constructor() { | ||
| _disableInitializers(); | ||
| } | ||
|
|
||
| /// @notice Initializer. | ||
| /// @param owner The address of the owner. | ||
| function initialize(address owner) external override reinitializer(ADDRESSES_PROVIDER_REVISION) { | ||
| __Ownable_init(owner); | ||
| __Ownable2Step_init(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,162 @@ | ||||||
| // SPDX-License-Identifier: LicenseRef-BUSL | ||||||
| pragma solidity ^0.8.0; | ||||||
|
|
||||||
| /// @title IV4AddressesProvider | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the V4 preffix may not be needed
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
| /// @author Aave Labs | ||||||
| /// @notice Main registry of the Hub and Spoke addresses of an Aave V4 instance. | ||||||
| interface IV4AddressesProvider { | ||||||
| /// @notice Address entry registered under an identifier. | ||||||
| /// @param addr The registered address. | ||||||
| /// @param tag The tag grouping the entry. | ||||||
| struct AddressEntry { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can be just
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
| address addr; | ||||||
| string tag; | ||||||
| } | ||||||
|
|
||||||
| /// @notice Emitted when the address associated with a name and tag is updated. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when the address of an entry is updated
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. event name can be changed to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
| /// @param id The identifier of the entry. | ||||||
| /// @param name The name of the entry. | ||||||
| /// @param tag The tag grouping the entry. | ||||||
| /// @param oldAddress The previous address of the entry. | ||||||
| /// @param newAddress The new address of the entry. | ||||||
| event AddressSet( | ||||||
| bytes32 indexed id, | ||||||
| string name, | ||||||
| string tag, | ||||||
| address indexed oldAddress, | ||||||
| address indexed newAddress | ||||||
| ); | ||||||
|
|
||||||
| /// @notice Thrown when an empty tag is supplied. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
same for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
| error InvalidTag(); | ||||||
|
|
||||||
| /// @notice Thrown when an empty name is supplied. | ||||||
| error InvalidName(); | ||||||
|
|
||||||
| /// @notice Thrown when an address is already registered under the identifier. | ||||||
| error AddressAlreadySet(bytes32 id); | ||||||
|
|
||||||
| /// @notice Thrown when no address is registered under the identifier. | ||||||
| error AddressNotSet(bytes32 id); | ||||||
|
|
||||||
| /// @notice Returns the tag grouping all canonical Hubs. | ||||||
| function CANONICAL_HUB_TAG() external view returns (string memory); | ||||||
|
|
||||||
| /// @notice Returns the tag grouping all canonical Spokes. | ||||||
| function CANONICAL_SPOKE_TAG() external view returns (string memory); | ||||||
|
|
||||||
| /// @notice Returns the tag grouping all tokenization Spokes. | ||||||
| function TOKENIZATION_SPOKE_TAG() external view returns (string memory); | ||||||
|
|
||||||
| /// @notice Returns the tag grouping all treasury Spokes. | ||||||
| function TREASURY_SPOKE_TAG() external view returns (string memory); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. view functions of constants at the bottom
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
|
|
||||||
| /// @notice Associates an address with a name, grouped under a tag. | ||||||
| /// @dev Associating the zero address removes the entry and its identifier from enumeration, it reverts if no address is registered. | ||||||
| /// @dev Reverts if an address is already registered under the identifier, it must be removed first. | ||||||
| /// @param name The name of the entry. | ||||||
| /// @param tag The tag grouping the entry. | ||||||
| /// @param newAddress The address to associate with the name and tag. | ||||||
| function setAddress(string memory name, string memory tag, address newAddress) external; | ||||||
|
|
||||||
| /// @notice Registers the canonical Hub associated with a name. | ||||||
| /// @dev Registering the zero address removes the entry and its identifier from enumeration, it reverts if no address is registered. | ||||||
| /// @dev Reverts if an address is already registered under the identifier, it must be removed first. | ||||||
| /// @param name The name of the Hub. | ||||||
| /// @param hub The address of the Hub. | ||||||
| function setCanonicalHub(string memory name, address hub) external; | ||||||
|
|
||||||
| /// @notice Registers the canonical Spoke associated with a name. | ||||||
| /// @dev Registering the zero address removes the entry and its identifier from enumeration, it reverts if no address is registered. | ||||||
| /// @dev Reverts if an address is already registered under the identifier, it must be removed first. | ||||||
| /// @param name The name of the Spoke. | ||||||
| /// @param spoke The address of the Spoke. | ||||||
| function setCanonicalSpoke(string memory name, address spoke) external; | ||||||
|
|
||||||
| /// @notice Registers the tokenization Spoke associated with a name. | ||||||
| /// @dev Registering the zero address removes the entry and its identifier from enumeration, it reverts if no address is registered. | ||||||
| /// @dev Reverts if an address is already registered under the identifier, it must be removed first. | ||||||
| /// @param name The name of the Spoke. | ||||||
| /// @param spoke The address of the Spoke. | ||||||
| function setTokenizationSpoke(string memory name, address spoke) external; | ||||||
|
|
||||||
| /// @notice Registers the treasury Spoke associated with a name. | ||||||
| /// @dev Registering the zero address removes the entry and its identifier from enumeration, it reverts if no address is registered. | ||||||
| /// @dev Reverts if an address is already registered under the identifier, it must be removed first. | ||||||
| /// @param name The name of the Spoke. | ||||||
| /// @param spoke The address of the Spoke. | ||||||
| function setTreasurySpoke(string memory name, address spoke) external; | ||||||
|
|
||||||
| /// @notice Returns the address associated with an identifier. | ||||||
| /// @param id The identifier of the entry. | ||||||
| /// @return The address of the entry, the zero address if none is registered. | ||||||
| function getAddress(bytes32 id) external view returns (address); | ||||||
|
|
||||||
| /// @notice Returns the address associated with a name and tag. | ||||||
| /// @param name The name of the entry. | ||||||
| /// @param tag The tag grouping the entry. | ||||||
| /// @return The address of the entry, the zero address if none is registered. | ||||||
| function getAddress(string memory name, string memory tag) external view returns (address); | ||||||
|
|
||||||
| /// @notice Returns the address entry associated with an identifier. | ||||||
| /// @param id The identifier of the entry. | ||||||
| /// @return The address entry associated with the identifier. | ||||||
| function getAddressEntry(bytes32 id) external view returns (AddressEntry memory); | ||||||
|
|
||||||
| /// @notice Returns the identifiers of all entries grouped under a tag. | ||||||
| /// @param tag The tag grouping the entries. | ||||||
| /// @return The list of identifiers. | ||||||
| function getIds(string memory tag) external view returns (bytes32[] memory); | ||||||
|
|
||||||
| /// @notice Returns the addresses of all entries grouped under a tag. | ||||||
| /// @param tag The tag grouping the entries. | ||||||
| /// @return The list of addresses. | ||||||
| function getAddresses(string memory tag) external view returns (address[] memory); | ||||||
|
|
||||||
| /// @notice Returns all tags with at least one registered entry. | ||||||
| /// @return The list of tags. | ||||||
| function getTags() external view returns (string[] memory); | ||||||
|
|
||||||
| /// @notice Returns the canonical Hub associated with a name. | ||||||
| /// @param name The name of the Hub. | ||||||
| /// @return The address of the Hub, the zero address if none is registered. | ||||||
| function getCanonicalHub(string memory name) external view returns (address); | ||||||
|
|
||||||
| /// @notice Returns the addresses of all registered canonical Hubs. | ||||||
| /// @return The list of canonical Hub addresses. | ||||||
| function getCanonicalHubs() external view returns (address[] memory); | ||||||
|
|
||||||
| /// @notice Returns the canonical Spoke associated with a name. | ||||||
| /// @param name The name of the Spoke. | ||||||
| /// @return The address of the Spoke, the zero address if none is registered. | ||||||
| function getCanonicalSpoke(string memory name) external view returns (address); | ||||||
|
|
||||||
| /// @notice Returns the addresses of all registered canonical Spokes. | ||||||
| /// @return The list of canonical Spoke addresses. | ||||||
| function getCanonicalSpokes() external view returns (address[] memory); | ||||||
|
|
||||||
| /// @notice Returns the tokenization Spoke associated with a name. | ||||||
| /// @param name The name of the Spoke. | ||||||
| /// @return The address of the Spoke, the zero address if none is registered. | ||||||
| function getTokenizationSpoke(string memory name) external view returns (address); | ||||||
|
|
||||||
| /// @notice Returns the addresses of all registered tokenization Spokes. | ||||||
| /// @return The list of tokenization Spoke addresses. | ||||||
| function getTokenizationSpokes() external view returns (address[] memory); | ||||||
|
|
||||||
| /// @notice Returns the treasury Spoke associated with a name. | ||||||
| /// @param name The name of the Spoke. | ||||||
| /// @return The address of the Spoke, the zero address if none is registered. | ||||||
| function getTreasurySpoke(string memory name) external view returns (address); | ||||||
|
|
||||||
| /// @notice Returns the addresses of all registered treasury Spokes. | ||||||
| /// @return The list of treasury Spoke addresses. | ||||||
| function getTreasurySpokes() external view returns (address[] memory); | ||||||
|
|
||||||
| /// @notice Returns the identifier of the entry associated with a name and tag. | ||||||
| /// @dev The identifier is the hash of `<name>_<tag>` (e.g. `CORE_CANONICAL_HUB`). | ||||||
| /// @param name The name of the entry. | ||||||
| /// @param tag The tag grouping the entry. | ||||||
| /// @return The identifier of the entry. | ||||||
| function getId(string memory name, string memory tag) external pure returns (bytes32); | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thinking more its a registry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I followed the v3 naming convention here (also with the plural in "addresses" which I don't like). I'm fine changing the name, thoughts @Kogaroshi @miguelmtzinf ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to keep v3 name convention, so we don't have more difference of naming in the tooling.