@venusprotocol/protocol-reserve 3.4.0-dev.3 → 3.4.0-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/deployments/arbitrumone/ProtocolShareReserve_Implementation.json +41 -41
  2. package/deployments/{berachainbartio/solcInputs/027aeec938943227f90cf24126ba2c44.json → arbitrumone/solcInputs/64291858ccadc72be51008438a30a689.json} +2 -2
  3. package/deployments/arbitrumone.json +1 -1
  4. package/deployments/arbitrumone_addresses.json +1 -1
  5. package/deployments/arbitrumsepolia/ProtocolShareReserve_Implementation.json +37 -37
  6. package/deployments/arbitrumsepolia/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  7. package/deployments/arbitrumsepolia.json +1 -1
  8. package/deployments/arbitrumsepolia_addresses.json +1 -1
  9. package/deployments/basemainnet/ProtocolShareReserve_Implementation.json +42 -42
  10. package/deployments/basemainnet/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  11. package/deployments/basemainnet.json +1 -1
  12. package/deployments/basemainnet_addresses.json +1 -1
  13. package/deployments/basesepolia/ProtocolShareReserve_Implementation.json +42 -42
  14. package/deployments/basesepolia/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  15. package/deployments/basesepolia.json +1 -1
  16. package/deployments/basesepolia_addresses.json +1 -1
  17. package/deployments/bscmainnet/ProtocolShareReserve_Implementation.json +52 -47
  18. package/deployments/bscmainnet/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  19. package/deployments/bscmainnet.json +1 -1
  20. package/deployments/bscmainnet_addresses.json +1 -1
  21. package/deployments/bsctestnet/ProtocolShareReserve_Implementation.json +50 -45
  22. package/deployments/bsctestnet/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  23. package/deployments/bsctestnet.json +1 -1
  24. package/deployments/bsctestnet_addresses.json +1 -1
  25. package/deployments/ethereum/ProtocolShareReserve_Implementation.json +53 -48
  26. package/deployments/ethereum/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  27. package/deployments/ethereum.json +1 -1
  28. package/deployments/ethereum_addresses.json +1 -1
  29. package/deployments/opbnbmainnet/ProtocolShareReserve_Implementation.json +53 -48
  30. package/deployments/opbnbmainnet/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  31. package/deployments/opbnbmainnet.json +1 -1
  32. package/deployments/opbnbmainnet_addresses.json +1 -1
  33. package/deployments/opbnbtestnet/ProtocolShareReserve_Implementation.json +66 -50
  34. package/deployments/opbnbtestnet/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  35. package/deployments/opbnbtestnet.json +6 -1
  36. package/deployments/opbnbtestnet_addresses.json +1 -1
  37. package/deployments/opmainnet/ProtocolShareReserve_Implementation.json +41 -41
  38. package/deployments/opmainnet/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  39. package/deployments/opmainnet.json +1 -1
  40. package/deployments/opmainnet_addresses.json +1 -1
  41. package/deployments/opsepolia/ProtocolShareReserve_Implementation.json +41 -41
  42. package/deployments/opsepolia/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  43. package/deployments/opsepolia.json +1 -1
  44. package/deployments/opsepolia_addresses.json +1 -1
  45. package/deployments/sepolia/ProtocolShareReserve_Implementation.json +71 -55
  46. package/deployments/sepolia/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  47. package/deployments/sepolia.json +6 -1
  48. package/deployments/sepolia_addresses.json +1 -1
  49. package/deployments/unichainmainnet/ProtocolShareReserve_Implementation.json +42 -42
  50. package/deployments/unichainmainnet/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  51. package/deployments/unichainmainnet.json +1 -1
  52. package/deployments/unichainmainnet_addresses.json +1 -1
  53. package/deployments/unichainsepolia/ProtocolShareReserve_Implementation.json +42 -42
  54. package/deployments/unichainsepolia/solcInputs/64291858ccadc72be51008438a30a689.json +280 -0
  55. package/deployments/unichainsepolia.json +1 -1
  56. package/deployments/unichainsepolia_addresses.json +1 -1
  57. package/deployments/zksyncmainnet/ProtocolShareReserve_Implementation.json +65 -103
  58. package/deployments/zksyncmainnet/solcInputs/df1333e6e275b480d88b215c38398750.json +271 -0
  59. package/deployments/zksyncmainnet.json +1 -1
  60. package/deployments/zksyncmainnet_addresses.json +1 -1
  61. package/deployments/zksyncsepolia/ProtocolShareReserve_Implementation.json +93 -69
  62. package/deployments/zksyncsepolia/solcInputs/df1333e6e275b480d88b215c38398750.json +271 -0
  63. package/deployments/zksyncsepolia.json +1 -1
  64. package/deployments/zksyncsepolia_addresses.json +1 -1
  65. package/dist/hardhat.config.d.ts.map +1 -1
  66. package/dist/hardhat.config.js +0 -19
  67. package/dist/hardhat.config.js.map +1 -1
  68. package/package.json +1 -1
  69. package/deployments/berachainbartio/.chainId +0 -1
  70. package/deployments/berachainbartio/DefaultProxyAdmin.json +0 -200
  71. package/deployments/berachainbartio/ProtocolShareReserve.json +0 -1059
  72. package/deployments/berachainbartio/ProtocolShareReserve_Implementation.json +0 -1285
  73. package/deployments/berachainbartio/ProtocolShareReserve_Proxy.json +0 -277
  74. package/deployments/berachainbartio/solcInputs/0e89febeebc7444140de8e67c9067d2c.json +0 -78
  75. package/deployments/berachainbartio.json +0 -2049
  76. package/deployments/berachainbartio_addresses.json +0 -10
