Skip to content

Commit

Permalink
feat: add btc test oval
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Maldonado <[email protected]>
  • Loading branch information
md0x committed Jan 2, 2024
1 parent 1970b39 commit 4a39601
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 11 deletions.
15 changes: 9 additions & 6 deletions scripts/src/gasProfiling/aaveV3Borrow.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { Signer, providers, utils } from "ethers";
import {
TenderlyForkParams,
TenderlyForkResult,
createTenderlyFork,
deleteTenderlyFork,
findForkByDescription,
getTenderlyFork,
setForkSimulationDescription,
shareTenderlyFork
shareTenderlyFork,
} from "../TenderlyHelpers/TenderlyFork";
import {
TenderlySimulationResult,
simulateTenderlyTx,
} from "../TenderlyHelpers/TenderlySimulation";
// Have to import TestedOval manually since it is not unique.
import { TestedOval__factory } from "../../contract-types/factories/AaveV3.Liquidation.sol/TestedOval__factory";
import { TestedOvalCustom__factory } from "../../contract-types";

// Common constants.
const blockNumber = 18427678;
Expand Down Expand Up @@ -80,6 +82,8 @@ const deployOvalForAsset = async (asset: string, fork: TenderlyForkResult, owner
const aaveOracleInterface = new utils.Interface(aaveOracleAbi);
// Get asset old oracle address

const isWBTC = asset === "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599";

const aaveOldOracleCallData = aaveOracleInterface.encodeFunctionData(
"getSourceOfAsset",
[asset]
Expand All @@ -91,7 +95,7 @@ const deployOvalForAsset = async (asset: string, fork: TenderlyForkResult, owner
});

// Deploy Oval.
const testedOvalFactory = new TestedOval__factory(ownerSigner);
const testedOvalFactory = isWBTC ? new TestedOvalCustom__factory(ownerSigner) : new TestedOval__factory(ownerSigner);
const testedOval = await testedOvalFactory.deploy(
'0x' + aaveOldOracle.substring(aaveOldOracle.length - 40),
8,
Expand Down Expand Up @@ -157,10 +161,9 @@ const OvalAaveV3Borrow = async (): Promise<number> => {
const ownerSigner = provider.getSigner(ownerAddress);
const forkTimestamp = (await provider.getBlock(blockNumber)).timestamp;

// Deploy Oval for USDT
let simulation = await deployOvalForAsset("0xdac17f958d2ee523a2206206994597c13d831ec7", fork, ownerSigner, unlockerAddress, forkTimestamp, provider);
// Deploy Oval for USDC
simulation = await deployOvalForAsset("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", fork, ownerSigner, unlockerAddress, forkTimestamp, provider);
let simulation = await deployOvalForAsset("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", fork, ownerSigner, unlockerAddress, forkTimestamp, provider);
simulation = await deployOvalForAsset("0xdac17f958d2ee523a2206206994597c13d831ec7", fork, ownerSigner, unlockerAddress, forkTimestamp, provider);
simulation = await deployOvalForAsset("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", fork, ownerSigner, unlockerAddress, forkTimestamp, provider);

// Open user position.
simulation = await borrowCall(forkTimestamp, fork.id, simulation.id);
Expand Down
10 changes: 5 additions & 5 deletions scripts/src/gasProfiling/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { aaveV3Borrow } from "./aaveV3Borrow";
const main = async () => {
console.log("Running gas profiling ...\n");

await compoundBorrow();
await compoundLiquidation();
await aaveV2Liquidation();
await aaveV3Liquidation();
await aaveV2Borrow();
// await compoundBorrow();
// await compoundLiquidation();
// await aaveV2Liquidation();
// await aaveV3Liquidation();
// await aaveV2Borrow();
await aaveV3Borrow();
};

Expand Down
121 changes: 121 additions & 0 deletions src/adapters/source-adapters/ChainlinkSourceAdapterTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.17;

import {DecimalLib} from "../lib/DecimalLib.sol";
import {IAggregatorV3Source} from "../../interfaces/chainlink/IAggregatorV3Source.sol";
import {DiamondRootOval} from "../../DiamondRootOval.sol";

/**
* @title ChainlinkSourceAdapter contract to read data from Chainlink aggregator and standardize it for Oval.
* @dev Can fetch information from Chainlink source at a desired timestamp for historic lookups.
*/

abstract contract ChainlinkSourceAdapterT is DiamondRootOval {
IAggregatorV3Source public immutable CHAINLINK_SOURCE;
uint8 private immutable SOURCE_DECIMALS;

// As per Chainlink documentation https://docs.chain.link/data-feeds/historical-data#roundid-in-proxy
// roundId on the aggregator proxy is comprised of phaseId (higher 16 bits) and roundId from phase aggregator
// (lower 64 bits). PHASE_MASK is used to calculate first roundId of current phase aggregator.
uint80 private constant PHASE_MASK = uint80(0xFFFF) << 64;

event SourceSet(address indexed sourceOracle, uint8 indexed sourceDecimals);

constructor(IAggregatorV3Source source) {
CHAINLINK_SOURCE = source;
SOURCE_DECIMALS = source.DECIMALS();

emit SourceSet(address(source), SOURCE_DECIMALS);
}

/**
* @notice Tries getting latest data as of requested timestamp. If this is not possible, returns the earliest data
* available past the requested timestamp within provided traversal limitations.
* @param timestamp The timestamp to try getting latest data at.
* @param maxTraversal The maximum number of rounds to traverse when looking for historical data.
* @return answer The answer as of requested timestamp, or earliest available data if not available, in 18 decimals.
* @return updatedAt The timestamp of the answer.
*/
function tryLatestDataAt(
uint256 timestamp,
uint256 maxTraversal
) public view virtual override returns (int256, uint256) {
(int256 answer, uint256 updatedAt) = _tryLatestRoundDataAt(
timestamp,
maxTraversal
);
return (
DecimalLib.convertDecimals(answer, SOURCE_DECIMALS, 18),
updatedAt
);
}

/**
* @notice Initiate a snapshot of the source data. This is a no-op for Chainlink.
*/
function snapshotData() public virtual override {}

/**
* @notice Returns the latest data from the source.
* @return answer The latest answer in 18 decimals.
* @return updatedAt The timestamp of the answer.
*/
function getLatestSourceData()
public
view
virtual
override
returns (int256, uint256)
{
(, int256 sourceAnswer, , uint256 updatedAt, ) = CHAINLINK_SOURCE
.latestRoundData();
return (
DecimalLib.convertDecimals(sourceAnswer, SOURCE_DECIMALS, 18),
updatedAt
);
}

// Tries getting latest data as of requested timestamp. If this is not possible, returns the earliest data available
// past the requested timestamp considering the maxTraversal limitations.
function _tryLatestRoundDataAt(
uint256 timestamp,
uint256 maxTraversal
) internal view returns (int256, uint256) {
return (CHAINLINK_SOURCE.latestAnswer(), 0);
}

// Tries finding latest historical data (ignoring current roundId) not newer than requested timestamp. Might return
// newer data than requested if exceeds traversal or hold uninitialized data that should be handled by the caller.
function _searchRoundDataAt(
uint256 timestamp,
uint80 targetRoundId,
uint256 maxTraversal
) internal view returns (int256, uint256) {
uint80 roundId;
int256 answer;
uint256 updatedAt;
uint80 traversedRounds = 0;
uint80 startRoundId = (targetRoundId & PHASE_MASK) + 1; // Phase aggregators are starting at round 1.

while (
traversedRounds < uint80(maxTraversal) &&
targetRoundId > startRoundId
) {
targetRoundId--; // We started from latest roundId that should be ignored.
// The aggregator proxy does not keep track when its phase aggregators got switched. This means that we can
// only traverse rounds of the current phase aggregator. When phase aggregators are switched there is
// normally an overlap period when both new and old phase aggregators receive updates. Without knowing exact
// time when the aggregator proxy switched them we might end up returning historical data from the new phase
// aggregator that was not yet available on the aggregator proxy at the requested timestamp.

(roundId, answer, , updatedAt, ) = CHAINLINK_SOURCE.getRoundData(
targetRoundId
);
if (!(roundId == targetRoundId && updatedAt > 0)) return (0, 0);
if (updatedAt <= timestamp) return (answer, updatedAt);
traversedRounds++;
}

return (answer, updatedAt); // Did not find requested round. Return earliest round or uninitialized data.
}
}
4 changes: 4 additions & 0 deletions src/interfaces/chainlink/IAggregatorV3Source.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ pragma solidity 0.8.17;
interface IAggregatorV3Source {
function decimals() external view returns (uint8);

function DECIMALS() external view returns (uint8);

function latestAnswer() external view returns (int256);

function latestRoundData()
external
view
Expand Down
9 changes: 9 additions & 0 deletions test/fork/aave/AaveV3.Liquidation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {CommonTest} from "../../Common.sol";

import {ImmutableController} from "../../../src/controllers/ImmutableController.sol";
import {ChainlinkSourceAdapter} from "../../../src/adapters/source-adapters/ChainlinkSourceAdapter.sol";
import {ChainlinkSourceAdapterT} from "../../../src/adapters/source-adapters/ChainlinkSourceAdapterTest.sol";
import {ChainlinkDestinationAdapter} from "../../../src/adapters/destination-adapters/ChainlinkDestinationAdapter.sol";
import {IAggregatorV3Source} from "../../../src/interfaces/chainlink/IAggregatorV3Source.sol";

Expand All @@ -25,6 +26,14 @@ contract TestedOval is ImmutableController, ChainlinkSourceAdapter, ChainlinkDes
{}
}

contract TestedOvalCustom is ImmutableController, ChainlinkSourceAdapterT, ChainlinkDestinationAdapter {
constructor(IAggregatorV3Source source, uint8 decimals, address[] memory unlockers)
ChainlinkSourceAdapterT(source)
ImmutableController(60, 10, unlockers)
ChainlinkDestinationAdapter(decimals)
{}
}

contract Aave3LiquidationTest is CommonTest {
uint256 amountToMint = 10000e6;
ILendingPool lendingPool = ILendingPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2);
Expand Down

0 comments on commit 4a39601

Please sign in to comment.