-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add maticX chainlink pricer, test cases and doc
- Loading branch information
1 parent
841f81d
commit 9cf7178
Showing
4 changed files
with
404 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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 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,126 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.6.10; | ||
|
||
import {AggregatorInterface} from "../interfaces/AggregatorInterface.sol"; | ||
import {OracleInterface} from "../interfaces/OracleInterface.sol"; | ||
import {OpynPricerInterface} from "../interfaces/OpynPricerInterface.sol"; | ||
import {SafeMath} from "../packages/oz/SafeMath.sol"; | ||
|
||
/** | ||
* @notice A Pricer contract for maticX as reported by Chainlink | ||
*/ | ||
contract MaticXPricer is OpynPricerInterface { | ||
using SafeMath for uint256; | ||
|
||
/// @dev base decimals | ||
uint256 internal constant BASE = 8; | ||
|
||
/// @notice maticX chainlink response decimals | ||
uint256 public aggregatorDecimals; | ||
|
||
/// @notice the opyn oracle address | ||
OracleInterface public oracle; | ||
/// @notice the aggregator for an asset | ||
AggregatorInterface public aggregator; | ||
|
||
/// @notice asset that this pricer will a get price for | ||
address public asset; | ||
/// @notice bot address that is allowed to call setExpiryPriceInOracle | ||
address public bot; | ||
|
||
/** | ||
* @param _bot priveleged address that can call setExpiryPriceInOracle | ||
* @param _asset asset that this pricer will get a price for | ||
* @param _aggregator Chainlink aggregator contract for the asset | ||
* @param _oracle Opyn Oracle address | ||
*/ | ||
constructor( | ||
address _bot, | ||
address _asset, | ||
address _aggregator, | ||
address _oracle | ||
) public { | ||
require(_bot != address(0), "ChainLinkPricer: Cannot set 0 address as bot"); | ||
require(_oracle != address(0), "ChainLinkPricer: Cannot set 0 address as oracle"); | ||
require(_aggregator != address(0), "ChainLinkPricer: Cannot set 0 address as aggregator"); | ||
|
||
bot = _bot; | ||
oracle = OracleInterface(_oracle); | ||
aggregator = AggregatorInterface(_aggregator); | ||
asset = _asset; | ||
|
||
aggregatorDecimals = uint256(aggregator.decimals()); | ||
} | ||
|
||
/** | ||
* @notice set the expiry price in the oracle, can only be called by Bot address | ||
* @dev a roundId must be provided to confirm price validity, which is the first Chainlink price provided after the expiryTimestamp | ||
* @param _expiryTimestamp expiry to set a price for | ||
* @param _roundId the first roundId after expiryTimestamp | ||
*/ | ||
function setExpiryPriceInOracle(uint256 _expiryTimestamp, uint80 _roundId) external { | ||
(, int256 price, , uint256 roundTimestamp, ) = aggregator.getRoundData(_roundId); | ||
|
||
require(_expiryTimestamp <= roundTimestamp, "ChainLinkPricer: roundId not first after expiry"); | ||
require(price >= 0, "ChainLinkPricer: invalid price"); | ||
|
||
if (msg.sender != bot) { | ||
bool isCorrectRoundId; | ||
uint80 previousRoundId = uint80(uint256(_roundId).sub(1)); | ||
|
||
while (!isCorrectRoundId) { | ||
(, , , uint256 previousRoundTimestamp, ) = aggregator.getRoundData(previousRoundId); | ||
|
||
if (previousRoundTimestamp == 0) { | ||
require(previousRoundId > 0, "ChainLinkPricer: Invalid previousRoundId"); | ||
previousRoundId = previousRoundId - 1; | ||
} else if (previousRoundTimestamp > _expiryTimestamp) { | ||
revert("ChainLinkPricer: previousRoundId not last before expiry"); | ||
} else { | ||
isCorrectRoundId = true; | ||
} | ||
} | ||
} | ||
|
||
oracle.setExpiryPrice(asset, _expiryTimestamp, uint256(price)); | ||
} | ||
|
||
/** | ||
* @notice get the live price for the asset | ||
* @dev overides the getPrice function in OpynPricerInterface | ||
* @return price of the asset in USD, scaled by 1e8 | ||
*/ | ||
function getPrice() external view override returns (uint256) { | ||
(, int256 answer, , , ) = aggregator.latestRoundData(); | ||
require(answer > 0, "ChainLinkPricer: price is lower than 0"); | ||
// chainlink's answer is already 1e8 | ||
return _scaleToBase(uint256(answer)); | ||
} | ||
|
||
/** | ||
* @notice get historical chainlink price | ||
* @param _roundId chainlink round id | ||
* @return round price and timestamp | ||
*/ | ||
function getHistoricalPrice(uint80 _roundId) external view override returns (uint256, uint256) { | ||
(, int256 price, , uint256 roundTimestamp, ) = aggregator.getRoundData(_roundId); | ||
return (_scaleToBase(uint256(price)), roundTimestamp); | ||
} | ||
|
||
/** | ||
* @notice scale aggregator response to base decimals (1e8) | ||
* @param _price aggregator price | ||
* @return price scaled to 1e8 | ||
*/ | ||
function _scaleToBase(uint256 _price) internal view returns (uint256) { | ||
if (aggregatorDecimals > BASE) { | ||
uint256 exp = aggregatorDecimals.sub(BASE); | ||
_price = _price.div(10**exp); | ||
} else if (aggregatorDecimals < BASE) { | ||
uint256 exp = BASE.sub(aggregatorDecimals); | ||
_price = _price.mul(10**exp); | ||
} | ||
|
||
return _price; | ||
} | ||
} |
This file contains 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,81 @@ | ||
# `MaticXPricer` | ||
|
||
A Pricer contract for maticX as reported by Chainlink | ||
|
||
## Modifiers: | ||
|
||
- `onlyBot()` | ||
|
||
## Functions: | ||
|
||
- `constructor(address _bot, address _asset, address _aggregator, address _oracle) (public)` | ||
|
||
- `setExpiryPriceInOracle(uint256 _expiryTimestamp, uint80 _roundId) (external)` | ||
|
||
- `getPrice() (external)` | ||
|
||
- `getHistoricalPrice(uint80 _roundId) (external)` | ||
|
||
- `_scaleToBase(uint256 _price) (internal)` | ||
|
||
### Modifier `onlyBot()` | ||
|
||
modifier to check if sender address is equal to bot address | ||
|
||
### Function `constructor(address _bot, address _asset, address _aggregator, address _oracle) public` | ||
|
||
#### Parameters: | ||
|
||
- `_bot`: priveleged address that can call setExpiryPriceInOracle | ||
|
||
- `_asset`: asset that this pricer will get a price for | ||
|
||
- `_aggregator`: Chainlink aggregator contract for the asset | ||
|
||
- `_oracle`: Opyn Oracle address | ||
|
||
### Function `setExpiryPriceInOracle(uint256 _expiryTimestamp, uint80 _roundId) external` | ||
|
||
set the expiry price in the oracle, can only be called by Bot address | ||
|
||
a roundId must be provided to confirm price validity, which is the first Chainlink price provided after the expiryTimestamp | ||
|
||
#### Parameters: | ||
|
||
- `_expiryTimestamp`: expiry to set a price for | ||
|
||
- `_roundId`: the first roundId after expiryTimestamp | ||
|
||
### Function `getPrice() → uint256 external` | ||
|
||
get the live price for the asset | ||
|
||
overides the getPrice function in OpynPricerInterface | ||
|
||
#### Return Values: | ||
|
||
- price of the asset in USD, scaled by 1e8 | ||
|
||
### Function `getHistoricalPrice(uint80 _roundId) → uint256, uint256 external` | ||
|
||
get historical chainlink price | ||
|
||
#### Parameters: | ||
|
||
- `_roundId`: chainlink round id | ||
|
||
#### Return Values: | ||
|
||
- round price and timestamp | ||
|
||
### Function `_scaleToBase(uint256 _price) → uint256 internal` | ||
|
||
scale aggregator response to base decimals (1e8) | ||
|
||
#### Parameters: | ||
|
||
- `_price`: aggregator price | ||
|
||
#### Return Values: | ||
|
||
- price scaled to 1e8 |
Oops, something went wrong.