@@ -116,7 +116,7 @@
116
116
  "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface VBep20Interface is IERC20Metadata {\n /**\n * @notice Underlying asset for this VToken\n */\n function underlying() external view returns (address);\n}\n"
117
117
  },
118
118
  "@venusprotocol/oracle/contracts/ResilientOracle.sol": {
119
- "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.25;\n\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\nimport \"./interfaces/VBep20Interface.sol\";\nimport \"./interfaces/OracleInterface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\n/**\n * @title ResilientOracle\n * @author Venus\n * @notice The Resilient Oracle is the main contract that the protocol uses to fetch prices of assets.\n * \n * DeFi protocols are vulnerable to price oracle failures including oracle manipulation and incorrectly\n * reported prices. If only one oracle is used, this creates a single point of failure and opens a vector\n * for attacking the protocol.\n * \n * The Resilient Oracle uses multiple sources and fallback mechanisms to provide accurate prices and protect\n * the protocol from oracle attacks. Currently it includes integrations with Chainlink, Pyth, Binance Oracle\n * and TWAP (Time-Weighted Average Price) oracles. TWAP uses PancakeSwap as the on-chain price source.\n * \n * For every market (vToken) we configure the main, pivot and fallback oracles. The oracles are configured per \n * vToken's underlying asset address. The main oracle oracle is the most trustworthy price source, the pivot \n * oracle is used as a loose sanity checker and the fallback oracle is used as a backup price source. \n * \n * To validate prices returned from two oracles, we use an upper and lower bound ratio that is set for every\n * market. The upper bound ratio represents the deviation between reported price (the price that’s being\n * validated) and the anchor price (the price we are validating against) above which the reported price will\n * be invalidated. The lower bound ratio presents the deviation between reported price and anchor price below\n * which the reported price will be invalidated. So for oracle price to be considered valid the below statement\n * should be true:\n\n```\nanchorRatio = anchorPrice/reporterPrice\nisValid = anchorRatio <= upperBoundAnchorRatio && anchorRatio >= lowerBoundAnchorRatio\n```\n\n * In most cases, Chainlink is used as the main oracle, TWAP or Pyth oracles are used as the pivot oracle depending\n * on which supports the given market and Binance oracle is used as the fallback oracle. For some markets we may\n * use Pyth or TWAP as the main oracle if the token price is not supported by Chainlink or Binance oracles. \n * \n * For a fetched price to be valid it must be positive and not stagnant. If the price is invalid then we consider the\n * oracle to be stagnant and treat it like it's disabled.\n */\ncontract ResilientOracle is PausableUpgradeable, AccessControlledV8, ResilientOracleInterface {\n /**\n * @dev Oracle roles:\n * **main**: The most trustworthy price source\n * **pivot**: Price oracle used as a loose sanity checker\n * **fallback**: The backup source when main oracle price is invalidated\n */\n enum OracleRole {\n MAIN,\n PIVOT,\n FALLBACK\n }\n\n struct TokenConfig {\n /// @notice asset address\n address asset;\n /// @notice `oracles` stores the oracles based on their role in the following order:\n /// [main, pivot, fallback],\n /// It can be indexed with the corresponding enum OracleRole value\n address[3] oracles;\n /// @notice `enableFlagsForOracles` stores the enabled state\n /// for each oracle in the same order as `oracles`\n bool[3] enableFlagsForOracles;\n }\n\n uint256 public constant INVALID_PRICE = 0;\n\n /// @notice Native market address\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable nativeMarket;\n\n /// @notice VAI address\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable vai;\n\n /// @notice Set this as asset address for Native token on each chain.This is the underlying for vBNB (on bsc)\n /// and can serve as any underlying asset of a market that supports native tokens\n address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Bound validator contract address\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n BoundValidatorInterface public immutable boundValidator;\n\n mapping(address => TokenConfig) private tokenConfigs;\n\n event TokenConfigAdded(\n address indexed asset,\n address indexed mainOracle,\n address indexed pivotOracle,\n address fallbackOracle\n );\n\n /// Event emitted when an oracle is set\n event OracleSet(address indexed asset, address indexed oracle, uint256 indexed role);\n\n /// Event emitted when an oracle is enabled or disabled\n event OracleEnabled(address indexed asset, uint256 indexed role, bool indexed enable);\n\n /**\n * @notice Checks whether an address is null or not\n */\n modifier notNullAddress(address someone) {\n if (someone == address(0)) revert(\"can't be zero address\");\n _;\n }\n\n /**\n * @notice Checks whether token config exists by checking whether asset is null address\n * @dev address can't be null, so it's suitable to be used to check the validity of the config\n * @param asset asset address\n */\n modifier checkTokenConfigExistence(address asset) {\n if (tokenConfigs[asset].asset == address(0)) revert(\"token config must exist\");\n _;\n }\n\n /// @notice Constructor for the implementation contract. Sets immutable variables.\n /// @dev nativeMarketAddress can be address(0) if on the chain we do not support native market\n /// (e.g vETH on ethereum would not be supported, only vWETH)\n /// @param nativeMarketAddress The address of a native market (for bsc it would be vBNB address)\n /// @param vaiAddress The address of the VAI token (if there is VAI on the deployed chain).\n /// Set to address(0) of VAI is not existent.\n /// @param _boundValidator Address of the bound validator contract\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(\n address nativeMarketAddress,\n address vaiAddress,\n BoundValidatorInterface _boundValidator\n ) notNullAddress(address(_boundValidator)) {\n nativeMarket = nativeMarketAddress;\n vai = vaiAddress;\n boundValidator = _boundValidator;\n\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the contract admin and sets the BoundValidator contract address\n * @param accessControlManager_ Address of the access control manager contract\n */\n function initialize(address accessControlManager_) external initializer {\n __AccessControlled_init(accessControlManager_);\n __Pausable_init();\n }\n\n /**\n * @notice Pauses oracle\n * @custom:access Only Governance\n */\n function pause() external {\n _checkAccessAllowed(\"pause()\");\n _pause();\n }\n\n /**\n * @notice Unpauses oracle\n * @custom:access Only Governance\n */\n function unpause() external {\n _checkAccessAllowed(\"unpause()\");\n _unpause();\n }\n\n /**\n * @notice Batch sets token configs\n * @param tokenConfigs_ Token config array\n * @custom:access Only Governance\n * @custom:error Throws a length error if the length of the token configs array is 0\n */\n function setTokenConfigs(TokenConfig[] memory tokenConfigs_) external {\n if (tokenConfigs_.length == 0) revert(\"length can't be 0\");\n uint256 numTokenConfigs = tokenConfigs_.length;\n for (uint256 i; i < numTokenConfigs; ) {\n setTokenConfig(tokenConfigs_[i]);\n unchecked {\n ++i;\n }\n }\n }\n\n /**\n * @notice Sets oracle for a given asset and role.\n * @dev Supplied asset **must** exist and main oracle may not be null\n * @param asset Asset address\n * @param oracle Oracle address\n * @param role Oracle role\n * @custom:access Only Governance\n * @custom:error Null address error if main-role oracle address is null\n * @custom:error NotNullAddress error is thrown if asset address is null\n * @custom:error TokenConfigExistance error is thrown if token config is not set\n * @custom:event Emits OracleSet event with asset address, oracle address and role of the oracle for the asset\n */\n function setOracle(\n address asset,\n address oracle,\n OracleRole role\n ) external notNullAddress(asset) checkTokenConfigExistence(asset) {\n _checkAccessAllowed(\"setOracle(address,address,uint8)\");\n if (oracle == address(0) && role == OracleRole.MAIN) revert(\"can't set zero address to main oracle\");\n tokenConfigs[asset].oracles[uint256(role)] = oracle;\n emit OracleSet(asset, oracle, uint256(role));\n }\n\n /**\n * @notice Enables/ disables oracle for the input asset. Token config for the input asset **must** exist\n * @dev Configuration for the asset **must** already exist and the asset cannot be 0 address\n * @param asset Asset address\n * @param role Oracle role\n * @param enable Enabled boolean of the oracle\n * @custom:access Only Governance\n * @custom:error NotNullAddress error is thrown if asset address is null\n * @custom:error TokenConfigExistance error is thrown if token config is not set\n */\n function enableOracle(\n address asset,\n OracleRole role,\n bool enable\n ) external notNullAddress(asset) checkTokenConfigExistence(asset) {\n _checkAccessAllowed(\"enableOracle(address,uint8,bool)\");\n tokenConfigs[asset].enableFlagsForOracles[uint256(role)] = enable;\n emit OracleEnabled(asset, uint256(role), enable);\n }\n\n /**\n * @notice Updates the TWAP pivot oracle price.\n * @dev This function should always be called before calling getUnderlyingPrice\n * @param vToken vToken address\n */\n function updatePrice(address vToken) external override {\n address asset = _getUnderlyingAsset(vToken);\n (address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);\n if (pivotOracle != address(0) && pivotOracleEnabled) {\n //if pivot oracle is not TwapOracle it will revert so we need to catch the revert\n try TwapInterface(pivotOracle).updateTwap(asset) {} catch {}\n }\n }\n\n /**\n * @notice Updates the pivot oracle price. Currently using TWAP\n * @dev This function should always be called before calling getPrice\n * @param asset asset address\n */\n function updateAssetPrice(address asset) external {\n (address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);\n if (pivotOracle != address(0) && pivotOracleEnabled) {\n //if pivot oracle is not TwapOracle it will revert so we need to catch the revert\n try TwapInterface(pivotOracle).updateTwap(asset) {} catch {}\n }\n }\n\n /**\n * @dev Gets token config by asset address\n * @param asset asset address\n * @return tokenConfig Config for the asset\n */\n function getTokenConfig(address asset) external view returns (TokenConfig memory) {\n return tokenConfigs[asset];\n }\n\n /**\n * @notice Gets price of the underlying asset for a given vToken. Validation flow:\n * - Check if the oracle is paused globally\n * - Validate price from main oracle against pivot oracle\n * - Validate price from fallback oracle against pivot oracle if the first validation failed\n * - Validate price from main oracle against fallback oracle if the second validation failed\n * In the case that the pivot oracle is not available but main price is available and validation is successful,\n * main oracle price is returned.\n * @param vToken vToken address\n * @return price USD price in scaled decimal places.\n * @custom:error Paused error is thrown when resilent oracle is paused\n * @custom:error Invalid resilient oracle price error is thrown if fetched prices from oracle is invalid\n */\n function getUnderlyingPrice(address vToken) external view override returns (uint256) {\n if (paused()) revert(\"resilient oracle is paused\");\n\n address asset = _getUnderlyingAsset(vToken);\n return _getPrice(asset);\n }\n\n /**\n * @notice Gets price of the asset\n * @param asset asset address\n * @return price USD price in scaled decimal places.\n * @custom:error Paused error is thrown when resilent oracle is paused\n * @custom:error Invalid resilient oracle price error is thrown if fetched prices from oracle is invalid\n */\n function getPrice(address asset) external view override returns (uint256) {\n if (paused()) revert(\"resilient oracle is paused\");\n return _getPrice(asset);\n }\n\n /**\n * @notice Sets/resets single token configs.\n * @dev main oracle **must not** be a null address\n * @param tokenConfig Token config struct\n * @custom:access Only Governance\n * @custom:error NotNullAddress is thrown if asset address is null\n * @custom:error NotNullAddress is thrown if main-role oracle address for asset is null\n * @custom:event Emits TokenConfigAdded event when the asset config is set successfully by the authorized account\n */\n function setTokenConfig(\n TokenConfig memory tokenConfig\n ) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.oracles[uint256(OracleRole.MAIN)]) {\n _checkAccessAllowed(\"setTokenConfig(TokenConfig)\");\n\n tokenConfigs[tokenConfig.asset] = tokenConfig;\n emit TokenConfigAdded(\n tokenConfig.asset,\n tokenConfig.oracles[uint256(OracleRole.MAIN)],\n tokenConfig.oracles[uint256(OracleRole.PIVOT)],\n tokenConfig.oracles[uint256(OracleRole.FALLBACK)]\n );\n }\n\n /**\n * @notice Gets oracle and enabled status by asset address\n * @param asset asset address\n * @param role Oracle role\n * @return oracle Oracle address based on role\n * @return enabled Enabled flag of the oracle based on token config\n */\n function getOracle(address asset, OracleRole role) public view returns (address oracle, bool enabled) {\n oracle = tokenConfigs[asset].oracles[uint256(role)];\n enabled = tokenConfigs[asset].enableFlagsForOracles[uint256(role)];\n }\n\n function _getPrice(address asset) internal view returns (uint256) {\n uint256 pivotPrice = INVALID_PRICE;\n\n // Get pivot oracle price, Invalid price if not available or error\n (address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);\n if (pivotOracleEnabled && pivotOracle != address(0)) {\n try OracleInterface(pivotOracle).getPrice(asset) returns (uint256 pricePivot) {\n pivotPrice = pricePivot;\n } catch {}\n }\n\n // Compare main price and pivot price, return main price and if validation was successful\n // note: In case pivot oracle is not available but main price is available and\n // validation is successful, the main oracle price is returned.\n (uint256 mainPrice, bool validatedPivotMain) = _getMainOraclePrice(\n asset,\n pivotPrice,\n pivotOracleEnabled && pivotOracle != address(0)\n );\n if (mainPrice != INVALID_PRICE && validatedPivotMain) return mainPrice;\n\n // Compare fallback and pivot if main oracle comparision fails with pivot\n // Return fallback price when fallback price is validated successfully with pivot oracle\n (uint256 fallbackPrice, bool validatedPivotFallback) = _getFallbackOraclePrice(asset, pivotPrice);\n if (fallbackPrice != INVALID_PRICE && validatedPivotFallback) return fallbackPrice;\n\n // Lastly compare main price and fallback price\n if (\n mainPrice != INVALID_PRICE &&\n fallbackPrice != INVALID_PRICE &&\n boundValidator.validatePriceWithAnchorPrice(asset, mainPrice, fallbackPrice)\n ) {\n return mainPrice;\n }\n\n revert(\"invalid resilient oracle price\");\n }\n\n /**\n * @notice Gets a price for the provided asset\n * @dev This function won't revert when price is 0, because the fallback oracle may still be\n * able to fetch a correct price\n * @param asset asset address\n * @param pivotPrice Pivot oracle price\n * @param pivotEnabled If pivot oracle is not empty and enabled\n * @return price USD price in scaled decimals\n * e.g. asset decimals is 8 then price is returned as 10**18 * 10**(18-8) = 10**28 decimals\n * @return pivotValidated Boolean representing if the validation of main oracle price\n * and pivot oracle price were successful\n * @custom:error Invalid price error is thrown if main oracle fails to fetch price of the asset\n * @custom:error Invalid price error is thrown if main oracle is not enabled or main oracle\n * address is null\n */\n function _getMainOraclePrice(\n address asset,\n uint256 pivotPrice,\n bool pivotEnabled\n ) internal view returns (uint256, bool) {\n (address mainOracle, bool mainOracleEnabled) = getOracle(asset, OracleRole.MAIN);\n if (mainOracleEnabled && mainOracle != address(0)) {\n try OracleInterface(mainOracle).getPrice(asset) returns (uint256 mainOraclePrice) {\n if (!pivotEnabled) {\n return (mainOraclePrice, true);\n }\n if (pivotPrice == INVALID_PRICE) {\n return (mainOraclePrice, false);\n }\n return (\n mainOraclePrice,\n boundValidator.validatePriceWithAnchorPrice(asset, mainOraclePrice, pivotPrice)\n );\n } catch {\n return (INVALID_PRICE, false);\n }\n }\n\n return (INVALID_PRICE, false);\n }\n\n /**\n * @dev This function won't revert when the price is 0 because getPrice checks if price is > 0\n * @param asset asset address\n * @return price USD price in 18 decimals\n * @return pivotValidated Boolean representing if the validation of fallback oracle price\n * and pivot oracle price were successfull\n * @custom:error Invalid price error is thrown if fallback oracle fails to fetch price of the asset\n * @custom:error Invalid price error is thrown if fallback oracle is not enabled or fallback oracle\n * address is null\n */\n function _getFallbackOraclePrice(address asset, uint256 pivotPrice) private view returns (uint256, bool) {\n (address fallbackOracle, bool fallbackEnabled) = getOracle(asset, OracleRole.FALLBACK);\n if (fallbackEnabled && fallbackOracle != address(0)) {\n try OracleInterface(fallbackOracle).getPrice(asset) returns (uint256 fallbackOraclePrice) {\n if (pivotPrice == INVALID_PRICE) {\n return (fallbackOraclePrice, false);\n }\n return (\n fallbackOraclePrice,\n boundValidator.validatePriceWithAnchorPrice(asset, fallbackOraclePrice, pivotPrice)\n );\n } catch {\n return (INVALID_PRICE, false);\n }\n }\n\n return (INVALID_PRICE, false);\n }\n\n /**\n * @dev This function returns the underlying asset of a vToken\n * @param vToken vToken address\n * @return asset underlying asset address\n */\n function _getUnderlyingAsset(address vToken) private view notNullAddress(vToken) returns (address asset) {\n if (vToken == nativeMarket) {\n asset = NATIVE_TOKEN_ADDR;\n } else if (vToken == vai) {\n asset = vai;\n } else {\n asset = VBep20Interface(vToken).underlying();\n }\n }\n}\n"
119
+ "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.25;\n\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\nimport \"./interfaces/VBep20Interface.sol\";\nimport \"./interfaces/OracleInterface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\n/**\n * @title ResilientOracle\n * @author Venus\n * @notice The Resilient Oracle is the main contract that the protocol uses to fetch prices of assets.\n *\n * DeFi protocols are vulnerable to price oracle failures including oracle manipulation and incorrectly\n * reported prices. If only one oracle is used, this creates a single point of failure and opens a vector\n * for attacking the protocol.\n *\n * The Resilient Oracle uses multiple sources and fallback mechanisms to provide accurate prices and protect\n * the protocol from oracle attacks. Currently it includes integrations with Chainlink, Pyth, Binance Oracle\n * and TWAP (Time-Weighted Average Price) oracles. TWAP uses PancakeSwap as the on-chain price source.\n *\n * For every market (vToken) we configure the main, pivot and fallback oracles. The oracles are configured per\n * vToken's underlying asset address. The main oracle oracle is the most trustworthy price source, the pivot\n * oracle is used as a loose sanity checker and the fallback oracle is used as a backup price source.\n *\n * To validate prices returned from two oracles, we use an upper and lower bound ratio that is set for every\n * market. The upper bound ratio represents the deviation between reported price (the price that’s being\n * validated) and the anchor price (the price we are validating against) above which the reported price will\n * be invalidated. The lower bound ratio presents the deviation between reported price and anchor price below\n * which the reported price will be invalidated. So for oracle price to be considered valid the below statement\n * should be true:\n\n```\nanchorRatio = anchorPrice/reporterPrice\nisValid = anchorRatio <= upperBoundAnchorRatio && anchorRatio >= lowerBoundAnchorRatio\n```\n\n * In most cases, Chainlink is used as the main oracle, TWAP or Pyth oracles are used as the pivot oracle depending\n * on which supports the given market and Binance oracle is used as the fallback oracle. For some markets we may\n * use Pyth or TWAP as the main oracle if the token price is not supported by Chainlink or Binance oracles.\n *\n * For a fetched price to be valid it must be positive and not stagnant. If the price is invalid then we consider the\n * oracle to be stagnant and treat it like it's disabled.\n */\ncontract ResilientOracle is PausableUpgradeable, AccessControlledV8, ResilientOracleInterface {\n /**\n * @dev Oracle roles:\n * **main**: The most trustworthy price source\n * **pivot**: Price oracle used as a loose sanity checker\n * **fallback**: The backup source when main oracle price is invalidated\n */\n enum OracleRole {\n MAIN,\n PIVOT,\n FALLBACK\n }\n\n struct TokenConfig {\n /// @notice asset address\n address asset;\n /// @notice `oracles` stores the oracles based on their role in the following order:\n /// [main, pivot, fallback],\n /// It can be indexed with the corresponding enum OracleRole value\n address[3] oracles;\n /// @notice `enableFlagsForOracles` stores the enabled state\n /// for each oracle in the same order as `oracles`\n bool[3] enableFlagsForOracles;\n }\n\n uint256 public constant INVALID_PRICE = 0;\n\n /// @notice Native market address\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable nativeMarket;\n\n /// @notice VAI address\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable vai;\n\n /// @notice Set this as asset address for Native token on each chain.This is the underlying for vBNB (on bsc)\n /// and can serve as any underlying asset of a market that supports native tokens\n address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Bound validator contract address\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n BoundValidatorInterface public immutable boundValidator;\n\n mapping(address => TokenConfig) private tokenConfigs;\n\n event TokenConfigAdded(\n address indexed asset,\n address indexed mainOracle,\n address indexed pivotOracle,\n address fallbackOracle\n );\n\n /// Event emitted when an oracle is set\n event OracleSet(address indexed asset, address indexed oracle, uint256 indexed role);\n\n /// Event emitted when an oracle is enabled or disabled\n event OracleEnabled(address indexed asset, uint256 indexed role, bool indexed enable);\n\n /**\n * @notice Checks whether an address is null or not\n */\n modifier notNullAddress(address someone) {\n if (someone == address(0)) revert(\"can't be zero address\");\n _;\n }\n\n /**\n * @notice Checks whether token config exists by checking whether asset is null address\n * @dev address can't be null, so it's suitable to be used to check the validity of the config\n * @param asset asset address\n */\n modifier checkTokenConfigExistence(address asset) {\n if (tokenConfigs[asset].asset == address(0)) revert(\"token config must exist\");\n _;\n }\n\n /// @notice Constructor for the implementation contract. Sets immutable variables.\n /// @dev nativeMarketAddress can be address(0) if on the chain we do not support native market\n /// (e.g vETH on ethereum would not be supported, only vWETH)\n /// @param nativeMarketAddress The address of a native market (for bsc it would be vBNB address)\n /// @param vaiAddress The address of the VAI token (if there is VAI on the deployed chain).\n /// Set to address(0) of VAI is not existent.\n /// @param _boundValidator Address of the bound validator contract\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(\n address nativeMarketAddress,\n address vaiAddress,\n BoundValidatorInterface _boundValidator\n ) notNullAddress(address(_boundValidator)) {\n nativeMarket = nativeMarketAddress;\n vai = vaiAddress;\n boundValidator = _boundValidator;\n\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the contract admin and sets the BoundValidator contract address\n * @param accessControlManager_ Address of the access control manager contract\n */\n function initialize(address accessControlManager_) external initializer {\n __AccessControlled_init(accessControlManager_);\n __Pausable_init();\n }\n\n /**\n * @notice Pauses oracle\n * @custom:access Only Governance\n */\n function pause() external {\n _checkAccessAllowed(\"pause()\");\n _pause();\n }\n\n /**\n * @notice Unpauses oracle\n * @custom:access Only Governance\n */\n function unpause() external {\n _checkAccessAllowed(\"unpause()\");\n _unpause();\n }\n\n /**\n * @notice Batch sets token configs\n * @param tokenConfigs_ Token config array\n * @custom:access Only Governance\n * @custom:error Throws a length error if the length of the token configs array is 0\n */\n function setTokenConfigs(TokenConfig[] memory tokenConfigs_) external {\n if (tokenConfigs_.length == 0) revert(\"length can't be 0\");\n uint256 numTokenConfigs = tokenConfigs_.length;\n for (uint256 i; i < numTokenConfigs; ) {\n setTokenConfig(tokenConfigs_[i]);\n unchecked {\n ++i;\n }\n }\n }\n\n /**\n * @notice Sets oracle for a given asset and role.\n * @dev Supplied asset **must** exist and main oracle may not be null\n * @param asset Asset address\n * @param oracle Oracle address\n * @param role Oracle role\n * @custom:access Only Governance\n * @custom:error Null address error if main-role oracle address is null\n * @custom:error NotNullAddress error is thrown if asset address is null\n * @custom:error TokenConfigExistance error is thrown if token config is not set\n * @custom:event Emits OracleSet event with asset address, oracle address and role of the oracle for the asset\n */\n function setOracle(\n address asset,\n address oracle,\n OracleRole role\n ) external notNullAddress(asset) checkTokenConfigExistence(asset) {\n _checkAccessAllowed(\"setOracle(address,address,uint8)\");\n if (oracle == address(0) && role == OracleRole.MAIN) revert(\"can't set zero address to main oracle\");\n tokenConfigs[asset].oracles[uint256(role)] = oracle;\n emit OracleSet(asset, oracle, uint256(role));\n }\n\n /**\n * @notice Enables/ disables oracle for the input asset. Token config for the input asset **must** exist\n * @dev Configuration for the asset **must** already exist and the asset cannot be 0 address\n * @param asset Asset address\n * @param role Oracle role\n * @param enable Enabled boolean of the oracle\n * @custom:access Only Governance\n * @custom:error NotNullAddress error is thrown if asset address is null\n * @custom:error TokenConfigExistance error is thrown if token config is not set\n */\n function enableOracle(\n address asset,\n OracleRole role,\n bool enable\n ) external notNullAddress(asset) checkTokenConfigExistence(asset) {\n _checkAccessAllowed(\"enableOracle(address,uint8,bool)\");\n tokenConfigs[asset].enableFlagsForOracles[uint256(role)] = enable;\n emit OracleEnabled(asset, uint256(role), enable);\n }\n\n /**\n * @notice Updates the TWAP pivot oracle price.\n * @dev This function should always be called before calling getUnderlyingPrice\n * @param vToken vToken address\n */\n function updatePrice(address vToken) external override {\n address asset = _getUnderlyingAsset(vToken);\n (address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);\n if (pivotOracle != address(0) && pivotOracleEnabled) {\n //if pivot oracle is not TwapOracle it will revert so we need to catch the revert\n try TwapInterface(pivotOracle).updateTwap(asset) {} catch {}\n }\n }\n\n /**\n * @notice Updates the pivot oracle price. Currently using TWAP\n * @dev This function should always be called before calling getPrice\n * @param asset asset address\n */\n function updateAssetPrice(address asset) external {\n (address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);\n if (pivotOracle != address(0) && pivotOracleEnabled) {\n //if pivot oracle is not TwapOracle it will revert so we need to catch the revert\n try TwapInterface(pivotOracle).updateTwap(asset) {} catch {}\n }\n }\n\n /**\n * @dev Gets token config by asset address\n * @param asset asset address\n * @return tokenConfig Config for the asset\n */\n function getTokenConfig(address asset) external view returns (TokenConfig memory) {\n return tokenConfigs[asset];\n }\n\n /**\n * @notice Gets price of the underlying asset for a given vToken. Validation flow:\n * - Check if the oracle is paused globally\n * - Validate price from main oracle against pivot oracle\n * - Validate price from fallback oracle against pivot oracle if the first validation failed\n * - Validate price from main oracle against fallback oracle if the second validation failed\n * In the case that the pivot oracle is not available but main price is available and validation is successful,\n * main oracle price is returned.\n * @param vToken vToken address\n * @return price USD price in scaled decimal places.\n * @custom:error Paused error is thrown when resilent oracle is paused\n * @custom:error Invalid resilient oracle price error is thrown if fetched prices from oracle is invalid\n */\n function getUnderlyingPrice(address vToken) external view override returns (uint256) {\n if (paused()) revert(\"resilient oracle is paused\");\n\n address asset = _getUnderlyingAsset(vToken);\n return _getPrice(asset);\n }\n\n /**\n * @notice Gets price of the asset\n * @param asset asset address\n * @return price USD price in scaled decimal places.\n * @custom:error Paused error is thrown when resilent oracle is paused\n * @custom:error Invalid resilient oracle price error is thrown if fetched prices from oracle is invalid\n */\n function getPrice(address asset) external view override returns (uint256) {\n if (paused()) revert(\"resilient oracle is paused\");\n return _getPrice(asset);\n }\n\n /**\n * @notice Sets/resets single token configs.\n * @dev main oracle **must not** be a null address\n * @param tokenConfig Token config struct\n * @custom:access Only Governance\n * @custom:error NotNullAddress is thrown if asset address is null\n * @custom:error NotNullAddress is thrown if main-role oracle address for asset is null\n * @custom:event Emits TokenConfigAdded event when the asset config is set successfully by the authorized account\n */\n function setTokenConfig(\n TokenConfig memory tokenConfig\n ) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.oracles[uint256(OracleRole.MAIN)]) {\n _checkAccessAllowed(\"setTokenConfig(TokenConfig)\");\n\n tokenConfigs[tokenConfig.asset] = tokenConfig;\n emit TokenConfigAdded(\n tokenConfig.asset,\n tokenConfig.oracles[uint256(OracleRole.MAIN)],\n tokenConfig.oracles[uint256(OracleRole.PIVOT)],\n tokenConfig.oracles[uint256(OracleRole.FALLBACK)]\n );\n }\n\n /**\n * @notice Gets oracle and enabled status by asset address\n * @param asset asset address\n * @param role Oracle role\n * @return oracle Oracle address based on role\n * @return enabled Enabled flag of the oracle based on token config\n */\n function getOracle(address asset, OracleRole role) public view returns (address oracle, bool enabled) {\n oracle = tokenConfigs[asset].oracles[uint256(role)];\n enabled = tokenConfigs[asset].enableFlagsForOracles[uint256(role)];\n }\n\n function _getPrice(address asset) internal view returns (uint256) {\n uint256 pivotPrice = INVALID_PRICE;\n\n // Get pivot oracle price, Invalid price if not available or error\n (address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);\n if (pivotOracleEnabled && pivotOracle != address(0)) {\n try OracleInterface(pivotOracle).getPrice(asset) returns (uint256 pricePivot) {\n pivotPrice = pricePivot;\n } catch {}\n }\n\n // Compare main price and pivot price, return main price and if validation was successful\n // note: In case pivot oracle is not available but main price is available and\n // validation is successful, the main oracle price is returned.\n (uint256 mainPrice, bool validatedPivotMain) = _getMainOraclePrice(\n asset,\n pivotPrice,\n pivotOracleEnabled && pivotOracle != address(0)\n );\n if (mainPrice != INVALID_PRICE && validatedPivotMain) return mainPrice;\n\n // Compare fallback and pivot if main oracle comparision fails with pivot\n // Return fallback price when fallback price is validated successfully with pivot oracle\n (uint256 fallbackPrice, bool validatedPivotFallback) = _getFallbackOraclePrice(asset, pivotPrice);\n if (fallbackPrice != INVALID_PRICE && validatedPivotFallback) return fallbackPrice;\n\n // Lastly compare main price and fallback price\n if (\n mainPrice != INVALID_PRICE &&\n fallbackPrice != INVALID_PRICE &&\n boundValidator.validatePriceWithAnchorPrice(asset, mainPrice, fallbackPrice)\n ) {\n return mainPrice;\n }\n\n revert(\"invalid resilient oracle price\");\n }\n\n /**\n * @notice Gets a price for the provided asset\n * @dev This function won't revert when price is 0, because the fallback oracle may still be\n * able to fetch a correct price\n * @param asset asset address\n * @param pivotPrice Pivot oracle price\n * @param pivotEnabled If pivot oracle is not empty and enabled\n * @return price USD price in scaled decimals\n * e.g. asset decimals is 8 then price is returned as 10**18 * 10**(18-8) = 10**28 decimals\n * @return pivotValidated Boolean representing if the validation of main oracle price\n * and pivot oracle price were successful\n * @custom:error Invalid price error is thrown if main oracle fails to fetch price of the asset\n * @custom:error Invalid price error is thrown if main oracle is not enabled or main oracle\n * address is null\n */\n function _getMainOraclePrice(\n address asset,\n uint256 pivotPrice,\n bool pivotEnabled\n ) internal view returns (uint256, bool) {\n (address mainOracle, bool mainOracleEnabled) = getOracle(asset, OracleRole.MAIN);\n if (mainOracleEnabled && mainOracle != address(0)) {\n try OracleInterface(mainOracle).getPrice(asset) returns (uint256 mainOraclePrice) {\n if (!pivotEnabled) {\n return (mainOraclePrice, true);\n }\n if (pivotPrice == INVALID_PRICE) {\n return (mainOraclePrice, false);\n }\n return (\n mainOraclePrice,\n boundValidator.validatePriceWithAnchorPrice(asset, mainOraclePrice, pivotPrice)\n );\n } catch {\n return (INVALID_PRICE, false);\n }\n }\n\n return (INVALID_PRICE, false);\n }\n\n /**\n * @dev This function won't revert when the price is 0 because getPrice checks if price is > 0\n * @param asset asset address\n * @return price USD price in 18 decimals\n * @return pivotValidated Boolean representing if the validation of fallback oracle price\n * and pivot oracle price were successfully\n * @custom:error Invalid price error is thrown if fallback oracle fails to fetch price of the asset\n * @custom:error Invalid price error is thrown if fallback oracle is not enabled or fallback oracle\n * address is null\n */\n function _getFallbackOraclePrice(address asset, uint256 pivotPrice) private view returns (uint256, bool) {\n (address fallbackOracle, bool fallbackEnabled) = getOracle(asset, OracleRole.FALLBACK);\n if (fallbackEnabled && fallbackOracle != address(0)) {\n try OracleInterface(fallbackOracle).getPrice(asset) returns (uint256 fallbackOraclePrice) {\n if (pivotPrice == INVALID_PRICE) {\n return (fallbackOraclePrice, false);\n }\n return (\n fallbackOraclePrice,\n boundValidator.validatePriceWithAnchorPrice(asset, fallbackOraclePrice, pivotPrice)\n );\n } catch {\n return (INVALID_PRICE, false);\n }\n }\n\n return (INVALID_PRICE, false);\n }\n\n /**\n * @dev This function returns the underlying asset of a vToken\n * @param vToken vToken address\n * @return asset underlying asset address\n */\n function _getUnderlyingAsset(address vToken) private view notNullAddress(vToken) returns (address asset) {\n if (vToken == nativeMarket) {\n asset = NATIVE_TOKEN_ADDR;\n } else if (vToken == vai) {\n asset = vai;\n } else {\n asset = VBep20Interface(vToken).underlying();\n }\n }\n}\n"
120
120
  },
