Skip to content

Commit

Permalink
Merge pull request #234 from VenusProtocol/feat/ven-2808
Browse files Browse the repository at this point in the history
[VEN-2808] ERC4626 Oracle
  • Loading branch information
chechu authored Dec 12, 2024
2 parents b68676a + 49beba8 commit a77b097
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 0 deletions.
7 changes: 7 additions & 0 deletions contracts/interfaces/IERC4626.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;

interface IERC4626 {
function convertToAssets(uint256 shares) external view returns (uint256);
function decimals() external view returns (uint8);
}
29 changes: 29 additions & 0 deletions contracts/oracles/ERC4626Oracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;

import { IERC4626 } from "../interfaces/IERC4626.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";

/**
* @title ERC4626Oracle
* @author Venus
* @notice This oracle fetches the price of ERC4626 tokens
*/
contract ERC4626Oracle is CorrelatedTokenOracle {
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address correlatedToken,
address underlyingToken,
address resilientOracle
) CorrelatedTokenOracle(correlatedToken, underlyingToken, resilientOracle) {}

/**
* @notice Fetches the amount of underlying token for 1 correlated token
* @return amount The amount of underlying token for correlated token
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return IERC4626(CORRELATED_TOKEN).convertToAssets(EXP_SCALE);
}
}
68 changes: 68 additions & 0 deletions test/ERC4626Oracle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
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, IERC4626, ResilientOracleInterface } from "../typechain-types";
import { addr0000 } from "./utils/data";

const { expect } = chai;
chai.use(smock.matchers);

const { FRAX, sFRAX } = ADDRESSES.ethereum;
const FRAX_USD_PRICE = parseUnits("0.9979", 18); // 0.99 USD for 1 FRAX

describe("ERC4626Oracle unit tests", () => {
let sFraxMock;
let resilientOracleMock;
let ERC4626OracleFactory;
let ERC4626Oracle;
let fraxMock;
before(async () => {
// To initialize the provider we need to hit the node with any request
await ethers.getSigners();
resilientOracleMock = await smock.fake<ResilientOracleInterface>("ResilientOracleInterface");

sFraxMock = await smock.fake<IERC4626>("IERC4626", { address: sFRAX });
sFraxMock.convertToAssets.returns(parseUnits("1.019194969966192602", 18));
sFraxMock.decimals.returns(18);

fraxMock = await smock.fake<BEP20Harness>("BEP20Harness", { address: FRAX });
fraxMock.decimals.returns(18);

ERC4626OracleFactory = await ethers.getContractFactory("ERC4626Oracle");
});

describe("deployment", () => {
it("revert if FRAX address is 0", async () => {
await expect(ERC4626OracleFactory.deploy(sFraxMock.address, addr0000, resilientOracleMock.address)).to.be
.reverted;
});
it("revert if sFRAX address is 0", async () => {
await expect(ERC4626OracleFactory.deploy(addr0000, fraxMock.address, resilientOracleMock.address)).to.be.reverted;
});
it("should deploy contract", async () => {
ERC4626Oracle = await ERC4626OracleFactory.deploy(
sFraxMock.address,
fraxMock.address,
resilientOracleMock.address,
);
});
});

describe("getPrice", () => {
it("revert if address is not valid sFrax address", async () => {
await expect(ERC4626Oracle.getPrice(addr0000)).to.be.revertedWithCustomError(
ERC4626Oracle,
"InvalidTokenAddress",
);
});

it("should get correct price of sFrax", async () => {
resilientOracleMock.getPrice.returns(FRAX_USD_PRICE);
const price = await ERC4626Oracle.getPrice(sFraxMock.address);
expect(price).to.equal(parseUnits("1.017054660529263597", 18));
});
});
});

0 comments on commit a77b097

Please sign in to comment.