Skip to content

Commit

Permalink
Equivalent tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
pahor167 committed Jan 17, 2024
1 parent 5d67d3e commit 17aae0f
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 2 deletions.
29 changes: 27 additions & 2 deletions packages/protocol/contracts/stability/SortedOracles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ contract SortedOracles is ISortedOracles, ICeloVersionedContract, Ownable, Initi
mapping(address => uint256) public tokenReportExpirySeconds;

IBreakerBox public breakerBox;
// Maps a token address to its equivalent token address.
// For example, maps the USDC token address to the cUSD token address.
// Original token will return the median value as equivalent token.
mapping(address => address) public equivalentTokens;

event OracleAdded(address indexed token, address indexed oracleAddress);
event OracleRemoved(address indexed token, address indexed oracleAddress);
Expand All @@ -75,6 +79,7 @@ contract SortedOracles is ISortedOracles, ICeloVersionedContract, Ownable, Initi
event ReportExpirySet(uint256 reportExpiry);
event TokenReportExpirySet(address token, uint256 reportExpiry);
event BreakerBoxUpdated(address indexed newBreakerBox);
event EquivalentTokenSet(address indexed token, address indexed equivalentToken);

modifier onlyOracle(address token) {
require(isOracle[token][msg.sender], "sender was not an oracle for token addr");
Expand Down Expand Up @@ -221,6 +226,17 @@ contract SortedOracles is ISortedOracles, ICeloVersionedContract, Ownable, Initi
return (false, oldest);
}

/**
* @notice Sets the equivalent token for a token.
* @param token The address of the token.
* @param equivalentToken The address of the equivalent token.
*/
function setEquivalentToken(address token, address equivalentToken) external onlyOwner {
require(token != address(0), "token address cannot be 0");
equivalentTokens[token] = equivalentToken;
emit EquivalentTokenSet(token, equivalentToken);
}

/**
* @notice Updates an oracle value and the median.
* @param token The rateFeedId for the rate that is being reported.
Expand Down Expand Up @@ -285,8 +301,17 @@ contract SortedOracles is ISortedOracles, ICeloVersionedContract, Ownable, Initi
* @return uint256 The median exchange rate for rateFeedId.
* @return fixidity
*/
function medianRate(address token) external view returns (uint256, uint256) {
return (rates[token].getMedianValue(), numRates(token) == 0 ? 0 : FIXED1_UINT);
function medianRate(address token) external view returns (uint256 rate, uint256 numRates) {
address equivalentToken = equivalentTokens[token];
if (equivalentToken != address(0)) {
rate = rates[equivalentToken].getMedianValue();
numRates = rates[equivalentToken].getNumElements();
} else {
rate = rates[token].getMedianValue();
numRates = rates[token].getNumElements();
}

numRates = numRates == 0 ? 0 : FIXED1_UINT;
}

/**
Expand Down
47 changes: 47 additions & 0 deletions packages/protocol/test-sol/stability/SortedOracles.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "../../contracts/common/FixidityLib.sol";
import "../../contracts/common/linkedlists/AddressSortedLinkedListWithMedian.sol";
import "../../contracts/common/linkedlists/SortedLinkedListWithMedian.sol";
import { Constants } from "../constants.sol";
import "forge-std/console.sol";

contract SortedOraclesTest is Test, Constants {
using FixidityLib for FixidityLib.Fraction;
Expand All @@ -31,6 +32,7 @@ contract SortedOraclesTest is Test, Constants {
event MedianUpdated(address indexed token, uint256 value);
event ReportExpirySet(uint256 reportExpiry);
event TokenReportExpirySet(address token, uint256 reportExpiry);
event EquivalentTokenSet(address indexed token, address indexed equivalentToken);

function setUp() public {
warp(0);
Expand Down Expand Up @@ -80,6 +82,38 @@ contract SetReportExpiry is SortedOraclesTest {
}
}

contract SetEquivalentToken is SortedOraclesTest {
address bToken = actor("bToken");

function test_ShouldSetReportExpiry() public {
sortedOracle.setEquivalentToken(aToken, bToken);
assertEq(sortedOracle.equivalentTokens(aToken), bToken);
}

function test_ShouldRevert_WhenEquivalentToken0() public {
vm.expectRevert("token address cannot be 0");
sortedOracle.setEquivalentToken(address(0), bToken);
}

function test_ShouldEmitEquivalentTokenSet() public {
vm.expectEmit(true, true, true, true);
emit EquivalentTokenSet(aToken, bToken);
sortedOracle.setEquivalentToken(aToken, bToken);
}

function test_ShouldRemoveEquivalentToken_WhenAlreadySet() public {
sortedOracle.setEquivalentToken(aToken, bToken);
sortedOracle.setEquivalentToken(aToken, address(0));
assertEq(sortedOracle.equivalentTokens(aToken), address(0));
}

function test_ShouldRevertWhenNotOwner() public {
vm.expectRevert("Ownable: caller is not the owner");
vm.prank(oracleAccount);
sortedOracle.setEquivalentToken(aToken, bToken);
}
}

contract SetTokenReportExpiry is SortedOraclesTest {
function test_ShouldSetTokenReportExpiry() public {
uint256 newReportExpiry = reportExpiry * 2;
Expand Down Expand Up @@ -479,6 +513,8 @@ contract Report is SortedOraclesTest {
uint256 oracleValue2 = FixidityLib.newFixedFraction(3, 1).unwrap();
uint256 anotherOracleValue = FIXED1;

address bToken = actor("bToken");

function setUp() public {
super.setUp();
sortedOracle.addOracle(aToken, oracleAccount);
Expand All @@ -498,6 +534,17 @@ contract Report is SortedOraclesTest {
assertEq(denominator, FIXED1);
}

function test_ShouldSetTheMedianRate_WhenEquivalentTokenIsSet() public {
vm.prank(oracleAccount);
sortedOracle.report(aToken, value, address(0), address(0));
sortedOracle.setEquivalentToken(bToken, aToken);
(uint256 medianRate, uint256 denominator) = sortedOracle.medianRate(bToken);
console.log("medianRate", medianRate);
console.log("denominator", denominator);
assertEq(medianRate, value);
assertEq(denominator, FIXED1);
}

function test_ShouldIncreaseTheNumberOfTimestamps() public {
vm.prank(oracleAccount);
sortedOracle.report(aToken, value, address(0), address(0));
Expand Down

0 comments on commit 17aae0f

Please sign in to comment.