121
121
  "@venusprotocol/solidity-utilities/contracts/constants.sol": {
122
122
  "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/// @dev Base unit for computations, usually used in scaling (multiplications, divisions)\nuint256 constant EXP_SCALE = 1e18;\n\n/// @dev A unit (literal one) in EXP_SCALE, usually used in additions/subtractions\nuint256 constant MANTISSA_ONE = EXP_SCALE;\n\n/// @dev The approximate number of seconds per year\nuint256 constant SECONDS_PER_YEAR = 31_536_000;\n"
@@ -146,7 +146,7 @@
146
146
  "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IPoolRegistry {\n /// @notice Get VToken in the Pool for an Asset\n function getVTokenForAsset(address comptroller, address asset) external view returns (address);\n\n /// @notice Get the addresss of the Pools supported that include a market for the provided asset\n function getPoolsSupportedByAsset(address asset) external view returns (address[] memory);\n}\n"
147
147
  },
148
148
  "contracts/Interfaces/IProtocolShareReserve.sol": {
149
- "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IProtocolShareReserve {\n /// @notice it represents the type of vToken income\n enum IncomeType {\n SPREAD,\n LIQUIDATION\n }\n\n function updateAssetsState(\n address comptroller,\n address asset,\n IncomeType incomeType\n ) external;\n}\n"
149
+ "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\ninterface IProtocolShareReserve {\n /// @notice it represents the type of vToken income\n enum IncomeType {\n SPREAD,\n LIQUIDATION,\n ERC4626_WRAPPER_REWARDS,\n FLASHLOAN\n }\n\n function updateAssetsState(\n address comptroller,\n address asset,\n IncomeType incomeType\n ) external;\n}\n"
150
150
  },
