creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/OracleRouter.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.12;\n\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { SignedMath } from \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\nimport { IOracleRouter } from \"./interfaces/IOracleRouter.sol\";\nimport { Errors } from \"./libraries/Errors.sol\";\nimport { IAggregatorV2V3 } from \"./interfaces/IAggregatorV2V3.sol\";\nimport { IPyth } from \"./interfaces/IPyth.sol\";\nimport { PythStructs } from \"./interfaces/PythStructs.sol\";\n\n/// @custom:security-contact security@radiant.capital\ncontract OracleRouter is Ownable, IOracleRouter {\n    //////////////// <*_*> Storage <*_*> ////////////////\n    /// @dev Mapping of asset address to its price feed data\n    mapping(address => PriceFeedData) public feeds;\n\n    /// @dev Mapping of asset address to its fallback price feed data\n    mapping(address => PriceFeedData) public fallbackFeeds;\n\n    /// @dev Mapping of oracle provider type to its address\n    mapping(IOracleRouter.OracleProviderType => OracleProvider) private oracleProviders;\n\n    /// @dev The base currency unit\n    uint256 public constant BASE_CURRENCY_UNIT = 1e18;\n\n    ////////////////// =^..^= Events =^..^= //////////////////\n    event FeedUpdated(address asset, address feedAddress, bytes32 feedId, uint256 heartbeat);\n    event FallbackFeedUpdated(address asset, address feedAddress, bytes32 feedId, uint256 heartbeat);\n    event PricesUpdated();\n\n    //////////////// <*_*> Structs <*_*> ////////////////\n    struct PriceFeedData {\n        /// required by Chainlink\n        address feedAddress;\n        /// required by Pyth and API3\n        bytes32 feedId;\n        uint256 heartbeat;\n        OracleProviderType oracleProviderType;\n        bool isSet;\n    }\n\n    struct OracleProvider {\n        address oracleProviderAddress;\n        function(PriceFeedData memory) view returns (bool, uint256) getPrice;\n    }\n\n    constructor(address _pyth) Ownable() {\n        oracleProviders[OracleProviderType.Chainlink] = OracleProvider(address(0x0), _getChainlinkPrice);\n        oracleProviders[OracleProviderType.Pyth] = OracleProvider(_pyth, _getPythPrice);\n    }\n\n    ////////////////// ô¿ô External Functions ô¿ô //////////////////\n\n    /// @notice Set the source of an asset\n    /// @param _asset The address of the asset\n    /// @param _feedAddress The address of the feed\n    /// @param _feedId The id of the feed\n    /// @param _heartbeat The heartbeat of the feed\n    /// @param _oracleType The type of the oracle, CL is 0, Pyth is 1 and so on\n    /// @param isFallback True if the feed is a fallback\n    function setAssetSource(\n        address _asset,\n        address _feedAddress,\n        bytes32 _feedId,\n        uint256 _heartbeat,\n        IOracleRouter.OracleProviderType _oracleType,\n        bool isFallback\n    ) external override onlyOwner {\n        _setAssetSource(_asset, _feedAddress, _feedId, _heartbeat, _oracleType, isFallback);\n    }\n\n    /**\n     * @notice Updates multiple price feeds on Pyth oracle\n     * @param priceUpdateData received from Pyth network and used to update the oracle\n     */\n    function updateUnderlyingPrices(bytes[] calldata priceUpdateData) external payable override {\n        IPyth pyth = IPyth(oracleProviders[OracleProviderType.Pyth].oracleProviderAddress);\n        uint256 fee = pyth.getUpdateFee(priceUpdateData);\n        pyth.updatePriceFeeds{ value: fee }(priceUpdateData);\n        // Send all remaining eth back to the sender\n        msg.sender.call{ value: msg.value - fee }(\"\");\n        emit PricesUpdated();\n    }\n\n    /// @notice Get the prices of multiple assets\n    /// @param assets The addresses of the assets\n    /// @return uint256[] The prices of the assets\n    function getAssetsPrices(address[] calldata assets) external view override returns (uint256[] memory) {\n        uint256 length = assets.length;\n        uint256[] memory prices = new uint256[](length);\n        for (uint256 i = 0; i < length;) {\n            prices[i] = getAssetPrice(assets[i]);\n            unchecked {\n                ++i;\n            }\n        }\n        return prices;\n    }\n\n    /// @notice Get the source of an asset. Tries to get the primary feed, then the fallback feed address\n    /// @notice If no feed is set, returns address(0)\n    /// @param asset The address of the asset\n    /// @return address The address of the feed or in case of pyth, return feed id\n    function getSourceOfAsset(address asset) external view override returns (address, bytes32) {\n        PriceFeedData memory feed = feeds[address(asset)];\n        if (feed.isSet) {\n            return (feed.feedAddress, feed.feedId);\n            // Check fallback feed if no primary feed is set\n        } else {\n            feed = fallbackFeeds[address(asset)];\n            if (feed.isSet) {\n                return (feed.feedAddress, feed.feedId);\n            }\n        }\n        return (address(0), bytes32(0));\n    }\n\n    ////////////////// ô¿ô Public Functions ô¿ô //////////////////\n\n    /// @notice Get the price of an asset\n    /// @param asset The address of the asset\n    function getAssetPrice(address asset) public view override returns (uint256) {\n        PriceFeedData memory feed = feeds[address(asset)];\n\n        if (!feed.isSet) {\n            revert Errors.NoFeedSet();\n        }\n\n        bool success;\n        uint256 price;\n        (success, price) = oracleProviders[feed.oracleProviderType].getPrice(feed);\n        // If the price is not available, try the fallback feed\n        if (!success) {\n            feed = fallbackFeeds[address(asset)];\n            // If there is no fallback feed, revert\n            if (!feed.isSet) {\n                revert Errors.NoFallbackFeedSet();\n            }\n            (success, price) = oracleProviders[feed.oracleProviderType].getPrice(feed);\n            // If the price is not available from the fallback feed, revert\n            if (!success) {\n                revert Errors.NoPriceAvailable();\n            }\n        }\n        // Price cannot be 0\n        if (price == 0) {\n            revert Errors.NoPriceAvailable();\n        }\n        return price;\n    }\n\n    ////////////////// ô¿ô Internal Functions ô¿ô  //////////////////\n\n    /// @notice Internal function to set the source of an asset\n    /// @param _asset The address of the asset\n    /// @param _feedAddress The address of the feed\n    /// @param _feedId The id of the feed\n    /// @param _heartbeat The heartbeat of the feed\n    /// @param _oracleType The type of the oracle\n    /// @param isFallback True if the feed is a fallback\n    function _setAssetSource(\n        address _asset,\n        address _feedAddress,\n        bytes32 _feedId,\n        uint256 _heartbeat,\n        IOracleRouter.OracleProviderType _oracleType,\n        bool isFallback\n    ) internal {\n        if (_oracleType == OracleProviderType.Chainlink) {\n            if (_feedAddress == address(0)) {\n                revert Errors.InvalidFeed();\n            }\n        } else if (_oracleType == OracleProviderType.Pyth) {\n            if (_feedId == bytes32(0)) {\n                revert Errors.InvalidFeed();\n            }\n        } else {\n            revert Errors.InvalidOracleProviderType();\n        }\n\n        if (!isFallback) {\n            feeds[_asset] = PriceFeedData(_feedAddress, _feedId, _heartbeat, _oracleType, true);\n            emit FeedUpdated(_asset, _feedAddress, _feedId, _heartbeat);\n        } else {\n            fallbackFeeds[_asset] = PriceFeedData(_feedAddress, _feedId, _heartbeat, _oracleType, true);\n            emit FallbackFeedUpdated(_asset, _feedAddress, _feedId, _heartbeat);\n        }\n    }\n\n    /// @notice Get the underlying price of an asset from a Chainlink aggregator\n    /// @param feed The feed data\n    /// @return bool True if the price is available, false if not\n    /// @return uint256 The price of the asset\n    function _getChainlinkPrice(PriceFeedData memory feed) internal view returns (bool, uint256) {\n        IAggregatorV2V3 chainlinkAggregator = IAggregatorV2V3(feed.feedAddress);\n        uint256 chainlinkDecimals = chainlinkAggregator.decimals();\n        if (chainlinkDecimals > 18) {\n            revert Errors.DecimalsOutOfRange(chainlinkDecimals);\n        }\n        uint256 decimalDelta = 18 - chainlinkDecimals;\n\n        (, int256 answer,, uint256 updatedAt,) = chainlinkAggregator.latestRoundData();\n        if (answer < 0) {\n            revert Errors.NegativeChainlinkPriceValue(answer);\n        }\n\n        return\n            block.timestamp <= updatedAt + feed.heartbeat ? (true, uint256(answer) * (10 ** decimalDelta)) : (false, 0);\n    }\n\n    /// @notice return price of an asset from Pyth\n    /// @param feed contains feedId required by Pyth\n    /// @return bool True if the price is available, false if not\n    /// @return uint256 The price of the asset scaled to 1e18\n    function _getPythPrice(PriceFeedData memory feed) internal view returns (bool, uint256) {\n        IPyth pyth = IPyth(oracleProviders[OracleProviderType.Pyth].oracleProviderAddress);\n\n        PythStructs.Price memory priceData = pyth.getPriceUnsafe(feed.feedId);\n\n        if (priceData.expo > 18 || priceData.expo < -18) {\n            revert Errors.ExponentOutOfRange(priceData.expo);\n        }\n        if (priceData.price < 0) {\n            revert Errors.NegativePythPriceValue(priceData.price);\n        }\n\n        return block.timestamp <= priceData.publishTime + feed.heartbeat\n            ? (true, uint256(int256(priceData.price)) * (10 ** (18 - SignedMath.abs(priceData.expo))))\n            : (false, 0);\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"
      },
      "src/interfaces/IOracleRouter.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.12;\n\nimport \"@radiant-v2-core/interfaces/IPriceOracleGetter.sol\";\n\ninterface IOracleRouter is IPriceOracleGetter {\n    enum OracleProviderType {\n        Chainlink,\n        Pyth\n    }\n    /**\n     * @notice Get the underlying price of a kToken asset\n     * @param asset to get the underlying price of\n     * @return The underlying asset price\n     *  Zero means the price is unavailable.\n     */\n\n    /// @notice Gets a list of prices from a list of assets addresses\n    /// @param assets The list of assets addresses\n    function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory);\n\n    /// @notice Gets the address of the source for an asset address\n    /// @param asset The address of the asset\n    /// @return address The address of the source, bytes32 The id of the source\n    function getSourceOfAsset(address asset) external view returns (address, bytes32);\n\n    /// @notice Set the source of an asset\n    /// @param _asset The address of the asset\n    /// @param _feedAddress The address of the feed\n    /// @param _feedId The id of the feed\n    /// @param _heartbeat The heartbeat of the feed\n    /// @param _oracleType The type of the oracle\n    /// @param isFallback True if the feed is a fallback\n    function setAssetSource(\n        address _asset,\n        address _feedAddress,\n        bytes32 _feedId,\n        uint256 _heartbeat,\n        OracleProviderType _oracleType,\n        bool isFallback\n    ) external;\n\n    /**\n     * @notice Updates multiple price feeds on Pyth oracle\n     * @param priceUpdateData received from Pyth network and used to update the oracle\n     */\n    function updateUnderlyingPrices(bytes[] calldata priceUpdateData) external payable;\n}\n"
      },
      "src/libraries/Errors.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.12;\n\n/**\n * @title Errors library\n * @author Aave & Radiant\n * @custom:security-contact security@radiant.capital\n * @notice Defines the error messages emitted by the different contracts of the Aave & Radiant protocols\n * @dev Error messages prefix glossary:\n *  - VL = ValidationLogic\n *  - MATH = Math libraries\n *  - CT = Common errors between tokens (AToken, VariableDebtToken and StableDebtToken)\n *  - AT = AToken\n *  - SDT = StableDebtToken\n *  - VDT = VariableDebtToken\n *  - LP = LendingPool\n *  - LPAPR = LendingPoolAddressesProviderRegistry\n *  - LPC = LendingPoolConfiguration\n *  - RL = ReserveLogic\n *  - LPCM = LendingPoolCollateralManager\n *  - P = Pausable\n */\nlibrary Errors {\n    // Common errors\n    error AddressZero();\n    error AmountZero();\n    error NotAContract();\n    error NotAuthorized();\n\n    // Oracle specific errors\n    error NoFeedSet();\n    error NoFallbackFeedSet();\n    error NoPriceAvailable();\n    error PoolDisabled();\n    error PoolNotDisabled();\n    // Oracle specific errors\n    error RoundNotComplete();\n\n    // Oracles General errors\n    error InvalidOracleProviderType();\n    error InvalidFeed();\n    error NegativePythPriceValue(int64 price);\n    error NegativeChainlinkPriceValue(int256 answer);\n    error ExponentOutOfRange(int32 expo);\n\n    // Riz Registry errors\n    error PoolRegisteredAlready();\n    error NoAddressProvider();\n    error NotLPConfigurator();\n\n    // Riz LockZap errors\n    error CannotRizZap();\n    error InvalidLendingPool();\n    error InvalidRatio();\n    error InvalidLockLength();\n    error SlippageTooHigh();\n    error SpecifiedSlippageExceedLimit();\n    error InvalidZapETHSource();\n    error ReceivedETHOnAlternativeAssetZap();\n    error InsufficientETH();\n    error SwapFailed(address asset, uint256 amount);\n    error WrongRoute(address fromToken, address toToken);\n\n    // RizLendingPoolConfigurator errors\n    error DecimalsOutOfRange(uint256 decimals);\n\n    // RizLendingPoolAddressesProvider errors\n    error InvalidId(bytes32 id);\n    error MarketIdAlreadySet();\n\n    // Riz Leverager errors\n    error ReceiveNotAllowed();\n    error FallbackNotAllowed();\n\n    /// @notice Disallow a loop count of 0\n    error InvalidLoopCount();\n\n    /// @notice Thrown when deployer sets the margin too high\n    error MarginTooHigh();\n\n    // Revenue Management errors\n    error OutputTokenConfigLengthMismatch();\n    error InputTokenConfigLengthMismatch();\n    error IndexOutOfBounds();\n    error OutputTokenBalanceOutOfRange();\n    error TokenAlreadyAdded();\n    error TokenNotPresent();\n    error PercentageMismatch();\n    error InvalidSwapStrategy();\n    error DexSwapFailed();\n    error ReceivedLessThanMinOutput();\n    error InvalidInputData();\n    error AddressNotApproved();\n    error NativeAssetsNotSupported();\n    error DuplicateOutputToken();\n\n    // Bad Debt Manager errors\n    error OnlyLendingPool();\n    error UserAlreadyWithdrawn();\n    error BadDebtIsZero();\n    error UserAllowanceZero();\n    error NotEmergencyAdmin();\n    error InvalidAssetsLength();\n\n    // BaseStrategy errors\n    error NotSelf();\n\n    // TokenizedStrategy errors\n    error ReentrantCall();\n    error NotManagement();\n    error NotKeeper();\n    error NotEmergencyAuthorized();\n    error AlreadyInitialized();\n    error InvalidChainID();\n    error CannotBeSelf();\n    error ZeroShares();\n    error ZeroAssets();\n    error DepositMoreThanMax();\n    error MintMoreThanMax();\n    error WithdrawMoreThanMax();\n    error RedeemMoreThanMax();\n    error SelfMint();\n    error ExceedsMaxBPS();\n    error TooMuchLoss();\n    error NotShutdown();\n    error NotPending();\n    error ExceedsMaxFee();\n    error TooLong();\n    error InvalidTransfer();\n    error CannotMintToAddressZero();\n    error CannotBurnToAddressZero();\n    error CannotApproveAddressZero();\n    error InsufficientAllowance();\n    error PermitDeadlineExpired();\n    error InvalidSigner();\n\n    // Common aave errors\n    string public constant CALLER_NOT_POOL_ADMIN = \"33\"; // 'The caller must be the pool admin'\n    string public constant BORROW_ALLOWANCE_NOT_ENOUGH = \"59\"; // User borrows on behalf, but allowance are too small\n\n    // Contract specific errors\n    string public constant VL_INVALID_AMOUNT = \"1\"; // 'Amount must be greater than 0'\n    string public constant VL_NO_ACTIVE_RESERVE = \"2\"; // 'Action requires an active reserve'\n    string public constant VL_RESERVE_FROZEN = \"3\"; // 'Action cannot be performed because the reserve is frozen'\n    string public constant VL_CURRENT_AVAILABLE_LIQUIDITY_NOT_ENOUGH = \"4\"; // 'The current liquidity is not enough'\n    string public constant VL_NOT_ENOUGH_AVAILABLE_USER_BALANCE = \"5\"; // 'User cannot withdraw more than the available\n        // balance'\n    string public constant VL_TRANSFER_NOT_ALLOWED = \"6\"; // 'Transfer cannot be allowed.'\n    string public constant VL_BORROWING_NOT_ENABLED = \"7\"; // 'Borrowing is not enabled'\n    string public constant VL_INVALID_INTEREST_RATE_MODE_SELECTED = \"8\"; // 'Invalid interest rate mode selected'\n    string public constant VL_COLLATERAL_BALANCE_IS_0 = \"9\"; // 'The collateral balance is 0'\n    string public constant VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD = \"10\"; // 'Health factor is lesser than\n        // the liquidation threshold'\n    string public constant VL_COLLATERAL_CANNOT_COVER_NEW_BORROW = \"11\"; // 'There is not enough collateral to cover a\n        // new borrow'\n    string public constant VL_STABLE_BORROWING_NOT_ENABLED = \"12\"; // stable borrowing not enabled\n    string public constant VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY = \"13\"; // collateral is (mostly) the same currency\n        // that is being borrowed\n    string public constant VL_AMOUNT_BIGGER_THAN_MAX_LOAN_SIZE_STABLE = \"14\"; // 'The requested amount is greater than\n        // the max loan size in stable rate mode\n    string public constant VL_NO_DEBT_OF_SELECTED_TYPE = \"15\"; // 'for repayment of stable debt, the user needs to have\n        // stable debt, otherwise, he needs to have variable debt'\n    string public constant VL_NO_EXPLICIT_AMOUNT_TO_REPAY_ON_BEHALF = \"16\"; // 'To repay on behalf of an user an\n        // explicit amount to repay is needed'\n    string public constant VL_NO_STABLE_RATE_LOAN_IN_RESERVE = \"17\"; // 'User does not have a stable rate loan in\n        // progress on this reserve'\n    string public constant VL_NO_VARIABLE_RATE_LOAN_IN_RESERVE = \"18\"; // 'User does not have a variable rate loan in\n        // progress on this reserve'\n    string public constant VL_UNDERLYING_BALANCE_NOT_GREATER_THAN_0 = \"19\"; // 'The underlying balance needs to be\n        // greater than 0'\n    string public constant VL_DEPOSIT_ALREADY_IN_USE = \"20\"; // 'User deposit is already being used as collateral'\n    string public constant LP_NOT_ENOUGH_STABLE_BORROW_BALANCE = \"21\"; // 'User does not have any stable rate loan for\n        // this reserve'\n    string public constant LP_INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET = \"22\"; // 'Interest rate rebalance conditions\n        // were not met'\n    string public constant LP_LIQUIDATION_CALL_FAILED = \"23\"; // 'Liquidation call failed'\n    string public constant LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = \"24\"; // 'There is not enough liquidity available to\n        // borrow'\n    string public constant LP_REQUESTED_AMOUNT_TOO_SMALL = \"25\"; // 'The requested amount is too small for a FlashLoan.'\n    string public constant LP_INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = \"26\"; // 'The actual balance of the protocol is\n        // inconsistent'\n    string public constant LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = \"27\"; // 'The caller of the function is not the\n        // lending pool configurator'\n    string public constant LP_INCONSISTENT_FLASHLOAN_PARAMS = \"28\";\n    string public constant CT_CALLER_MUST_BE_LENDING_POOL = \"29\"; // 'The caller of this function must be a lending\n        // pool'\n    string public constant CT_CANNOT_GIVE_ALLOWANCE_TO_HIMSELF = \"30\"; // 'User cannot give allowance to himself'\n    string public constant CT_TRANSFER_AMOUNT_NOT_GT_0 = \"31\"; // 'Transferred amount needs to be greater than zero'\n    string public constant RL_RESERVE_ALREADY_INITIALIZED = \"32\"; // 'Reserve has already been initialized'\n    string public constant LPC_RESERVE_LIQUIDITY_NOT_0 = \"34\"; // 'The liquidity of the reserve needs to be 0'\n    string public constant LPC_INVALID_ATOKEN_POOL_ADDRESS = \"35\"; // 'The liquidity of the reserve needs to be 0'\n    string public constant LPC_INVALID_STABLE_DEBT_TOKEN_POOL_ADDRESS = \"36\"; // 'The liquidity of the reserve needs to\n        // be 0'\n    string public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_POOL_ADDRESS = \"37\"; // 'The liquidity of the reserve needs\n        // to be 0'\n    string public constant LPC_INVALID_STABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = \"38\"; // 'The liquidity of the reserve\n        // needs to be 0'\n    string public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = \"39\"; // 'The liquidity of the reserve\n        // needs to be 0'\n    string public constant LPC_INVALID_ADDRESSES_PROVIDER_ID = \"40\"; // 'The liquidity of the reserve needs to be 0'\n    string public constant LPC_INVALID_CONFIGURATION = \"75\"; // 'Invalid risk parameters for the reserve'\n    string public constant LPC_CALLER_NOT_EMERGENCY_ADMIN = \"76\"; // 'The caller must be the emergency admin'\n    string public constant LPAPR_PROVIDER_NOT_REGISTERED = \"41\"; // 'Provider is not registered'\n    string public constant LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = \"42\"; // 'Health factor is not below the threshold'\n    string public constant LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = \"43\"; // 'The collateral chosen cannot be liquidated'\n    string public constant LPCM_SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = \"44\"; // 'User did not borrow the specified\n        // currency'\n    string public constant LPCM_NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = \"45\"; // \"There isn't enough liquidity available to\n        // liquidate\"\n    string public constant LPCM_NO_ERRORS = \"46\"; // 'No errors'\n    string public constant LP_INVALID_FLASHLOAN_MODE = \"47\"; //Invalid flashloan mode selected\n    string public constant MATH_MULTIPLICATION_OVERFLOW = \"48\";\n    string public constant MATH_ADDITION_OVERFLOW = \"49\";\n    string public constant MATH_DIVISION_BY_ZERO = \"50\";\n    string public constant RL_LIQUIDITY_INDEX_OVERFLOW = \"51\"; //  Liquidity index overflows uint128\n    string public constant RL_VARIABLE_BORROW_INDEX_OVERFLOW = \"52\"; //  Variable borrow index overflows uint128\n    string public constant RL_LIQUIDITY_RATE_OVERFLOW = \"53\"; //  Liquidity rate overflows uint128\n    string public constant RL_VARIABLE_BORROW_RATE_OVERFLOW = \"54\"; //  Variable borrow rate overflows uint128\n    string public constant RL_STABLE_BORROW_RATE_OVERFLOW = \"55\"; //  Stable borrow rate overflows uint128\n    string public constant CT_INVALID_MINT_AMOUNT = \"56\"; //invalid amount to mint\n    string public constant LP_FAILED_REPAY_WITH_COLLATERAL = \"57\";\n    string public constant CT_INVALID_BURN_AMOUNT = \"58\"; //invalid amount to burn\n    string public constant LP_FAILED_COLLATERAL_SWAP = \"60\";\n    string public constant LP_INVALID_EQUAL_ASSETS_TO_SWAP = \"61\";\n    string public constant LP_REENTRANCY_NOT_ALLOWED = \"62\";\n    string public constant LP_CALLER_MUST_BE_AN_ATOKEN = \"63\";\n    string public constant LP_IS_PAUSED = \"64\"; // 'Pool is paused'\n    string public constant LP_NO_MORE_RESERVES_ALLOWED = \"65\";\n    string public constant LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN = \"66\";\n    string public constant RC_INVALID_LTV = \"67\";\n    string public constant RC_INVALID_LIQ_THRESHOLD = \"68\";\n    string public constant RC_INVALID_LIQ_BONUS = \"69\";\n    string public constant RC_INVALID_DECIMALS = \"70\";\n    string public constant RC_INVALID_RESERVE_FACTOR = \"71\";\n    string public constant LPAPR_INVALID_ADDRESSES_PROVIDER_ID = \"72\";\n    string public constant VL_INCONSISTENT_FLASHLOAN_PARAMS = \"73\";\n    string public constant LP_INCONSISTENT_PARAMS_LENGTH = \"74\";\n    string public constant UL_INVALID_INDEX = \"77\";\n    string public constant LP_NOT_CONTRACT = \"78\";\n    string public constant SDT_STABLE_DEBT_OVERFLOW = \"79\";\n    string public constant SDT_BURN_EXCEEDS_BALANCE = \"80\";\n\n    /**\n     * @dev Custom Radiant codes added +200 to avoid conflicts with the AaveV2/V3 ones\n     * @custom:borrow-and-supply-caps\n     */\n    string public constant INVALID_BORROW_CAP = \"201\"; // Invalid borrow cap value\n    string public constant INVALID_SUPPLY_CAP = \"202\"; // Invalid supply cap value\n    string public constant BORROW_CAP_EXCEEDED = \"203\"; // Borrow cap is exceeded\n    string public constant SUPPLY_CAP_EXCEEDED = \"204\"; // Supply cap is exceeded\n\n    enum CollateralManagerErrors {\n        NO_ERROR,\n        NO_COLLATERAL_AVAILABLE,\n        COLLATERAL_CANNOT_BE_LIQUIDATED,\n        CURRRENCY_NOT_BORROWED,\n        HEALTH_FACTOR_ABOVE_THRESHOLD,\n        NOT_ENOUGH_LIQUIDITY,\n        NO_ACTIVE_RESERVE,\n        HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD,\n        INVALID_EQUAL_ASSETS_TO_SWAP,\n        FROZEN_RESERVE\n    }\n}\n"
      },
      "src/interfaces/IAggregatorV2V3.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.12;\n\n/**\n * @title The V2 & V3 Aggregator Interface\n * @notice Solidity V0.5 does not allow interfaces to inherit from other\n * interfaces so this contract is a combination of v0.5 AggregatorInterface.sol\n * and v0.5 AggregatorV3Interface.sol.\n */\ninterface IAggregatorV2V3 {\n    //\n    // V2 Interface:\n    //\n    function latestAnswer() external view returns (int256);\n    function latestTimestamp() external view returns (uint256);\n    function latestRound() external view returns (uint256);\n    function getAnswer(uint256 roundId) external view returns (int256);\n    function getTimestamp(uint256 roundId) external view returns (uint256);\n\n    event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);\n    event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);\n\n    //\n    // V3 Interface:\n    //\n    function decimals() external view returns (uint8);\n    function description() external view returns (string memory);\n    function version() external view returns (uint256);\n\n    // getRoundData and latestRoundData should both raise \"No data present\"\n    // if they do not have data to report, instead of returning unset values\n    // which could be misinterpreted as actual reported values.\n    function getRoundData(uint80 _roundId)\n        external\n        view\n        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n    function latestRoundData()\n        external\n        view\n        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n}\n"
      },
      "src/interfaces/IPyth.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.0;\n\nimport \"./PythStructs.sol\";\nimport \"./IPythEvents.sol\";\n\n/// @title Consume prices from the Pyth Network (https://pyth.network/).\n/// @dev Please refer to the guidance at https://docs.pyth.network/consumers/best-practices for how to consume prices\n/// safely.\n/// @author Pyth Data Association\ninterface IPyth is IPythEvents {\n    /// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time\n    function getValidTimePeriod() external view returns (uint256 validTimePeriod);\n\n    /// @notice Returns the price and confidence interval.\n    /// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds.\n    /// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getPrice(bytes32 id) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the exponentially-weighted moving average price and confidence interval.\n    /// @dev Reverts if the EMA price is not available.\n    /// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getEmaPrice(bytes32 id) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the price of a price feed without any sanity checks.\n    /// @dev This function returns the most recent price update in this contract without any recency checks.\n    /// This function is unsafe as the returned price update may be arbitrarily far in the past.\n    ///\n    /// Users of this function should check the `publishTime` in the price to ensure that the returned price is\n    /// sufficiently recent for their application. If you are considering using this function, it may be\n    /// safer / easier to use either `getPrice` or `getPriceNoOlderThan`.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getPriceUnsafe(bytes32 id) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the price that is no older than `age` seconds of the current time.\n    /// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in\n    /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently\n    /// recently.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getPriceNoOlderThan(bytes32 id, uint256 age) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.\n    /// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.\n    /// However, if the price is not recent this function returns the latest available price.\n    ///\n    /// The returned price can be from arbitrarily far in the past; this function makes no guarantees that\n    /// the returned price is recent or useful for any particular application.\n    ///\n    /// Users of this function should check the `publishTime` in the price to ensure that the returned price is\n    /// sufficiently recent for their application. If you are considering using this function, it may be\n    /// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getEmaPriceUnsafe(bytes32 id) external view returns (PythStructs.Price memory price);\n\n    /// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds\n    /// of the current time.\n    /// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in\n    /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently\n    /// recently.\n    /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.\n    function getEmaPriceNoOlderThan(bytes32 id, uint256 age) external view returns (PythStructs.Price memory price);\n\n    /// @notice Update price feeds with given update messages.\n    /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling\n    /// `getUpdateFee` with the length of the `updateData` array.\n    /// Prices will be updated if they are more recent than the current stored prices.\n    /// The call will succeed even if the update is not the most recent.\n    /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.\n    /// @param updateData Array of price update data.\n    function updatePriceFeeds(bytes[] calldata updateData) external payable;\n\n    /// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is\n    /// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the\n    /// given `publishTimes` for the price feeds and does not read the actual price update publish time within\n    /// `updateData`.\n    ///\n    /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling\n    /// `getUpdateFee` with the length of the `updateData` array.\n    ///\n    /// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime\n    /// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have\n    /// a newer or equal publish time than the given publish time, it will reject the transaction to save gas.\n    /// Otherwise, it calls updatePriceFeeds method to update the prices.\n    ///\n    /// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid.\n    /// @param updateData Array of price update data.\n    /// @param priceIds Array of price ids.\n    /// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`\n    function updatePriceFeedsIfNecessary(\n        bytes[] calldata updateData,\n        bytes32[] calldata priceIds,\n        uint64[] calldata publishTimes\n    ) external payable;\n\n    /// @notice Returns the required fee to update an array of price updates.\n    /// @param updateData Array of price update data.\n    /// @return feeAmount The required fee in Wei.\n    function getUpdateFee(bytes[] calldata updateData) external view returns (uint256 feeAmount);\n\n    /// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published\n    /// within `minPublishTime` and `maxPublishTime`.\n    ///\n    /// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price;\n    /// otherwise, please consider using `updatePriceFeeds`. This method does not store the price updates on-chain.\n    ///\n    /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling\n    /// `getUpdateFee` with the length of the `updateData` array.\n    ///\n    ///\n    /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is\n    /// no update for any of the given `priceIds` within the given time range.\n    /// @param updateData Array of price update data.\n    /// @param priceIds Array of price ids.\n    /// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.\n    /// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.\n    /// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).\n    function parsePriceFeedUpdates(\n        bytes[] calldata updateData,\n        bytes32[] calldata priceIds,\n        uint64 minPublishTime,\n        uint64 maxPublishTime\n    ) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);\n}\n"
      },
      "src/interfaces/PythStructs.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.0;\n\ncontract PythStructs {\n    // A price with a degree of uncertainty, represented as a price +- a confidence interval.\n    //\n    // The confidence interval roughly corresponds to the standard error of a normal distribution.\n    // Both the price and confidence are stored in a fixed-point numeric representation,\n    // `x * (10^expo)`, where `expo` is the exponent.\n    //\n    // Please refer to the documentation at https://docs.pyth.network/price-feeds/best-practices for how\n    // to use this price safely.\n    struct Price {\n        // Price\n        int64 price;\n        // Confidence interval around the price\n        uint64 conf;\n        // Price exponent\n        int32 expo;\n        // Unix timestamp describing when the price was published\n        uint256 publishTime;\n    }\n\n    // PriceFeed represents a current aggregate price from pyth publisher feeds.\n    struct PriceFeed {\n        // The price ID.\n        bytes32 id;\n        // Latest available price\n        Price price;\n        // Latest available exponentially-weighted moving average price\n        Price emaPrice;\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "lib/radiant-v2-core/contracts/main/interfaces/IPriceOracleGetter.sol": {
        "content": "// SPDX-License-Identifier: agpl-3.0\npragma solidity 0.8.12;\n\n/**\n * @title IPriceOracleGetter interface\n * @notice Interface for the Aave price oracle.\n **/\n\ninterface IPriceOracleGetter {\n\t/**\n\t * @dev returns the asset price in ETH\n\t * @param asset the address of the asset\n\t * @return the ETH price of the asset\n\t **/\n\tfunction getAssetPrice(address asset) external view returns (uint256);\n}\n"
      },
      "src/interfaces/IPythEvents.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.0;\n\n/// @title IPythEvents contains the events that Pyth contract emits.\n/// @dev This interface can be used for listening to the updates for off-chain and testing purposes.\ninterface IPythEvents {\n    /// @dev Emitted when the price feed with `id` has received a fresh update.\n    /// @param id The Pyth Price Feed ID.\n    /// @param publishTime Publish time of the given price update.\n    /// @param price Price of the given price update.\n    /// @param conf Confidence interval of the given price update.\n    event PriceFeedUpdate(bytes32 indexed id, uint64 publishTime, int64 price, uint64 conf);\n\n    /// @dev Emitted when a batch price update is processed successfully.\n    /// @param chainId ID of the source chain that the batch price update comes from.\n    /// @param sequenceNumber Sequence number of the batch price update.\n    event BatchPriceFeedUpdate(uint16 chainId, uint64 sequenceNumber);\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
        "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
        "@uniswap/v2-core/contracts/=lib/uniswap-v2-core/contracts/",
        "@layerzerolabs/solidity-examples/contracts/=lib/layer-zero/contracts/",
        "@radiant-v2-core/interfaces/=lib/radiant-v2-core/contracts/main/interfaces/",
        "@radiant-v2-core/lending/=lib/radiant-v2-core/contracts/main/lending/",
        "@radiant-v2-core/radiant/=lib/radiant-v2-core/contracts/main/radiant/",
        "@radiant-v2-core/mocks/=lib/radiant-v2-core/contracts/main/test/",
        "@balancer-labs/v2-interfaces/=lib/balancer-v2-monorepo/pkg/interfaces/",
        "@bgd-labs-stk-v3/contracts/=lib/bgd-labs-stk-v3/src/contracts/",
        "aave-token-v3/=lib/bgd-labs-stk-v3/lib/aave-token-v3/src/",
        "@aave/core-v3/=lib/bgd-labs-stk-v3/lib/aave-address-book/lib/aave-v3-core/",
        "@aave/periphery-v3/=lib/bgd-labs-stk-v3/lib/aave-address-book/lib/aave-v3-periphery/",
        "aave-address-book/=lib/bgd-labs-stk-v3/lib/aave-address-book/src/",
        "aave-helpers/=lib/bgd-labs-stk-v3/lib/aave-helpers/",
        "aave-token-v2/=lib/bgd-labs-stk-v3/lib/aave-token-v3/lib/aave-token-v2/contracts/",
        "aave-v3-core/=lib/bgd-labs-stk-v3/lib/aave-address-book/lib/aave-v3-core/",
        "aave-v3-periphery/=lib/bgd-labs-stk-v3/lib/aave-address-book/lib/aave-v3-periphery/",
        "balancer-v2-monorepo/=lib/balancer-v2-monorepo/",
        "bgd-labs-stk-v3/=lib/bgd-labs-stk-v3/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
        "forge-std/=lib/forge-std/src/",
        "governance-crosschain-bridges/=lib/bgd-labs-stk-v3/lib/aave-helpers/lib/governance-crosschain-bridges/",
        "layer-zero/=lib/layer-zero/contracts/",
        "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/",
        "openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
        "radiant-v2-core/=lib/radiant-v2-core/contracts/",
        "solidity-utils/=lib/bgd-labs-stk-v3/lib/aave-helpers/lib/solidity-utils/",
        "uniswap-v2-core/=lib/uniswap-v2-core/contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 1000
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs"
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "london",
      "viaIR": false,
      "libraries": {}
    }
  }}