https://etherscan.io/address/0x24451f47caf13b24f4b5034e1df6c0e401ec0e46 (opens in a new tab)
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
// Prettier ignore to prevent buidler flatter bug
// prettier-ignore
import {ILendPoolAddressesProvider} from "../interfaces/ILendPoolAddressesProvider.sol";
import {BendUpgradeableProxy} from "../libraries/proxy/BendUpgradeableProxy.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
/**
* @title LendPoolAddressesProvider contract
* @dev Main registry of addresses part of or connected to the protocol, including permissioned roles
* - Acting also as factory of proxies and admin of those, so with right to change its implementations
* - Owned by the Bend Governance
* @author Bend
**/
contract LendPoolAddressesProvider is Ownable, ILendPoolAddressesProvider {
string private _marketId;
mapping(bytes32 => address) private _addresses;
bytes32 private constant LEND_POOL = "LEND_POOL";
bytes32 private constant LEND_POOL_CONFIGURATOR = "LEND_POOL_CONFIGURATOR";
bytes32 private constant POOL_ADMIN = "POOL_ADMIN";
bytes32 private constant EMERGENCY_ADMIN = "EMERGENCY_ADMIN";
bytes32 private constant RESERVE_ORACLE = "RESERVE_ORACLE";
bytes32 private constant NFT_ORACLE = "NFT_ORACLE";
bytes32 private constant BEND_ORACLE = "BEND_ORACLE";
bytes32 private constant LEND_POOL_LOAN = "LEND_POOL_LOAN";
bytes32 private constant BNFT_REGISTRY = "BNFT_REGISTRY";
bytes32 private constant LEND_POOL_LIQUIDATOR = "LEND_POOL_LIQUIDATOR";
bytes32 private constant INCENTIVES_CONTROLLER = "INCENTIVES_CONTROLLER";
bytes32 private constant BEND_DATA_PROVIDER = "BEND_DATA_PROVIDER";
bytes32 private constant UI_DATA_PROVIDER = "UI_DATA_PROVIDER";
bytes32 private constant WALLET_BALANCE_PROVIDER = "WALLET_BALANCE_PROVIDER";
constructor(string memory marketId) {
_setMarketId(marketId);
}
/**
* @dev Returns the id of the Bend market to which this contracts points to
* @return The market id
**/
function getMarketId() external view override returns (string memory) {
return _marketId;
}
/**
* @dev Allows to set the market which this LendPoolAddressesProvider represents
* @param marketId The market id
*/
function setMarketId(string memory marketId) external override onlyOwner {
_setMarketId(marketId);
}
/**
* @dev General function to update the implementation of a proxy registered with
* certain `id`. If there is no proxy registered, it will instantiate one and
* set as implementation the `implementationAddress`
* IMPORTANT Use this function carefully, only for ids that don't have an explicit
* setter function, in order to avoid unexpected consequences
* @param id The id
* @param implementationAddress The address of the new implementation
*/
function setAddressAsProxy(
bytes32 id,
address implementationAddress,
bytes memory encodedCallData
) external override onlyOwner {
_updateImpl(id, implementationAddress);
emit AddressSet(id, implementationAddress, true, encodedCallData);
if (encodedCallData.length > 0) {
Address.functionCall(_addresses[id], encodedCallData);
}
}
/**
* @dev Sets an address for an id replacing the address saved in the addresses map
* IMPORTANT Use this function carefully, as it will do a hard replacement
* @param id The id
* @param newAddress The address to set
*/
function setAddress(bytes32 id, address newAddress) external override onlyOwner {
_addresses[id] = newAddress;
emit AddressSet(id, newAddress, false, new bytes(0));
}
/**
* @dev Returns an address by id
* @return The address
*/
function getAddress(bytes32 id) public view override returns (address) {
return _addresses[id];
}
/**
* @dev Returns the address of the LendPool proxy
* @return The LendPool proxy address
**/
function getLendPool() external view override returns (address) {
return getAddress(LEND_POOL);
}
/**
* @dev Updates the implementation of the LendPool, or creates the proxy
* setting the new `pool` implementation on the first time calling it
* @param pool The new LendPool implementation
**/
function setLendPoolImpl(address pool, bytes memory encodedCallData) external override onlyOwner {
_updateImpl(LEND_POOL, pool);
emit LendPoolUpdated(pool, encodedCallData);
if (encodedCallData.length > 0) {
Address.functionCall(_addresses[LEND_POOL], encodedCallData);
}
}
/**
* @dev Returns the address of the LendPoolConfigurator proxy
* @return The LendPoolConfigurator proxy address
**/
function getLendPoolConfigurator() external view override returns (address) {
return getAddress(LEND_POOL_CONFIGURATOR);
}
/**
* @dev Updates the implementation of the LendPoolConfigurator, or creates the proxy
* setting the new `configurator` implementation on the first time calling it
* @param configurator The new LendPoolConfigurator implementation
**/
function setLendPoolConfiguratorImpl(address configurator, bytes memory encodedCallData) external override onlyOwner {
_updateImpl(LEND_POOL_CONFIGURATOR, configurator);
emit LendPoolConfiguratorUpdated(configurator, encodedCallData);
if (encodedCallData.length > 0) {
Address.functionCall(_addresses[LEND_POOL_CONFIGURATOR], encodedCallData);
}
}
/**
* @dev The functions below are getters/setters of addresses that are outside the context
* of the protocol hence the upgradable proxy pattern is not used
**/
function getPoolAdmin() external view override returns (address) {
return getAddress(POOL_ADMIN);
}
function setPoolAdmin(address admin) external override onlyOwner {
_addresses[POOL_ADMIN] = admin;
emit ConfigurationAdminUpdated(admin);
}
function getEmergencyAdmin() external view override returns (address) {
return getAddress(EMERGENCY_ADMIN);
}
function setEmergencyAdmin(address emergencyAdmin) external override onlyOwner {
_addresses[EMERGENCY_ADMIN] = emergencyAdmin;
emit EmergencyAdminUpdated(emergencyAdmin);
}
function getReserveOracle() external view override returns (address) {
return getAddress(RESERVE_ORACLE);
}
function setReserveOracle(address reserveOracle) external override onlyOwner {
_addresses[RESERVE_ORACLE] = reserveOracle;
emit ReserveOracleUpdated(reserveOracle);
}
function getNFTOracle() external view override returns (address) {
return getAddress(NFT_ORACLE);
}
function setNFTOracle(address nftOracle) external override onlyOwner {
_addresses[NFT_ORACLE] = nftOracle;
emit NftOracleUpdated(nftOracle);
}
function getLendPoolLoan() external view override returns (address) {
return getAddress(LEND_POOL_LOAN);
}
function setLendPoolLoanImpl(address loanAddress, bytes memory encodedCallData) external override onlyOwner {
_updateImpl(LEND_POOL_LOAN, loanAddress);
emit LendPoolLoanUpdated(loanAddress, encodedCallData);
if (encodedCallData.length > 0) {
Address.functionCall(_addresses[LEND_POOL_LOAN], encodedCallData);
}
}
function getBNFTRegistry() external view override returns (address) {
return getAddress(BNFT_REGISTRY);
}
function setBNFTRegistry(address factory) external override onlyOwner {
_addresses[BNFT_REGISTRY] = factory;
emit BNFTRegistryUpdated(factory);
}
function getLendPoolLiquidator() external view override returns (address) {
return getAddress(LEND_POOL_LIQUIDATOR);
}
function setLendPoolLiquidator(address liquidator) external override onlyOwner {
_addresses[LEND_POOL_LIQUIDATOR] = liquidator;
emit LendPoolLiquidatorUpdated(liquidator);
}
function getIncentivesController() external view override returns (address) {
return getAddress(INCENTIVES_CONTROLLER);
}
function setIncentivesController(address controller) external override onlyOwner {
_addresses[INCENTIVES_CONTROLLER] = controller;
emit IncentivesControllerUpdated(controller);
}
function getUIDataProvider() external view override returns (address) {
return getAddress(UI_DATA_PROVIDER);
}
function setUIDataProvider(address provider) external override onlyOwner {
_addresses[UI_DATA_PROVIDER] = provider;
emit UIDataProviderUpdated(provider);
}
function getBendDataProvider() external view override returns (address) {
return getAddress(BEND_DATA_PROVIDER);
}
function setBendDataProvider(address provider) external override onlyOwner {
_addresses[BEND_DATA_PROVIDER] = provider;
emit BendDataProviderUpdated(provider);
}
function getWalletBalanceProvider() external view override returns (address) {
return getAddress(WALLET_BALANCE_PROVIDER);
}
function setWalletBalanceProvider(address provider) external override onlyOwner {
_addresses[WALLET_BALANCE_PROVIDER] = provider;
emit WalletBalanceProviderUpdated(provider);
}
function getImplementation(address proxyAddress) external view onlyOwner returns (address) {
BendUpgradeableProxy proxy = BendUpgradeableProxy(payable(proxyAddress));
return proxy.getImplementation();
}
/**
* @dev Internal function to update the implementation of a specific proxied component of the protocol
* - If there is no proxy registered in the given `id`, it creates the proxy setting `newAdress`
* as implementation and calls the initialize() function on the proxy
* - If there is already a proxy registered, it just updates the implementation to `newAddress` and
* calls the encoded method function via upgradeToAndCall() in the proxy
* @param id The id of the proxy to be updated
* @param newAddress The address of the new implementation
**/
function _updateImpl(bytes32 id, address newAddress) internal {
address payable proxyAddress = payable(_addresses[id]);
if (proxyAddress == address(0)) {
bytes memory params = abi.encodeWithSignature("initialize(address)", address(this));
// create proxy, then init proxy & implementation
BendUpgradeableProxy proxy = new BendUpgradeableProxy(newAddress, address(this), params);
_addresses[id] = address(proxy);
emit ProxyCreated(id, address(proxy));
} else {
// upgrade implementation
BendUpgradeableProxy proxy = BendUpgradeableProxy(proxyAddress);
proxy.upgradeTo(newAddress);
}
}
function _setMarketId(string memory marketId) internal {
_marketId = marketId;
emit MarketIdSet(marketId);
}
}