diff --git a/contracts/facade/factories/CurveOracleFactory.sol b/contracts/facade/factories/CurveOracleFactory.sol new file mode 100644 index 0000000000..1fd5193c07 --- /dev/null +++ b/contracts/facade/factories/CurveOracleFactory.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BlueOak-1.0.0 +pragma solidity 0.8.19; + +import { divuu } from "../../libraries/Fixed.sol"; + +// weird circular inheritance preventing us from using proper IRToken, not worth figuring out +interface IMinimalRToken { + function basketsNeeded() external view returns (uint192); + + function totalSupply() external view returns (uint256); +} + +contract CurveOracle { + address public immutable rToken; + + constructor(address _rToken) { + rToken = _rToken; + } + + function exchangeRate() external view returns (uint256) { + return + divuu( + uint256(IMinimalRToken(rToken).basketsNeeded()), + IMinimalRToken(rToken).totalSupply() + ); + } +} + +/** + * @title CurveOracleFactory + * @notice An immutable factory for Curve oracles + */ +contract CurveOracleFactory { + error CurveOracleAlreadyDeployed(); + + event CurveOracleDeployed(address indexed rToken, address indexed curveOracle); + + mapping(address => CurveOracle) public curveOracles; + + function deployCurveOracle(address rToken) external returns (address) { + if (address(curveOracles[rToken]) != address(0)) revert CurveOracleAlreadyDeployed(); + CurveOracle curveOracle = new CurveOracle(rToken); + curveOracle.exchangeRate(); // ensure it works + curveOracles[rToken] = curveOracle; + emit CurveOracleDeployed(address(rToken), address(curveOracle)); + return address(curveOracle); + } +} diff --git a/tasks/deployment/create-curve-oracle-factory.ts b/tasks/deployment/create-curve-oracle-factory.ts new file mode 100644 index 0000000000..04e547ce37 --- /dev/null +++ b/tasks/deployment/create-curve-oracle-factory.ts @@ -0,0 +1,56 @@ +import { getChainId } from '../../common/blockchain-utils' +import { task, types } from 'hardhat/config' +import { CurveOracleFactory } from '../../typechain' + +task('create-curve-oracle-factory', 'Deploys a CurveOracleFactory') + .addOptionalParam('noOutput', 'Suppress output', false, types.boolean) + .setAction(async (params, hre) => { + const [wallet] = await hre.ethers.getSigners() + + const chainId = await getChainId(hre) + + if (!params.noOutput) { + console.log( + `Deploying CurveOracleFactory to ${hre.network.name} (${chainId}) with burner account ${wallet.address}` + ) + } + + const CurveOracleFactoryFactory = await hre.ethers.getContractFactory('CurveOracleFactory') + const curveOracleFactory = ( + await CurveOracleFactoryFactory.connect(wallet).deploy() + ) + await curveOracleFactory.deployed() + + if (!params.noOutput) { + console.log( + `Deployed CurveOracleFactory to ${hre.network.name} (${chainId}): ${curveOracleFactory.address}` + ) + } + + // Uncomment to verify + if (!params.noOutput) { + console.log('sleeping 30s') + } + + // Sleep to ensure API is in sync with chain + await new Promise((r) => setTimeout(r, 30000)) // 30s + + if (!params.noOutput) { + console.log('verifying') + } + + /** ******************** Verify CurveOracleFactory ****************************************/ + console.time('Verifying CurveOracleFactory') + await hre.run('verify:verify', { + address: curveOracleFactory.address, + constructorArguments: [], + contract: 'contracts/facade/factories/CurveOracleFactory.sol:CurveOracleFactory', + }) + console.timeEnd('Verifying CurveOracleFactory') + + if (!params.noOutput) { + console.log('verified') + } + + return { curveOracleFactory: curveOracleFactory.address } + }) diff --git a/tasks/index.ts b/tasks/index.ts index 6fba90bae8..ae59550e14 100644 --- a/tasks/index.ts +++ b/tasks/index.ts @@ -16,6 +16,7 @@ import './deployment/mock/deploy-mock-aave' import './deployment/mock/deploy-mock-wbtc' import './deployment/mock/deploy-mock-easyauction' import './deployment/create-deployer-registry' +import './deployment/create-curve-oracle-factory' import './deployment/deploy-facade-monitor' import './deployment/empty-wallet' import './deployment/cancel-tx'