151
151
  "contracts/Interfaces/IRiskFund.sol": {
152
152
  "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/**\n * @title IRiskFund\n * @author Venus\n * @notice Interface implemented by `RiskFund`.\n */\ninterface IRiskFund {\n function transferReserveForAuction(address comptroller, uint256 amount) external returns (uint256);\n\n function updatePoolState(\n address comptroller,\n address asset,\n uint256 amount\n ) external;\n\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256);\n}\n\n/**\n * @title IRiskFundGetters\n * @author Venus\n * @notice Interface implemented by `RiskFund` for getter methods.\n */\ninterface IRiskFundGetters {\n function convertibleBaseAsset() external view returns (address);\n}\n"
@@ -2284,7 +2284,7 @@
2284
2284
  ]
2285
2285
  },
2286
2286
  "ProtocolShareReserve_Implementation": {
2287
- "address": "0x6B2D272CD89585BCE8404006f366a77680324F7d",
2287
+ "address": "0xFde46857B36881d69F742D44Aa5bF81e8f8dcF94",
2288
2288
  "abi": [
2289
2289
  {
2290
2290
  "inputs": [
@@ -7,7 +7,7 @@
7
7
  "ConverterNetwork_Proxy": "0x2F6672C9A0988748b0172D97961BecfD9DC6D6d5",
8
8
  "DefaultProxyAdmin": "0xF6fF3e9459227f0cDE8B102b90bE25960317b216",
9
9
  "ProtocolShareReserve": "0xF9263eaF7eB50815194f26aCcAB6765820B13D41",
10
- "ProtocolShareReserve_Implementation": "0x6B2D272CD89585BCE8404006f366a77680324F7d",
10
+ "ProtocolShareReserve_Implementation": "0xFde46857B36881d69F742D44Aa5bF81e8f8dcF94",
11
11
  "ProtocolShareReserve_Proxy": "0xF9263eaF7eB50815194f26aCcAB6765820B13D41",
12
12
  "SingleTokenConverterBeacon": "0x993900Ab4ef4092e5B76d4781D09A2732086F0F0",
13
13
  "SingleTokenConverterImp": "0x07801d54906Be49517DfDEd26c89A81fb94e504B",