-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add capped fallback rate source; update rate source to include decimals * add capped fallback rate source; update rate source to include decimals * add unit tests * add integration test * anchor old tests to previous fork * update to new block with correct LST rate * add readme * review fixes * styling on if/else * separate tests for decimal change and comment * simplify the logic for getAPR() * more extensive boundary tests
- Loading branch information
Showing
12 changed files
with
323 additions
and
22 deletions.
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,47 @@ | ||
// SPDX-License-Identifier: AGPL-3.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import { IRateSource } from "./interfaces/IRateSource.sol"; | ||
|
||
/** | ||
* @title CappedFallbackRateSource | ||
* @notice Wraps another rate source, caps the rate and protects against reverts with a fallback value. | ||
*/ | ||
contract CappedFallbackRateSource is IRateSource { | ||
|
||
IRateSource public immutable source; | ||
uint256 public immutable lowerBound; | ||
uint256 public immutable upperBound; | ||
uint256 public immutable defaultRate; | ||
|
||
constructor( | ||
address _source, | ||
uint256 _lowerBound, | ||
uint256 _upperBound, | ||
uint256 _defaultRate | ||
) { | ||
require(_lowerBound <= _upperBound, "CappedFallbackRateSource/invalid-bounds"); | ||
require(_defaultRate >= _lowerBound && _defaultRate <= _upperBound, "CappedFallbackRateSource/invalid-default-rate"); | ||
|
||
source = IRateSource(_source); | ||
lowerBound = _lowerBound; | ||
upperBound = _upperBound; | ||
defaultRate = _defaultRate; | ||
} | ||
|
||
function getAPR() external override view returns (uint256) { | ||
try source.getAPR() returns (uint256 rate) { | ||
if (rate < lowerBound) return lowerBound; | ||
else if (rate > upperBound) return upperBound; | ||
|
||
return rate; | ||
} catch { | ||
return defaultRate; | ||
} | ||
} | ||
|
||
function decimals() external view override returns (uint8) { | ||
return source.decimals(); | ||
} | ||
|
||
} |
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
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
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,142 @@ | ||
// SPDX-License-Identifier: AGPL-3.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import "forge-std/Test.sol"; | ||
|
||
import { RateSourceMock } from "./mocks/RateSourceMock.sol"; | ||
|
||
import { CappedFallbackRateSource } from "../src/CappedFallbackRateSource.sol"; | ||
|
||
contract RevertingRateSource { | ||
function getAPR() external pure returns (uint256) { | ||
revert("RevertingRateSource/some-error"); | ||
} | ||
} | ||
|
||
contract CappedFallbackRateSourceTest is Test { | ||
|
||
RateSourceMock originalSource; | ||
|
||
CappedFallbackRateSource rateSource; | ||
|
||
function setUp() public { | ||
originalSource = new RateSourceMock(0.037e18, 18); | ||
|
||
rateSource = new CappedFallbackRateSource({ | ||
_source: address(originalSource), | ||
_lowerBound: 0.01e18, | ||
_upperBound: 0.08e18, | ||
_defaultRate: 0.03e18 | ||
}); | ||
} | ||
|
||
function test_constructor_lowerBoundGtUpperBoundBoundary() public { | ||
vm.expectRevert("CappedFallbackRateSource/invalid-bounds"); | ||
new CappedFallbackRateSource({ | ||
_source: address(originalSource), | ||
_lowerBound: 0.01e18 + 1, // Lower bound is larger than upper bound | ||
_upperBound: 0.01e18, | ||
_defaultRate: 0.01e18 | ||
}); | ||
|
||
new CappedFallbackRateSource({ | ||
_source: address(originalSource), | ||
_lowerBound: 0.01e18, | ||
_upperBound: 0.01e18, | ||
_defaultRate: 0.01e18 | ||
}); | ||
} | ||
|
||
function test_constructor_defaultRateLtLowerBoundBoundary() public { | ||
vm.expectRevert("CappedFallbackRateSource/invalid-default-rate"); | ||
new CappedFallbackRateSource({ | ||
_source: address(originalSource), | ||
_lowerBound: 0.01e18, | ||
_upperBound: 0.08e18, | ||
_defaultRate: 0.01e18 - 1 // Default rate is below lower bound | ||
}); | ||
|
||
new CappedFallbackRateSource({ | ||
_source: address(originalSource), | ||
_lowerBound: 0.01e18, | ||
_upperBound: 0.08e18, | ||
_defaultRate: 0.01e18 | ||
}); | ||
} | ||
|
||
function test_constructor_defaultRateGtUpperBoundBoundary() public { | ||
vm.expectRevert("CappedFallbackRateSource/invalid-default-rate"); | ||
new CappedFallbackRateSource({ | ||
_source: address(originalSource), | ||
_lowerBound: 0.01e18, | ||
_upperBound: 0.08e18, | ||
_defaultRate: 0.08e18 + 1 // Default rate is above upper bound | ||
}); | ||
|
||
new CappedFallbackRateSource({ | ||
_source: address(originalSource), | ||
_lowerBound: 0.01e18, | ||
_upperBound: 0.08e18, | ||
_defaultRate: 0.08e18 | ||
}); | ||
} | ||
|
||
function test_constructor() public { | ||
assertEq(address(rateSource.source()), address(originalSource)); | ||
assertEq(rateSource.lowerBound(), 0.01e18); | ||
assertEq(rateSource.upperBound(), 0.08e18); | ||
assertEq(rateSource.defaultRate(), 0.03e18); | ||
} | ||
|
||
function test_decimals() public { | ||
assertEq(rateSource.decimals(), 18); | ||
|
||
originalSource.setDecimals(27); | ||
|
||
assertEq(rateSource.decimals(), 27); | ||
} | ||
|
||
function test_getAPR_rateWithinBounds() public { | ||
assertEq(rateSource.getAPR(), 0.037e18); | ||
} | ||
|
||
function test_getAPR_rateBelowLowerBoundBoundary() public { | ||
originalSource.setRate(0.01e18 - 1); | ||
|
||
assertEq(rateSource.getAPR(), 0.01e18); // Use lowerBound | ||
|
||
originalSource.setRate(0.01e18); | ||
|
||
assertEq(rateSource.getAPR(), 0.01e18); // Use sourceRate | ||
|
||
originalSource.setRate(0.01e18 + 1); | ||
|
||
assertEq(rateSource.getAPR(), 0.01e18 + 1); // Use sourceRate | ||
} | ||
|
||
function test_getAPR_rateAboveUpperBoundBoundary() public { | ||
originalSource.setRate(0.08e18 + 1); | ||
|
||
assertEq(rateSource.getAPR(), 0.08e18); // Use upperBound | ||
|
||
originalSource.setRate(0.08e18); | ||
|
||
assertEq(rateSource.getAPR(), 0.08e18); // Use sourceRate | ||
|
||
originalSource.setRate(0.08e18 - 1); | ||
|
||
assertEq(rateSource.getAPR(), 0.08e18 - 1); // Use sourceRate | ||
} | ||
|
||
function test_getAPR_rateReverts() public { | ||
rateSource = new CappedFallbackRateSource({ | ||
_source: address(new RevertingRateSource()), | ||
_lowerBound: 0.01e18, | ||
_upperBound: 0.08e18, | ||
_defaultRate: 0.03e18 | ||
}); | ||
|
||
assertEq(rateSource.getAPR(), 0.03e18); | ||
} | ||
|
||
} |
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
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
Oops, something went wrong.