Skip to content

Commit e4a64cf

Browse files
authored
Merge pull request #26 from perpetual-protocol/hotfix/fix-update-rule
hotfix/fix update rule
2 parents a62f397 + 66494f7 commit e4a64cf

File tree

5 files changed

+21
-46
lines changed

5 files changed

+21
-46
lines changed

contracts/ChainlinkPriceFeed.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ contract ChainlinkPriceFeed is IPriceFeed, BlockContext, CachedTwap {
2222
/// @dev anyone can help update it.
2323
function update() external {
2424
(, uint256 latestPrice, uint256 latestTimestamp) = _getLatestRoundData();
25-
2625
_update(latestPrice, latestTimestamp);
2726
}
2827

contracts/twap/CumulativeTwap.sol

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,8 @@ contract CumulativeTwap is BlockContext {
4040
}
4141

4242
// CT_IT: invalid timestamp
43-
// add `==` in the require statement in case that two or more price with the same timestamp
44-
// this might happen on Optimism bcs their timestamp is not up-to-date
4543
Observation memory lastObservation = observations[currentObservationIndex];
46-
require(lastUpdatedTimestamp >= lastObservation.timestamp, "CT_IT");
44+
require(lastUpdatedTimestamp > lastObservation.timestamp, "CT_IT");
4745

4846
// overflow of currentObservationIndex is desired since currentObservationIndex is uint8 (0 - 255),
4947
// so 255 + 1 will be 0

test/BandPriceFeed.spec.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,7 @@ describe("BandPriceFeed/CumulativeTwap Spec", () => {
8888
expect(observation.priceCumulative).to.eq(parseEther("6000"))
8989
})
9090

91-
// skip this test for being compatible with Chainlink aggregator
92-
// Chainlink aggregator might have the same timestamp in different round
93-
it.skip("force error, the second update is the same timestamp", async () => {
91+
it("force error, the second update is the same timestamp", async () => {
9492
await updatePrice(400, false)
9593

9694
roundData.push([parseEther("440"), currentTime, currentTime])

test/CachedTwap.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ describe("Cached Twap Spec", () => {
8686
await updatePrice(400)
8787
await updatePrice(405)
8888
await updatePrice(410)
89+
90+
await bandReference.setReferenceData({
91+
rate: parseEther("415"),
92+
lastUpdatedBase: currentTime,
93+
lastUpdatedQuote: currentTime,
94+
})
8995
})
9096

9197
describe("cacheTwap should be exactly the same getPrice()", () => {
@@ -98,6 +104,8 @@ describe("Cached Twap Spec", () => {
98104
it("if cached twap found, twap price should equal cached twap", async () => {
99105
const price = await testPriceFeed.callStatic.getPrice(45)
100106
expect(price.twap).to.eq(price.cachedTwap)
107+
// `getPrice` here is no a view function, it mocked function in TestPriceFeed
108+
// and it will update the cache if necessary
101109
expect(price.twap).to.eq(await bandPriceFeed.getPrice(45))
102110
})
103111

@@ -113,6 +121,8 @@ describe("Cached Twap Spec", () => {
113121

114122
const price2 = await testPriceFeed.callStatic.getPrice(45)
115123
expect(price2.twap).to.eq(price2.cachedTwap)
124+
// `getPrice` here is no a view function, it mocked function in TestPriceFeed
125+
// and it will update the cache if necessary
116126
expect(price2.twap).to.eq(await bandPriceFeed.getPrice(45))
117127

118128
expect(price1.cachedTwap).to.not.eq(price2.cachedTwap)

test/ChainlinkPriceFeed.spec.ts

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -48,50 +48,20 @@ describe("ChainlinkPriceFeed Spec", () => {
4848
})
4949

5050
describe("edge cases, have the same timestamp for several rounds", () => {
51-
beforeEach(async () => {
52-
// `base` = now - _interval
53-
// aggregator's answer
54-
// timestamp(base + 0) : 400
55-
// timestamp(base + 15) : 405
56-
// timestamp(base + 30) : 410
57-
// now = base + 45
58-
//
59-
// --+------+-----+-----+-----+-----+-----+
60-
// base now
61-
const latestTimestamp = (await waffle.provider.getBlock("latest")).timestamp
62-
currentTime = latestTimestamp
51+
it("force error, can't update if timestamp is the same", async () => {
52+
currentTime = (await waffle.provider.getBlock("latest")).timestamp
6353
roundData = [
6454
// [roundId, answer, startedAt, updatedAt, answeredInRound]
6555
]
56+
// set first round data
57+
roundData.push([0, parseEther("399"), currentTime, currentTime, 0])
58+
aggregator.latestRoundData.returns(() => {
59+
return roundData[roundData.length - 1]
60+
})
6661

62+
// update without forward timestamp
6763
await updatePrice(0, 400, false)
68-
await updatePrice(1, 405, false)
69-
await updatePrice(2, 410, false)
70-
// // have the same timestamp for rounds
71-
// roundData.push([0, parseEther("400"), currentTime, currentTime, 0])
72-
// roundData.push([1, parseEther("405"), currentTime, currentTime, 1])
73-
// roundData.push([2, parseEther("410"), currentTime, currentTime, 2])
74-
75-
// aggregator.latestRoundData.returns(() => {
76-
// return roundData[roundData.length - 1]
77-
// })
78-
// aggregator.getRoundData.returns(round => {
79-
// return roundData[round]
80-
// })
81-
82-
currentTime += 15
83-
await ethers.provider.send("evm_setNextBlockTimestamp", [currentTime])
84-
await ethers.provider.send("evm_mine", [])
85-
})
86-
87-
it("get the latest price", async () => {
88-
const price = await chainlinkPriceFeed.getPrice(45)
89-
expect(price).to.eq(parseEther("410"))
90-
})
91-
92-
it("asking interval more than aggregator has", async () => {
93-
const price = await chainlinkPriceFeed.getPrice(46)
94-
expect(price).to.eq(parseEther("410"))
64+
await expect(chainlinkPriceFeed.update()).to.be.revertedWith("CT_IT")
9565
})
9666
})
9767
})

0 commit comments

Comments
 (0)