Skip to content

Commit

Permalink
fix 205
Browse files Browse the repository at this point in the history
  • Loading branch information
LayneHaber committed Jun 26, 2022
1 parent ac95c1b commit 59c1a73
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ contract ConnextPriceOracle is PriceOracle {
address public wrapped;
address public v1PriceOracle;

uint256 public constant VALID_PERIOD = 1 minutes;

/// @notice Chainlink Aggregators
mapping(address => AggregatorV3Interface) public aggregators;

Expand All @@ -59,8 +61,13 @@ contract ConnextPriceOracle is PriceOracle {
bool active; // Active status of price record 0
}

struct Price {
uint256 updatedAt;
uint256 price;
}

mapping(address => PriceInfo) public priceRecords;
mapping(address => uint256) public assetPrices;
mapping(address => Price) public assetPrices;

event NewAdmin(address oldAdmin, address newAdmin);
event PriceRecordUpdated(address token, address baseToken, address lpToken, bool _active);
Expand All @@ -83,7 +90,10 @@ contract ConnextPriceOracle is PriceOracle {
if (_tokenAddress == address(0)) {
tokenAddress = wrapped;
}
uint256 tokenPrice = assetPrices[tokenAddress];
uint256 tokenPrice = assetPrices[tokenAddress].price;
if (tokenPrice > 0 && ((block.timestamp - assetPrices[tokenAddress].updatedAt) <= VALID_PERIOD)) {
return tokenPrice;
}
if (tokenPrice == 0) {
tokenPrice = getPriceFromOracle(tokenAddress);
}
Expand Down Expand Up @@ -155,9 +165,25 @@ contract ConnextPriceOracle is PriceOracle {
emit PriceRecordUpdated(_token, _baseToken, _lpToken, _active);
}

function setDirectPrice(address _token, uint256 _price) external onlyAdmin {
emit DirectPriceUpdated(_token, assetPrices[_token], _price);
assetPrices[_token] = _price;
function setDirectPrice(
address _token,
uint256 _price,
uint256 _timestamp
) external onlyAdmin {
require(_price > 0, "bad price");

if (block.timestamp > _timestamp) {
// reject stale price
require(block.timestamp - _timestamp < VALID_PERIOD, "bad timestamp");
} else {
// reject future timestamp (<3s is allowed)
require(_timestamp - block.timestamp < 3, "in future");
_timestamp = block.timestamp;
}
emit DirectPriceUpdated(_token, assetPrices[_token].price, _price);

assetPrices[_token].price = _price;
assetPrices[_token].updatedAt = _timestamp;
}

function setV1PriceOracle(address _v1PriceOracle) external onlyAdmin {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ contract ConnextPriceOracleTest is ForgeHelper {
address[] memory sources = new address[](1);
tokenAddresses[0] = _wrapped;
sources[0] = _aggregator;
v1PriceOracle.setDirectPrice(_tokenV1, 1e18);
v1PriceOracle.setDirectPrice(_tokenV1, 1e18, block.timestamp);
priceOracle.setAggregators(tokenAddresses, sources);
priceOracle.setV1PriceOracle(address(v1PriceOracle));
}

// ============ getTokenPrice ============
function test_ConnextPriceOracle__getTokenPrice_worksIfExistsInAssetPrices() public {
priceOracle.setDirectPrice(_tokenA, 1e18);
priceOracle.setDirectPrice(_tokenA, 1e18, block.timestamp);
assertEq(priceOracle.getTokenPrice(_tokenA), 1e18);
}

Expand All @@ -59,7 +59,7 @@ contract ConnextPriceOracleTest is ForgeHelper {
address mockLpAddress = address(11111);
TestERC20(_tokenA).mint(mockLpAddress, 100);
TestERC20(_tokenB).mint(mockLpAddress, 200);
priceOracle.setDirectPrice(_tokenA, 1e18);
priceOracle.setDirectPrice(_tokenA, 1e18, block.timestamp);
priceOracle.setDexPriceInfo(_tokenB, _tokenA, mockLpAddress, true);
assertEq(priceOracle.getTokenPrice(_tokenB), 5e17);
}
Expand Down Expand Up @@ -92,7 +92,7 @@ contract ConnextPriceOracleTest is ForgeHelper {
address mockLpAddress = address(11111);
TestERC20(_tokenA).mint(mockLpAddress, 100);
TestERC20(_tokenB).mint(mockLpAddress, 200);
priceOracle.setDirectPrice(_tokenA, 1e18);
priceOracle.setDirectPrice(_tokenA, 1e18, block.timestamp);
priceOracle.setDexPriceInfo(_tokenB, _tokenA, mockLpAddress, true);
assertEq(priceOracle.getPriceFromDex(_tokenB), 5e17);
}
Expand Down Expand Up @@ -128,7 +128,7 @@ contract ConnextPriceOracleTest is ForgeHelper {
address mockLpAddress = address(11111);
TestERC20(_tokenA).mint(mockLpAddress, 100);
TestERC20(_tokenB).mint(mockLpAddress, 200);
priceOracle.setDirectPrice(_tokenA, 1e18);
priceOracle.setDirectPrice(_tokenA, 1e18, block.timestamp);
vm.expectEmit(true, true, true, true);
emit PriceRecordUpdated(_tokenB, _tokenA, mockLpAddress, true);
priceOracle.setDexPriceInfo(_tokenB, _tokenA, mockLpAddress, true);
Expand All @@ -139,15 +139,18 @@ contract ConnextPriceOracleTest is ForgeHelper {
function test_ConnextPriceOracle__setDirectPrice_worksIfOnlyAdmin() public {
vm.expectEmit(true, true, true, true);
emit DirectPriceUpdated(_tokenA, 0, 2e18);
priceOracle.setDirectPrice(_tokenA, 2e18);
assertEq(priceOracle.assetPrices(_tokenA), 2e18);
priceOracle.setDirectPrice(_tokenA, 2e18, block.timestamp);
(uint256 timestamp, uint256 price) = priceOracle.assetPrices(_tokenA);
assertEq(timestamp, block.timestamp);
assertEq(price, 2e18);
}

function test_ConnextPriceOracle__setDirectPrice_failsIfNotAdmin() public {
vm.expectRevert(bytes("caller is not the admin"));
vm.prank(address(12345));
priceOracle.setDirectPrice(_tokenA, 2e18);
assertEq(priceOracle.assetPrices(_tokenA), 0);
priceOracle.setDirectPrice(_tokenA, 2e18, block.timestamp);
(uint256 price, ) = priceOracle.assetPrices(_tokenA);
assertEq(price, 0);
}

// ============ setV1PriceOracle ============
Expand Down

0 comments on commit 59c1a73

Please sign in to comment.