From 015755882fae8298aeb62addb36a3521594a1348 Mon Sep 17 00:00:00 2001 From: Elliot <34463580+ElliotFriedman@users.noreply.github.com> Date: Mon, 27 Jun 2022 16:05:17 -0700 Subject: [PATCH] Scaling Price Oracle Sets Chainlink Token (#81) * Scaling Price Oracle sets chainlink token when not on local network * update with new params from may numbers * update ScalingPriceOracle to use chainlink token provided in constructor rather than function setPublicChainlinkToken * add arbitrum chainlink token to config * add test to verify cl token address, expose getter method in SPO to get cl token address * add new scaling price oracle to mainnet addresses file, remove unnecessary comment --- contracts/mock/MockL2ScalingPriceOracle.sol | 2 + contracts/mock/MockScalingPriceOracle.sol | 14 ++++- contracts/oracle/L2ScalingPriceOracle.sol | 13 ++++- contracts/oracle/ScalingPriceOracle.sol | 19 ++++--- .../IntegrationTestL2ScalingPriceOracle.t.sol | 14 ++++- .../IntegrationTestVoltDeployment.t.sol | 7 ++- .../unit/oracle/L2ScalingPriceOracle.t.sol | 18 ++++++- .../test/unit/oracle/OraclePassThrough.t.sol | 6 ++- .../test/unit/oracle/ScalingPriceOracle.t.sol | 7 ++- contracts/test/unit/psm/NonCustodialPSM.t.sol | 3 +- protocol-configuration/mainnetAddresses.ts | 2 +- scripts/L2Config.ts | 9 ++-- scripts/l2SPOdeploy.ts | 53 +++++++++++++++++++ 13 files changed, 140 insertions(+), 27 deletions(-) create mode 100644 scripts/l2SPOdeploy.ts diff --git a/contracts/mock/MockL2ScalingPriceOracle.sol b/contracts/mock/MockL2ScalingPriceOracle.sol index 724b1c6c9..4d51f06bf 100644 --- a/contracts/mock/MockL2ScalingPriceOracle.sol +++ b/contracts/mock/MockL2ScalingPriceOracle.sol @@ -15,6 +15,7 @@ contract MockL2ScalingPriceOracle is L2ScalingPriceOracle { uint256 _fee, uint128 _currentMonth, uint128 _previousMonth, + address _chainlinkToken, uint256 _actualStartTime, uint256 _startingOraclePrice ) @@ -24,6 +25,7 @@ contract MockL2ScalingPriceOracle is L2ScalingPriceOracle { _fee, _currentMonth, _previousMonth, + _chainlinkToken, _actualStartTime, _startingOraclePrice ) diff --git a/contracts/mock/MockScalingPriceOracle.sol b/contracts/mock/MockScalingPriceOracle.sol index 129ed12fd..f4aa12652 100644 --- a/contracts/mock/MockScalingPriceOracle.sol +++ b/contracts/mock/MockScalingPriceOracle.sol @@ -16,8 +16,18 @@ contract MockScalingPriceOracle is ScalingPriceOracle { bytes32 _jobid, uint256 _fee, uint128 _currentMonth, - uint128 _previousMonth - ) ScalingPriceOracle(_oracle, _jobid, _fee, _currentMonth, _previousMonth) { + uint128 _previousMonth, + address _chainlinkToken + ) + ScalingPriceOracle( + _oracle, + _jobid, + _fee, + _currentMonth, + _previousMonth, + _chainlinkToken + ) + { owner = msg.sender; } diff --git a/contracts/oracle/L2ScalingPriceOracle.sol b/contracts/oracle/L2ScalingPriceOracle.sol index 55e93c341..54814f16a 100644 --- a/contracts/oracle/L2ScalingPriceOracle.sol +++ b/contracts/oracle/L2ScalingPriceOracle.sol @@ -19,6 +19,7 @@ contract L2ScalingPriceOracle is ScalingPriceOracle { /// @param _fee maximum fee paid to chainlink data provider /// @param _currentMonth current month's inflation data /// @param _previousMonth previous month's inflation data + /// @param _chainlinkToken address of the chainlink token /// @param _actualStartTime unix timestamp of Oracle Price interpolation starting time /// @param _startingOraclePrice starting oracle price constructor( @@ -27,9 +28,19 @@ contract L2ScalingPriceOracle is ScalingPriceOracle { uint256 _fee, uint128 _currentMonth, uint128 _previousMonth, + address _chainlinkToken, uint256 _actualStartTime, uint256 _startingOraclePrice - ) ScalingPriceOracle(_oracle, _jobid, _fee, _currentMonth, _previousMonth) { + ) + ScalingPriceOracle( + _oracle, + _jobid, + _fee, + _currentMonth, + _previousMonth, + _chainlinkToken + ) + { /// ensure start time is not more than 28 days ago require( _actualStartTime > block.timestamp - TIMEFRAME, diff --git a/contracts/oracle/ScalingPriceOracle.sol b/contracts/oracle/ScalingPriceOracle.sol index c837c7874..f776202c6 100644 --- a/contracts/oracle/ScalingPriceOracle.sol +++ b/contracts/oracle/ScalingPriceOracle.sol @@ -68,22 +68,16 @@ contract ScalingPriceOracle is /// @param _fee maximum fee paid to chainlink data provider /// @param _currentMonth current month's inflation data /// @param _previousMonth previous month's inflation data + /// @param _chainlinkToken address of the chainlink token constructor( address _oracle, bytes32 _jobid, uint256 _fee, uint128 _currentMonth, - uint128 _previousMonth + uint128 _previousMonth, + address _chainlinkToken ) Timed(TIMEFRAME) { - uint256 chainId; - // solhint-disable-next-line no-inline-assembly - assembly { - chainId := chainid() - } - - if (chainId == 1 || chainId == 42) { - setPublicChainlinkToken(); - } + setChainlinkToken(_chainlinkToken); oracle = _oracle; jobId = _jobid; @@ -124,6 +118,11 @@ contract ScalingPriceOracle is percentageChange = (delta * Constants.BP_INT) / int128(previousMonth); } + /// @notice return the address of the chainlink token referenced by this contract + function getChainlinkTokenAddress() public view returns (address) { + return chainlinkTokenAddress(); + } + /// ------------- Public API To Request Chainlink Data ------------- /// @notice Create a Chainlink request to retrieve API response, find the target diff --git a/contracts/test/integration/IntegrationTestL2ScalingPriceOracle.t.sol b/contracts/test/integration/IntegrationTestL2ScalingPriceOracle.t.sol index 66a55893c..b8ab57433 100644 --- a/contracts/test/integration/IntegrationTestL2ScalingPriceOracle.t.sol +++ b/contracts/test/integration/IntegrationTestL2ScalingPriceOracle.t.sol @@ -23,6 +23,10 @@ contract IntegrationTestL2ScalingPriceOracle is DSTest { ScalingPriceOracle(0x79412660E95F94a4D2d02a050CEA776200939917); L2ScalingPriceOracle private l2scalingPriceOracle; + /// @notice address of chainlink token on arbitrum + address public constant chainlinkToken = + 0xf97f4df75117a78c1A5a0DBb814Af92458539FB4; + /// @notice increase price by x% per month int256 public monthlyChangeRateBasisPoints = scalingPriceOracle.monthlyChangeRateBasisPoints(); @@ -58,6 +62,7 @@ contract IntegrationTestL2ScalingPriceOracle is DSTest { fee, currentMonth, previousMonth, + chainlinkToken, startTime, startOraclePrice ); @@ -99,6 +104,10 @@ contract IntegrationTestL2ScalingPriceOracle is DSTest { scalingPriceOracle.getCurrentOraclePrice(), l2scalingPriceOracle.getCurrentOraclePrice() ); + assertEq( + l2scalingPriceOracle.getChainlinkTokenAddress(), + chainlinkToken + ); } function _testOraclePriceEquivalence() internal { @@ -125,14 +134,17 @@ contract IntegrationTestL2ScalingPriceOracle is DSTest { jobId, fee, previousMonth, /// flip current and previous months so that rate is -3% - currentMonth + currentMonth, + chainlinkToken ); + l2scalingPriceOracle = new MockL2ScalingPriceOracle( oracle, jobId, fee, previousMonth, /// flip current and previous months so that rate is -3% currentMonth, + chainlinkToken, scalingPriceOracle.startTime(), 1e18 ); diff --git a/contracts/test/integration/IntegrationTestVoltDeployment.t.sol b/contracts/test/integration/IntegrationTestVoltDeployment.t.sol index a2dbac8e4..9f913ddba 100644 --- a/contracts/test/integration/IntegrationTestVoltDeployment.t.sol +++ b/contracts/test/integration/IntegrationTestVoltDeployment.t.sol @@ -56,6 +56,10 @@ contract IntegrationTestVoltDeployment is DSTest, StdLib { address public immutable feiDAOTimelock = 0xd51dbA7a94e1adEa403553A8235C302cEbF41a3c; + /// @notice address of chainlink token on mainnet + address public constant chainlinkToken = + 0x514910771AF9Ca656af840dff83E8264EcF986CA; + /// @notice Oracle Pass Through contract OraclePassThrough public oracle; @@ -70,7 +74,8 @@ contract IntegrationTestVoltDeployment is DSTest, StdLib { jobId, 10e18, 101, - 100 + 100, + address(0) ); oracle = new OraclePassThrough( diff --git a/contracts/test/unit/oracle/L2ScalingPriceOracle.t.sol b/contracts/test/unit/oracle/L2ScalingPriceOracle.t.sol index 0b97760fb..4381d1b4b 100644 --- a/contracts/test/unit/oracle/L2ScalingPriceOracle.t.sol +++ b/contracts/test/unit/oracle/L2ScalingPriceOracle.t.sol @@ -55,7 +55,8 @@ contract L2ScalingPriceOracleTest is DSTest { jobId, fee, currentMonth, - previousMonth + previousMonth, + address(0) ); vm.warp(block.timestamp + 20 days); /// now 70 days have passed @@ -66,6 +67,7 @@ contract L2ScalingPriceOracleTest is DSTest { fee, currentMonth, previousMonth, + address(0), 50 days, 1e18 ); @@ -86,6 +88,11 @@ contract L2ScalingPriceOracleTest is DSTest { scalingPriceOracle.getMonthlyAPR(), monthlyChangeRateBasisPoints ); + assertEq( + scalingPriceOracle.getChainlinkTokenAddress(), + l2scalingPriceOracle.getChainlinkTokenAddress() + ); + assertEq(l2scalingPriceOracle.getChainlinkTokenAddress(), address(0)); } function testOracleSetupEquivalence() public { @@ -135,7 +142,8 @@ contract L2ScalingPriceOracleTest is DSTest { jobId, fee, previousMonth, /// flip current and previous months so that rate is -3% - currentMonth + currentMonth, + address(0) ); l2scalingPriceOracle = new MockL2ScalingPriceOracle( oracle, @@ -143,6 +151,7 @@ contract L2ScalingPriceOracleTest is DSTest { fee, previousMonth, /// flip current and previous months so that rate is -3% currentMonth, + address(0), block.timestamp, 1e18 ); @@ -321,6 +330,7 @@ contract L2ScalingPriceOracleTest is DSTest { fee, currentMonth, previousMonth, + address(0), 0, /// cause first check to fail as 0 < 1 1e18 ); @@ -336,6 +346,7 @@ contract L2ScalingPriceOracleTest is DSTest { fee, currentMonth, previousMonth, + address(0), block.timestamp, 99e16 ); @@ -348,6 +359,7 @@ contract L2ScalingPriceOracleTest is DSTest { fee, currentMonth, previousMonth, + address(0), block.timestamp, 2e18 ); @@ -363,6 +375,7 @@ contract L2ScalingPriceOracleTest is DSTest { fee, currentMonth, previousMonth, + address(0), block.timestamp, 2e18 ); @@ -418,6 +431,7 @@ contract L2ScalingPriceOracleTest is DSTest { fee, currentMonth, previousMonth, + address(0), block.timestamp, x ); diff --git a/contracts/test/unit/oracle/OraclePassThrough.t.sol b/contracts/test/unit/oracle/OraclePassThrough.t.sol index 422498cb6..5a5e0bc0f 100644 --- a/contracts/test/unit/oracle/OraclePassThrough.t.sol +++ b/contracts/test/unit/oracle/OraclePassThrough.t.sol @@ -47,7 +47,8 @@ contract OraclePassThroughTest is DSTest { jobId, fee, currentMonth, - previousMonth + previousMonth, + address(0) ); oraclePassThrough = new OraclePassThrough( @@ -96,7 +97,8 @@ contract OraclePassThroughTest is DSTest { jobId, fee, currentMonth, - previousMonth + previousMonth, + address(0) ) ) ); diff --git a/contracts/test/unit/oracle/ScalingPriceOracle.t.sol b/contracts/test/unit/oracle/ScalingPriceOracle.t.sol index fa6ec27f3..21bee0053 100644 --- a/contracts/test/unit/oracle/ScalingPriceOracle.t.sol +++ b/contracts/test/unit/oracle/ScalingPriceOracle.t.sol @@ -51,7 +51,8 @@ contract ScalingPriceOracleTest is DSTest { jobId, fee, currentMonth, - previousMonth + previousMonth, + address(0) ); } @@ -65,6 +66,7 @@ contract ScalingPriceOracleTest is DSTest { scalingPriceOracle.getMonthlyAPR(), monthlyChangeRateBasisPoints ); + assertEq(scalingPriceOracle.getChainlinkTokenAddress(), address(0)); } /// positive price action from oracle -- inflation case @@ -80,7 +82,8 @@ contract ScalingPriceOracleTest is DSTest { jobId, fee, previousMonth, /// flip current and previous months so that rate is -3% - currentMonth + currentMonth, + address(0) ); vm.warp(block.timestamp + 28 days); diff --git a/contracts/test/unit/psm/NonCustodialPSM.t.sol b/contracts/test/unit/psm/NonCustodialPSM.t.sol index 92787d615..0d057571c 100644 --- a/contracts/test/unit/psm/NonCustodialPSM.t.sol +++ b/contracts/test/unit/psm/NonCustodialPSM.t.sol @@ -55,7 +55,8 @@ contract NonCustodialPSMTest is DSTest { keccak256(abi.encodePacked("test")), 10e18, 101, - 100 + 100, + address(0) ); oracle = new OraclePassThrough( diff --git a/protocol-configuration/mainnetAddresses.ts b/protocol-configuration/mainnetAddresses.ts index 8a943028b..0733bcc6e 100644 --- a/protocol-configuration/mainnetAddresses.ts +++ b/protocol-configuration/mainnetAddresses.ts @@ -196,7 +196,7 @@ const MainnetAddresses: MainnetAddresses = { network: Network.Arbitrum }, arbitrumScalingPriceOracle: { - address: '0x0313a76AD2cE70A35eC95066f942becab6A64893', + address: '0x138F30D35557FA72478663b601f0f0FD7cc4E39E', artifactName: 'L2ScalingPriceOracle', category: AddressCategory.Oracle, network: Network.Arbitrum diff --git a/scripts/L2Config.ts b/scripts/L2Config.ts index f9d100fbf..8aa509792 100644 --- a/scripts/L2Config.ts +++ b/scripts/L2Config.ts @@ -24,16 +24,17 @@ const l2config = { ADDRESS_ONE: '0x0000000000000000000000000000000000000001', L2_REDEEM_FEE_BASIS_POINTS: 5, - ACTUAL_START_TIME: '1652575642', - STARTING_L2_ORACLE_PRICE: '1028069999088399458', + ACTUAL_START_TIME: '1655251723', + STARTING_L2_ORACLE_PRICE: '1033724384083385655', /// Chainlink L2_ARBITRUM_JOB_ID: ethers.utils.toUtf8Bytes('db685451903340c590d22eb505d49946'), L2_ARBITRUM_CHAINLINK_FEE: ethers.utils.parseEther('1'), /// 1 Link to request data on L2 L2_ARBITRUM_CHAINLINK_ORACLE_ADDRESS: '0xf76F586F6aAC0c8dE147Eea75D76AB7c2f23eDC2', + L2_ARBITRUM_CHAINLINK_TOKEN: '0xf97f4df75117a78c1A5a0DBb814Af92458539FB4', - L2_ARBITRUM_PREVIOUS_MONTH: '287504', - L2_ARBITRUM_CURRENT_MONTH: '289109', + L2_ARBITRUM_PREVIOUS_MONTH: '289109', + L2_ARBITRUM_CURRENT_MONTH: '292296', L2_ARBITRUM_PROTOCOL_MULTISIG_ADDRESS: '0x1A1075cef632624153176CCf19Ae0175953CF010', L2_ARBITRUM_VOLT: '0x6Ba6f18a290Cd55cf1B00be2bEc5c954cb29fAc5', diff --git a/scripts/l2SPOdeploy.ts b/scripts/l2SPOdeploy.ts new file mode 100644 index 000000000..16dd69272 --- /dev/null +++ b/scripts/l2SPOdeploy.ts @@ -0,0 +1,53 @@ +import l2config from './l2config'; +import { getAllContractAddresses } from '@scripts/utils/loadContracts'; +import { ethers } from 'hardhat'; +import '@nomiclabs/hardhat-ethers'; +import { expect } from 'chai'; + +const { + /// bls cpi-u inflation data + L2_ARBITRUM_PREVIOUS_MONTH, + L2_ARBITRUM_CURRENT_MONTH, + + /// L2 chainlink + STARTING_L2_ORACLE_PRICE, + ACTUAL_START_TIME, + L2_ARBITRUM_JOB_ID, + L2_ARBITRUM_CHAINLINK_FEE, + L2_ARBITRUM_CHAINLINK_TOKEN +} = l2config; + +async function deploy() { + /// -------- System Deployment -------- + + const addresses = await getAllContractAddresses(); + const L2ScalingPriceOracleFactory = await ethers.getContractFactory('L2ScalingPriceOracle'); + + const scalingPriceOracle = await L2ScalingPriceOracleFactory.deploy( + addresses.arbitrumFiewsChainlinkOracle, + L2_ARBITRUM_JOB_ID, + L2_ARBITRUM_CHAINLINK_FEE, + L2_ARBITRUM_CURRENT_MONTH, + L2_ARBITRUM_PREVIOUS_MONTH, + L2_ARBITRUM_CHAINLINK_TOKEN, + ACTUAL_START_TIME, + STARTING_L2_ORACLE_PRICE + ); + await scalingPriceOracle.deployed(); + + console.log(`⚡L2ScalingPriceOracle⚡: ${scalingPriceOracle.address}`); + + expect(await scalingPriceOracle.getChainlinkTokenAddress()).to.be.equal(L2_ARBITRUM_CHAINLINK_TOKEN); + expect(await scalingPriceOracle.monthlyChangeRateBasisPoints()).to.be.equal(110); + expect(await scalingPriceOracle.previousMonth()).to.be.equal(L2_ARBITRUM_PREVIOUS_MONTH); + expect(await scalingPriceOracle.currentMonth()).to.be.equal(L2_ARBITRUM_CURRENT_MONTH); + expect(await scalingPriceOracle.oraclePrice()).to.be.equal(STARTING_L2_ORACLE_PRICE); + expect(await scalingPriceOracle.startTime()).to.be.equal(ACTUAL_START_TIME); +} + +deploy() + .then(() => process.exit(0)) + .catch((err) => { + console.log(err); + process.exit(1); + });