Skip to content
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

Feat/pricer fixes #446

Closed
wants to merge 18 commits into from
Closed
28 changes: 18 additions & 10 deletions contracts/pricers/ChainlinkPricer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,34 @@ contract ChainLinkPricer is OpynPricerInterface {
aggregatorDecimals = uint256(aggregator.decimals());
}

/**
* @notice modifier to check if sender address is equal to bot address
*/
modifier onlyBot() {
require(msg.sender == bot, "ChainLinkPricer: unauthorized sender");

_;
}

/**
* @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 onlyBot {
function setExpiryPriceInOracle(uint256 _expiryTimestamp, uint80 _roundId) external {
(, int256 price, , uint256 roundTimestamp, ) = aggregator.getRoundData(_roundId);

require(_expiryTimestamp <= roundTimestamp, "ChainLinkPricer: invalid roundId");

if (msg.sender != bot) {
bool isCorrectRoundId;
uint80 previousRoundId = uint80(uint256(_roundId).sub(1));

while (!isCorrectRoundId) {
(, , , uint256 previousRoundTimestamp, ) = aggregator.getRoundData(previousRoundId);

if (previousRoundTimestamp == 0) {
previousRoundId = uint80(uint256(previousRoundId).sub(1));
} else if (previousRoundTimestamp > _expiryTimestamp) {
revert("ChainLinkPricer: invalid roundId");
} else {
isCorrectRoundId = true;
}
}
}

oracle.setExpiryPrice(asset, _expiryTimestamp, uint256(price));
}

Expand Down
14 changes: 1 addition & 13 deletions test/integration-tests/pricer-oracle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,19 +161,7 @@ contract('Pricer + Oracle', ([owner, bot, disputer, random]) => {
'CompoundPricer: underlying price not set yet',
)
})

it('should revert set weth price if sender is not bot address', async () => {
const expiryTimestamp = (t0 + t1) / 2 // between t0 and t1
if ((await time.latest()) < expiryTimestamp + lockingPeriod) {
await time.increaseTo(expiryTimestamp + lockingPeriod + 10)
}
const roundId = 1
await expectRevert(
wethPricer.setExpiryPriceInOracle(expiryTimestamp, roundId, { from: random }),
'ChainLinkPricer: unauthorized sender',
)
})


it('should set weth price when sender is bot address', async () => {
const expiryTimestamp = (t0 + t1) / 2 // between t0 and t1
if ((await time.latest()) < expiryTimestamp + lockingPeriod) {
Expand Down
25 changes: 21 additions & 4 deletions test/unit-tests/chainlinkPricer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ contract('ChainlinkPricer', ([owner, bot, random]) => {
await wethAggregator.setRoundTimestamp(4, t4)
})

it('should set the correct price to the oracle', async () => {
it('bot should set the correct price to the oracle', async () => {
const expiryTimestamp = (t0 + t1) / 2 // between t0 and t1
const roundId = 1

Expand All @@ -128,15 +128,32 @@ contract('ChainlinkPricer', ([owner, bot, random]) => {
assert.equal(p1.toString(), priceFromOracle[0].toString())
})

it('should revert if sender is not bot address', async () => {
it('should revert if sender is not bot address and roundId is too early', async () => {
const expiryTimestamp = (t1 + t2) / 2 // between t0 and t1
const roundId = 1
await expectRevert(
pricer.setExpiryPriceInOracle(expiryTimestamp, roundId, { from: random }),
'ChainLinkPricer: unauthorized sender',
pricer.setExpiryPriceInOracle(expiryTimestamp, roundId, {from: random}),
'ChainLinkPricer: invalid roundId',
)
})

it('should revert if sender is not bot address and roundId is too late', async () => {
const expiryTimestamp = (t1 + t2) / 2 // between t0 and t1
const roundId = 3
await expectRevert(
pricer.setExpiryPriceInOracle(expiryTimestamp, roundId, {from: random}),
'ChainLinkPricer: invalid roundId',
)
})

it('anyone should be able to set prices', async () => {
const expiryTimestamp = (t1 + t2) / 2 // between t0 and t1
const roundId = 2
await pricer.setExpiryPriceInOracle(expiryTimestamp, roundId, {from: random})
const priceFromOracle = await oracle.getExpiryPrice(weth.address, expiryTimestamp)
assert.equal(p2.toString(), priceFromOracle[0].toString())
})

it('should revert if round ID is incorrect: price[roundId].timestamp < expiry', async () => {
const expiryTimestamp = (t1 + t2) / 2 // between t0 and t1
const roundId = 1
Expand Down