generated from PaulRBerg/hardhat-template
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
188 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
pragma solidity 0.8.13; | ||
|
||
interface IPendlePtOracle { | ||
function getPtToAssetRate(address market, uint32 duration) external view returns (uint256); | ||
} |
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,52 @@ | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
pragma solidity 0.8.13; | ||
|
||
import { IPendlePtOracle } from "../interfaces/IPendlePtOracle.sol"; | ||
import { LiquidStakedTokenOracle } from "./common/LiquidStakedTokenOracle.sol"; | ||
import { ensureNonzeroAddress, ensureNonzeroValue } from "@venusprotocol/solidity-utilities/contracts/validators.sol"; | ||
|
||
/** | ||
* @title PendleOracle | ||
* @author Venus | ||
* @notice This oracle fetches the price of an pendle token | ||
*/ | ||
contract PendleOracle is LiquidStakedTokenOracle { | ||
/// @notice Address of the PT oracle | ||
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable | ||
IPendlePtOracle public immutable PT_ORACLE; | ||
|
||
/// @notice Address of the market | ||
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable | ||
address public immutable MARKET; | ||
|
||
/// @notice Twap duration for the oracle | ||
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable | ||
uint32 public immutable TWAP_DURATION; | ||
|
||
/// @notice Constructor for the implementation contract. | ||
/// @custom:oz-upgrades-unsafe-allow constructor | ||
constructor( | ||
address market, | ||
address ptOracle, | ||
address ptToken, | ||
address underlyingToken, | ||
address resilientOracle, | ||
uint32 twapDuration | ||
) LiquidStakedTokenOracle(ptToken, underlyingToken, resilientOracle) { | ||
ensureNonzeroAddress(market); | ||
ensureNonzeroAddress(ptOracle); | ||
ensureNonzeroValue(twapDuration); | ||
|
||
MARKET = market; | ||
PT_ORACLE = IPendlePtOracle(ptOracle); | ||
TWAP_DURATION = twapDuration; | ||
} | ||
|
||
/** | ||
* @notice Fetches the amount of FRAX for 1 sFrax | ||
* @return amount The amount of FRAX for sFrax | ||
*/ | ||
function getUnderlyingAmount() internal view override returns (uint256) { | ||
return PT_ORACLE.getPtToAssetRate(MARKET, TWAP_DURATION); | ||
} | ||
} |
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,129 @@ | ||
import { smock } from "@defi-wonderland/smock"; | ||
import chai from "chai"; | ||
import { parseUnits } from "ethers/lib/utils"; | ||
import { ethers } from "hardhat"; | ||
|
||
import { ADDRESSES } from "../helpers/deploymentConfig"; | ||
import { BEP20Harness, IPendlePtOracle, ResilientOracleInterface } from "../typechain-types"; | ||
import { addr0000 } from "./utils/data"; | ||
|
||
const { expect } = chai; | ||
chai.use(smock.matchers); | ||
|
||
const { PTweETH, PTweETHMarket, PTOracle, eETH } = ADDRESSES.ethereum; | ||
const eETH_PRICE = parseUnits("3400", 18); | ||
const PRICE_DENOMINATOR = parseUnits("1", 18); | ||
const EETH_AMOUNT_FOR_ONE_WEETH = parseUnits("0.923601422168630818", 18); | ||
const DURATION = 3600; // 1 hour | ||
|
||
describe("WstETHOracle unit tests", () => { | ||
let ptWeETHMock; | ||
let resilientOracleMock; | ||
let pendleOracle; | ||
let pendleOracleFactory; | ||
let ptOracleMock; | ||
before(async () => { | ||
// To initialize the provider we need to hit the node with any request | ||
await ethers.getSigners(); | ||
resilientOracleMock = await smock.fake<ResilientOracleInterface>("ResilientOracleInterface"); | ||
resilientOracleMock.getPrice.returns(eETH_PRICE); | ||
|
||
ptWeETHMock = await smock.fake<BEP20Harness>("BEP20Harness", { address: PTweETH }); | ||
ptWeETHMock.decimals.returns(18); | ||
|
||
ptOracleMock = await smock.fake<IPendlePtOracle>("IPendlePtOracle", { address: PTOracle }); | ||
ptOracleMock.getPtToAssetRate.returns(EETH_AMOUNT_FOR_ONE_WEETH); | ||
|
||
pendleOracleFactory = await ethers.getContractFactory("PendleOracle"); | ||
}); | ||
|
||
describe("deployment", () => { | ||
it("revert if market address is 0", async () => { | ||
await expect( | ||
pendleOracleFactory.deploy( | ||
addr0000, | ||
ptOracleMock.address, | ||
ptWeETHMock.address, | ||
eETH, | ||
resilientOracleMock.address, | ||
DURATION, | ||
), | ||
).to.be.reverted; | ||
}); | ||
it("revert if ptOracle address is 0", async () => { | ||
await expect( | ||
pendleOracleFactory.deploy( | ||
PTweETHMarket, | ||
addr0000, | ||
ptWeETHMock.address, | ||
eETH, | ||
resilientOracleMock.address, | ||
DURATION, | ||
), | ||
).to.be.reverted; | ||
}); | ||
it("revert if ptWeETH address is 0", async () => { | ||
await expect( | ||
pendleOracleFactory.deploy( | ||
PTweETHMarket, | ||
ptOracleMock.address, | ||
addr0000, | ||
eETH, | ||
resilientOracleMock.address, | ||
DURATION, | ||
), | ||
).to.be.reverted; | ||
}); | ||
it("revert if eETH address is 0", async () => { | ||
await expect( | ||
pendleOracleFactory.deploy( | ||
PTweETHMarket, | ||
ptOracleMock.address, | ||
ptWeETHMock.address, | ||
addr0000, | ||
resilientOracleMock.address, | ||
DURATION, | ||
), | ||
).to.be.reverted; | ||
}); | ||
it("revert if ResilientOracle address is 0", async () => { | ||
await expect( | ||
pendleOracleFactory.deploy(PTweETHMarket, ptOracleMock.address, ptWeETHMock.address, eETH, addr0000, DURATION), | ||
).to.be.reverted; | ||
}); | ||
it("revert if TWAP duration is 0", async () => { | ||
await expect( | ||
pendleOracleFactory.deploy( | ||
PTweETHMarket, | ||
ptOracleMock.address, | ||
ptWeETHMock.address, | ||
eETH, | ||
resilientOracleMock.address, | ||
0, | ||
), | ||
).to.be.reverted; | ||
}); | ||
|
||
it("should deploy contract", async () => { | ||
pendleOracle = await pendleOracleFactory.deploy( | ||
PTweETHMarket, | ||
ptOracleMock.address, | ||
ptWeETHMock.address, | ||
eETH, | ||
resilientOracleMock.address, | ||
DURATION, | ||
); | ||
}); | ||
}); | ||
|
||
describe("getPrice", () => { | ||
it("revert if wstETH address is wrong", async () => { | ||
await expect(pendleOracle.getPrice(addr0000)).to.be.revertedWith("wrong token address"); | ||
}); | ||
|
||
// it("should get correct price", async () => { | ||
// const expectedPrice = STETH_USD_PRICE.mul(STETH_AMOUNT_FOR_ONE_WSTETH).div(PRICE_DENOMINATOR); | ||
// expect(await wstETHOracle.getPrice(WSTETH)).to.equal(expectedPrice); | ||
// }); | ||
}); | ||
}); |