Skip to content

Commit

Permalink
feat: marketCompressorDraft
Browse files Browse the repository at this point in the history
  • Loading branch information
0xmikko committed Aug 22, 2024
1 parent a192f89 commit c078f36
Show file tree
Hide file tree
Showing 13 changed files with 990 additions and 469 deletions.
385 changes: 385 additions & 0 deletions broadcast/Deploy.sol/1/run-1724332446.json

Large diffs are not rendered by default.

385 changes: 385 additions & 0 deletions broadcast/Deploy.sol/1/run-latest.json

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions contracts/compressors/MarketCompressorV3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Holdings, 2024
pragma solidity ^0.8.17;

import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol";
import {IPoolQuotaKeeperV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolQuotaKeeperV3.sol";

import {PoolCompressorV3} from "./PoolCompressor.sol";
import {PriceFeedCompressor} from "./PriceFeedCompressor.sol";

// // EXCEPTIONS
// import "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol";

import {MarketData} from "../types/MarketData.sol";
import {PoolState} from "../types/PoolState.sol";

import "forge-std/console.sol";

// struct PriceOnDemand {
// address priceFeed;
// bytes callData;
// }

/// @title Data compressor 3.0.
/// @notice Collects data from various contracts for use in the dApp
/// Do not use for data from data compressor for state-changing functions
contract MarketCompressorV3 {
// Contract version
uint256 public constant version = 3_10;

PriceFeedCompressor priceOracleCompressor;
PoolCompressorV3 poolCompressor;

error CreditManagerIsNotV3Exception();

constructor(address priceOracleCompressorAddress) {
poolCompressor = new PoolCompressorV3();
priceOracleCompressor = PriceFeedCompressor(priceOracleCompressorAddress);
}

function getMarketData(address pool) public view returns (MarketData memory result) {
result.pool = poolCompressor.getPoolState(pool);
result.poolQuotaKeeper = poolCompressor.getPoolQuotaKeeperState(result.pool.poolQuotaKeeper);
result.rateKeeper = poolCompressor.getRateKeeperState(result.poolQuotaKeeper.rateKeeper);
result.interestRateModel = poolCompressor.getInterestRateModelState(result.pool.interestRateModel);

address priceOracle = _getPriceOracle(result.pool);
address[] memory tokens = IPoolQuotaKeeperV3(result.pool.poolQuotaKeeper).quotedTokens();

result.tokens = new address[](tokens.length + 1);
result.tokens[0] = result.pool.underlying;

for (uint256 i = 0; i < tokens.length; i++) {
result.tokens[i + 1] = tokens[i];
}
// How to query if no credit mangers are deployed?
result.priceOracleData = priceOracleCompressor.getPriceOracleState(priceOracle, result.tokens);
}

function _getPriceOracle(PoolState memory ps) internal view returns (address) {
if (ps.creditManagerDebtParams.length == 0) {
return address(0);
}

return ICreditManagerV3(ps.creditManagerDebtParams[0].creditManager).priceOracle();
}
}
78 changes: 76 additions & 2 deletions contracts/compressors/PoolCompressor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@ pragma experimental ABIEncoderV2;
import {PoolV3} from "@gearbox-protocol/core-v3/contracts/pool/PoolV3.sol";
import {IPoolQuotaKeeperV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolQuotaKeeperV3.sol";
import {IGaugeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IGaugeV3.sol";
import {IVersion} from "../interfaces/IVersion.sol";
import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol";
import {ICreditConfiguratorV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditConfiguratorV3.sol";
import {ICreditFacadeV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol";

import {PoolState, CreditManagerDebtParams} from "../types/PoolState.sol";
import {PoolQuotaKeeperState, QuotaTokenParams} from "../types/PoolQuotaKeeperState.sol";
import {RateKeeperState, Rate} from "../types/RateKeeperState.sol";
import {InterestRateModelState} from "../types/InterestRateModelState.sol";
import {CreditManagerState} from "../types/CreditManagerState.sol";

import {PERCENTAGE_FACTOR, RAY} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol";
import {IRateKeeper} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IRateKeeper.sol";

import {RateKeeperType} from "../types/Enums.sol";

// Serializers
import {GaugeSerializer} from "../serializers/pool/GaugeSerializer.sol";
import {LinearInterestModelSerializer} from "../serializers/pool/LinearInterestModelSerializer.sol";

/// @title Pool compressor
/// @notice Collects data from pool related contracts
Expand All @@ -26,9 +35,11 @@ contract PoolCompressorV3 {
uint256 public constant version = 3_10;

address public immutable gaugeSerializer;
address public immutable linearInterestModelSerializer;

constructor() {
gaugeSerializer = address(new GaugeSerializer());
linearInterestModelSerializer = address(new LinearInterestModelSerializer());
}

function getPoolState(address pool) public view returns (PoolState memory result) {
Expand Down Expand Up @@ -73,8 +84,8 @@ contract PoolCompressorV3 {
result.baseInterestIndex = _pool.baseInterestIndex();
// uint256 baseInterestRate;
result.baseInterestRate = _pool.baseInterestRate();
// uint256 dieselRate_RAY;
result.dieselRate_RAY = _pool.convertToAssets(RAY);
// uint256 dieselRate;
result.dieselRate = _pool.convertToAssets(RAY);
// uint256 totalBorrowed;
result.totalBorrowed = _pool.totalBorrowed();
// uint256 totalDebtLimit;
Expand Down Expand Up @@ -173,4 +184,67 @@ contract PoolCompressorV3 {
result.rates[i].rate = rawRates[i];
}
}

function getInterestRateModelState(address irm) external view returns (InterestRateModelState memory result) {
InterestRateModelState memory irmState;
irmState.addr = irm;
irmState.version = IVersion(irm).version();

try IVersion(irm).contractType() returns (bytes32 contractType) {
irmState.contractType = contractType;
} catch {
irmState.contractType = "IRM_LINEAR";
}
// add serialiser
irmState.serializedParams = LinearInterestModelSerializer(linearInterestModelSerializer).serialize(irm);
return irmState;
}

/// @dev Returns CreditManagerData for a particular _cm
/// @param _cm CreditManager address
function getCreditManagerData(address _cm) public view returns (CreditManagerState memory result) {
ICreditManagerV3 creditManager = ICreditManagerV3(_cm);
ICreditConfiguratorV3 creditConfigurator = ICreditConfiguratorV3(creditManager.creditConfigurator());
ICreditFacadeV3 creditFacade = ICreditFacadeV3(creditManager.creditFacade());

result.addr = _cm;
result.name = ICreditManagerV3(_cm).name();
result.cfVersion = IVersion(address(creditFacade)).version();

result.creditFacade = address(creditFacade);
result.creditConfigurator = address(creditConfigurator);

result.underlying = creditManager.underlying();

(result.minDebt, result.maxDebt) = creditFacade.debtLimits();

{
uint256 collateralTokenCount = creditManager.collateralTokensCount();

result.collateralTokens = new address[](collateralTokenCount);
result.liquidationThresholds = new uint256[](collateralTokenCount);

unchecked {
for (uint256 i = 0; i < collateralTokenCount; ++i) {
(result.collateralTokens[i], result.liquidationThresholds[i]) =
creditManager.collateralTokenByMask(1 << i);
}
}
}

result.degenNFT = creditFacade.degenNFT();

// (, result.isIncreaseDebtForbidden,,) = creditFacade.params(); // V2 only: true if increasing debt is forbidden
result.forbiddenTokenMask = creditFacade.forbiddenTokenMask(); // V2 only: mask which forbids some particular tokens
result.maxEnabledTokensLength = creditManager.maxEnabledTokens(); // V2 only: a limit on enabled tokens imposed for security
{
(
result.feeInterest,
result.feeLiquidation,
result.liquidationDiscount,
result.feeLiquidationExpired,
result.liquidationDiscountExpired
) = creditManager.fees();
}
}
}
17 changes: 15 additions & 2 deletions contracts/compressors/PriceFeedCompressor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {IPriceOracleV3, PriceFeedParams} from "@gearbox-protocol/core-v3/contrac
import {IPriceFeed, IUpdatablePriceFeed} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPriceFeed.sol";
import {IPriceFeedCompressor} from "../interfaces/IPriceFeedCompressor.sol";
import {PriceFeedType} from "@gearbox-protocol/sdk-gov/contracts/PriceFeedType.sol";
import {IVersion} from "../interfaces/IVersion.sol";

import {IStateSerializerLegacy} from "../interfaces/IStateSerializerLegacy.sol";
import {IStateSerializer} from "../interfaces/IStateSerializer.sol";
Expand All @@ -17,7 +18,7 @@ import {BPTWeightedPriceFeedSerializer} from "../serializers/oracles/BPTWeighted
import {LPPriceFeedSerializer} from "../serializers/oracles/LPPriceFeedSerializer.sol";
import {PythPriceFeedSerializer} from "../serializers/oracles/PythPriceFeedSerializer.sol";
import {RedstonePriceFeedSerializer} from "../serializers/oracles/RedstonePriceFeedSerializer.sol";
import {PriceFeedAnswer, PriceFeedMapEntry, PriceFeedTreeNode} from "../types/PriceOracleState.sol";
import {PriceFeedAnswer, PriceFeedMapEntry, PriceFeedTreeNode, PriceOracleState} from "../types/PriceOracleState.sol";

interface ImplementsPriceFeedType {
/// @dev Annotates `priceFeedType` as `uint8` instead of `PriceFeedType` enum to support future types
Expand Down Expand Up @@ -78,7 +79,7 @@ contract PriceFeedCompressor is IPriceFeedCompressor {
/// from `priceFeedMap` and their underlying feeds, in case former are nested, which can help to determine
/// what underlying feeds should be updated to query the nested one.
function getPriceFeeds(address priceOracle)
external
public
view
override
returns (PriceFeedMapEntry[] memory priceFeedMap, PriceFeedTreeNode[] memory priceFeedTree)
Expand All @@ -87,6 +88,18 @@ contract PriceFeedCompressor is IPriceFeedCompressor {
return getPriceFeeds(priceOracle, tokens);
}

function getPriceOracleState(address priceOracle, address[] memory tokens)
external
view
returns (PriceOracleState memory result)
{
result.addr = priceOracle;
result.version = IPriceOracleV3(priceOracle).version();
result.contractType = IVersion(priceOracle).contractType();

(result.priceFeedMapping, result.priceFeedStructure) = getPriceFeeds(priceOracle, tokens);
}

/// @dev Same as the above but takes the list of tokens as argument as legacy oracle doesn't implement `getTokens`
function getPriceFeeds(address priceOracle, address[] memory tokens)
public
Expand Down
13 changes: 13 additions & 0 deletions contracts/interfaces/IVersion.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

/// @title Version interface
/// @notice Defines contract version
interface IVersion {
/// @notice Contract version
function version() external view returns (uint256);

function contractType() external view returns (bytes32);
}
Loading

0 comments on commit c078f36

Please sign in to comment.