-
Notifications
You must be signed in to change notification settings - Fork 7
feat: scaled price adaptor #23
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
Changes from 1 commit
66f0d6a
c3aec05
a3de678
b91bff7
481aba9
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,51 @@ | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
| pragma solidity ^0.8.10; | ||
|
|
||
| import {AggregatorInterface} from '../../dependencies/chainlink/AggregatorInterface.sol'; | ||
| import {IScaledPriceAdaptor} from '../../interfaces/IScaledPriceAdaptor.sol'; | ||
|
|
||
| /** | ||
| * @title ScaledPriceAdaptor | ||
| * @author Aave Labs | ||
| * @dev Price Adaptor for Chainlink price feeds with non standard decimal USD feeds to 8 decimals. | ||
| */ | ||
| contract ScaledPriceAdaptor is IScaledPriceAdaptor { | ||
| AggregatorInterface internal immutable _SOURCE; | ||
|
|
||
| uint8 internal constant _BASE_DECIMALS = 8; | ||
| bool internal immutable _SCALE_UP; | ||
| uint256 internal immutable _SCALE; | ||
|
|
||
| constructor(address source_) { | ||
| _SOURCE = AggregatorInterface(source_); | ||
| uint8 sourceDecimals = _SOURCE.decimals(); | ||
| _SCALE_UP = sourceDecimals < _BASE_DECIMALS; | ||
| _SCALE = 10 ** (_SCALE_UP ? _BASE_DECIMALS - sourceDecimals : sourceDecimals - _BASE_DECIMALS); | ||
| } | ||
|
|
||
| /// @inheritdoc IScaledPriceAdaptor | ||
| function latestAnswer() external view returns (int256) { | ||
| return | ||
| _SCALE_UP ? _SOURCE.latestAnswer() * int256(_SCALE) : _SOURCE.latestAnswer() / int256(_SCALE); | ||
| } | ||
|
|
||
| /// @inheritdoc IScaledPriceAdaptor | ||
| function description() external view returns (string memory) { | ||
| return string.concat(_SOURCE.description(), ' (USD Scaled)'); | ||
|
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. why USD? should we omit it?
Member
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. 'USD' unit for the 8 decimals (that we've fixed here) |
||
| } | ||
|
|
||
| /// @inheritdoc IScaledPriceAdaptor | ||
| function decimals() external pure returns (uint8) { | ||
| return _BASE_DECIMALS; | ||
| } | ||
|
|
||
| /// @inheritdoc IScaledPriceAdaptor | ||
| function scale() external view returns (bool, uint256) { | ||
| return (_SCALE_UP, _SCALE); | ||
| } | ||
|
|
||
| /// @inheritdoc IScaledPriceAdaptor | ||
| function source() external view returns (address) { | ||
| return address(_SOURCE); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
| pragma solidity ^0.8.10; | ||
|
|
||
| interface IScaledPriceAdaptor { | ||
| /** | ||
| * @dev Units and direction used to scale answer to base decimals of 8. | ||
| * @dev Looses price precision when scaling down by log10(scaleUnits). | ||
DhairyaSethi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * @return scaleUp Whether to scale up or down. | ||
| * @return scaleUnits The units to scale by. | ||
| */ | ||
| function scale() external view returns (bool scaleUp, uint256 scaleUnits); | ||
|
|
||
| /** | ||
| * @dev The decimals of price adaptor. | ||
| */ | ||
| function decimals() external view returns (uint8); | ||
|
|
||
| /** | ||
| * @dev Underlying chainlink price source. | ||
| */ | ||
| function source() external view returns (address); | ||
|
|
||
| /** | ||
| * @dev Description of price adaptor. | ||
| */ | ||
| function description() external view returns (string memory); | ||
|
|
||
| /** | ||
| * @dev Scaled `latestAnswer` from chainlink price feed. | ||
| * @dev Looses price precision when scaling down by log10(scaleUnits). | ||
DhairyaSethi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| */ | ||
| function latestAnswer() external view returns (int256); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.10; | ||
|
|
||
| import {MockAggregator} from './MockAggregator.sol'; | ||
|
|
||
| contract MockAggregatorMetadata is MockAggregator { | ||
| uint8 internal immutable _DECIMALS; | ||
|
|
||
| constructor(int256 initialAnswer_, uint8 decimals_) MockAggregator(initialAnswer_) { | ||
| _DECIMALS = decimals_; | ||
| } | ||
|
|
||
| function decimals() external view override returns (uint8) { | ||
| return _DECIMALS; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import {MockAggregatorMetadata} from '../../../src/contracts/mocks/oracle/CLAggregators/MockAggregatorMetadata.sol'; | ||
| import {ScaledPriceAdaptor} from '../../../src/contracts/extensions/price-adaptors/ScaledPriceAdaptor.sol'; | ||
| import {TestnetProcedures} from '../../utils/TestnetProcedures.sol'; | ||
|
|
||
| contract ScaledPriceAdaptorTests is TestnetProcedures { | ||
| function test_adaptor_less_than_base() public { | ||
| test_fuzz_adaptor({sourceDecimals: 2, price: 1e2}); | ||
| test_fuzz_adaptor({sourceDecimals: 6, price: 32.323e6}); | ||
| } | ||
|
|
||
| function test_adaptor_greater_than_base() public { | ||
| test_fuzz_adaptor({sourceDecimals: 12, price: 1e12}); | ||
| } | ||
|
|
||
| function test_adaptor_equal_to_base() public { | ||
| test_fuzz_adaptor({sourceDecimals: 8, price: 1e8}); | ||
| } | ||
|
|
||
| function test_fuzz_adaptor(uint256 sourceDecimals, int256 price) public { | ||
| sourceDecimals = bound(sourceDecimals, 1, 36); | ||
| price = bound(price, 1, int256(10 ** sourceDecimals)); | ||
| address source = address(new MockAggregatorMetadata(price, uint8(sourceDecimals))); | ||
| ScaledPriceAdaptor adaptor = new ScaledPriceAdaptor(source); | ||
|
|
||
| (bool scaleUp, uint256 scale) = adaptor.scale(); | ||
| assertEq(adaptor.decimals(), 8); | ||
| assertEq(scaleUp, adaptor.decimals() > sourceDecimals); | ||
| assertEq( | ||
| scale, | ||
| 10 ** (scaleUp ? adaptor.decimals() - sourceDecimals : sourceDecimals - adaptor.decimals()) | ||
| ); | ||
| assertEq(adaptor.latestAnswer(), scaleUp ? price * int256(scale) : price / int256(scale)); | ||
| assertEq(adaptor.source(), source); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.