diff --git a/deployments/bscmainnet.json b/deployments/bscmainnet.json index e906baee3..5af34f202 100644 --- a/deployments/bscmainnet.json +++ b/deployments/bscmainnet.json @@ -45346,6 +45346,80 @@ } ] }, + "VToken_vTWT_DeFi": { + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "beacon", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ] + }, "VToken_vUSDD_DeFi": { "address": "0xA615467caE6B9E0bb98BC04B4411d9296fd1dFa0", "abi": [ diff --git a/deployments/bscmainnet/VToken_vTWT_DeFi.json b/deployments/bscmainnet/VToken_vTWT_DeFi.json new file mode 100644 index 000000000..d6c592211 --- /dev/null +++ b/deployments/bscmainnet/VToken_vTWT_DeFi.json @@ -0,0 +1,246 @@ +{ + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "beacon", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "receipt": { + "to": null, + "from": "0x03862dFa5D0be8F64509C001cb8C6188194469DF", + "contractAddress": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "transactionIndex": 96, + "gasUsed": "652784", + "logsBloom": "0x00000000000400000000001000000000000001000000000000800000000000200000000000000040000400020000000000000000000000000000000840048000001000000000000080000000001000000001000002040000000000080000002000002000020004000080000000000800000002000000000000000000000000400000000000000000000000000000080200000000080080100000000000000000000000001100000100000000000400000000000000800000000000000000004000000004000000000002020200040000000000000000000000c40000000060100040000000000000000000800000000400000800000000000000000000010000", + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3", + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "logs": [ + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": [ + "0x1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e", + "0x0000000000000000000000002b8a1c539abac89cbf7e2bc6987a0a38a5e660d4" + ], + "data": "0x", + "logIndex": 250, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000003862dfa5d0be8f64509c001cb8c6188194469df" + ], + "data": "0x", + "logIndex": 251, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": ["0x66fd58e82f7b31a2a5c30e0888f3093efe4e111b00cd2b0c31fe014601293aa0"], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000004788629abc6cfca10f9f969efdeaa1cf70c23555", + "logIndex": 252, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": [ + "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000003344417c9360b963ca93a4e8305361aede340ab9" + ], + "data": "0x", + "logIndex": 253, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": [ + "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000035dacdbfa83369d9edac586c65ff4aba850f1dba" + ], + "data": "0x", + "logIndex": 254, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": ["0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460"], + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003782dace9d90000", + "logIndex": 255, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": [ + "0x6dbf1ff28f860de5edafa4c6505e37c0aba213288cc4166c5352b6d3776c79ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001" + ], + "data": "0x", + "logIndex": 256, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": [ + "0xafec95c8612496c3ecf5dddc71e393528fe29bd145fbaf9c6b496d78d7e2d79b", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000f322942f644a996a617bd29c16bd7d231d9f35e9" + ], + "data": "0x", + "logIndex": 257, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x00000000000000000000000003862dfa5d0be8f64509c001cb8c6188194469df", + "0x000000000000000000000000939bd8d64c0a9583a7dcea9933f7b21697ab6396" + ], + "data": "0x", + "logIndex": 258, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + }, + { + "transactionIndex": 96, + "blockNumber": 31162123, + "transactionHash": "0xbae5da60656c114b0ae8d9ca5cbf16a5f5761d1924d6c6544901237601191457", + "address": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", + "topics": ["0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498"], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 259, + "blockHash": "0x4791c2c3d90774c4e72b96c5b59ec0647cef329a1019f8c94a13922ed96ff2e3" + } + ], + "blockNumber": 31162123, + "cumulativeGasUsed": "11208263", + "status": 1, + "byzantium": true + }, + "args": [ + "0x2b8A1C539ABaC89CbF7E2Bc6987A0A38A5e660D4", + "0x8a42c3190000000000000000000000004b0f1812e5df2a09796481ff14017e60055080030000000000000000000000003344417c9360b963ca93a4e8305361aede340ab900000000000000000000000035dacdbfa83369d9edac586c65ff4aba850f1dba0000000000000000000000000000000000000000204fce5e3e25026110000000000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000939bd8d64c0a9583a7dcea9933f7b21697ab63960000000000000000000000004788629abc6cfca10f9f969efdeaa1cf70c235550000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f322942f644a996a617bd29c16bd7d231d9f35e900000000000000000000000000000000000000000000000003782dace9d90000000000000000000000000000000000000000000000000000000000000000001056656e75732054575420284465466929000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009765457545f446546690000000000000000000000000000000000000000000000" + ], + "numDeployments": 1, + "solcInputHash": "fe42e787f43c7b3c0c64f0274853de01", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't conflict with the storage layout of the implementation behind the proxy. _Available since v3.4._\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"details\":\"Initializes the proxy with `beacon`. If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. Requirements: - `beacon` must be a contract with the interface {IBeacon}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\":\"BeaconProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/interfaces/IERC1967.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\\n *\\n * _Available since v4.8.3._\\n */\\ninterface IERC1967 {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Emitted when the beacon is changed.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n}\\n\",\"keccak256\":\"0x3cbef5ebc24b415252e2f8c0c9254555d30d9f085603b4b80d9b5ed20ab87e90\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/draft-IERC1822.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822Proxiable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x1d4afe6cb24200cc4545eed814ecf5847277dfe5d613a1707aad5fceecebcfff\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeacon.sol\\\";\\nimport \\\"../../interfaces/IERC1967.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/StorageSlot.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n */\\nabstract contract ERC1967Upgrade is IERC1967 {\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(Address.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(\\n Address.isContract(IBeacon(newBeacon).implementation()),\\n \\\"ERC1967: beacon implementation is not a contract\\\"\\n );\\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b21ae06bf5957f73fa16754b0669c77b7abd8ba6c072d35c3281d446fdb86c2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\\n * be specified by overriding the virtual {_implementation} function.\\n *\\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\\n * different contract through the {_delegate} function.\\n *\\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\\n */\\nabstract contract Proxy {\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal virtual {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n /**\\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\\n * and {_fallback} should delegate.\\n */\\n function _implementation() internal view virtual returns (address);\\n\\n /**\\n * @dev Delegates the current call to the address returned by `_implementation()`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _fallback() internal virtual {\\n _beforeFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\\n * is empty.\\n */\\n receive() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\\n * call, or as part of the Solidity `fallback` or `receive` functions.\\n *\\n * If overridden should call `super._beforeFallback()`.\\n */\\n function _beforeFallback() internal virtual {}\\n}\\n\",\"keccak256\":\"0xc130fe33f1b2132158531a87734153293f6d07bc263ff4ac90e85da9c82c0e27\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IBeacon.sol\\\";\\nimport \\\"../Proxy.sol\\\";\\nimport \\\"../ERC1967/ERC1967Upgrade.sol\\\";\\n\\n/**\\n * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.\\n *\\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\\n * conflict with the storage layout of the implementation behind the proxy.\\n *\\n * _Available since v3.4._\\n */\\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\\n /**\\n * @dev Initializes the proxy with `beacon`.\\n *\\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\\n * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity\\n * constructor.\\n *\\n * Requirements:\\n *\\n * - `beacon` must be a contract with the interface {IBeacon}.\\n */\\n constructor(address beacon, bytes memory data) payable {\\n _upgradeBeaconToAndCall(beacon, data, false);\\n }\\n\\n /**\\n * @dev Returns the current beacon address.\\n */\\n function _beacon() internal view virtual returns (address) {\\n return _getBeacon();\\n }\\n\\n /**\\n * @dev Returns the current implementation address of the associated beacon.\\n */\\n function _implementation() internal view virtual override returns (address) {\\n return IBeacon(_getBeacon()).implementation();\\n }\\n\\n /**\\n * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\\n *\\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\\n *\\n * Requirements:\\n *\\n * - `beacon` must be a contract.\\n * - The implementation returned by `beacon` must be a contract.\\n */\\n function _setBeacon(address beacon, bytes memory data) internal virtual {\\n _upgradeBeaconToAndCall(beacon, data, false);\\n }\\n}\\n\",\"keccak256\":\"0x85439e74ab467b6a23d45d32bdc9506cbc3760320289afd605f11638c4138e95\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/beacon/IBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeacon {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n *\\n * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)\\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```solidity\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._\\n * _Available since v4.9 for `string`, `bytes`._\\n */\\nlibrary StorageSlot {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n struct StringSlot {\\n string value;\\n }\\n\\n struct BytesSlot {\\n bytes value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `StringSlot` with member `value` located at `slot`.\\n */\\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\\n */\\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := store.slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BytesSlot` with member `value` located at `slot`.\\n */\\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\\n */\\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := store.slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf09e68aa0dc6722a25bc46490e8d48ed864466d17313b8a0b254c36b54e49899\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405260405161091438038061091483398101604081905261002291610463565b61002e82826000610035565b505061058d565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610523565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610523565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108ed602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe919061053e565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c95782516000036103c2576001600160a01b0385163b6103c25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d3565b6103d383836103db565b949350505050565b8151156103eb5781518083602001fd5b8060405162461bcd60e51b8152600401610169919061055a565b80516001600160a01b038116811461041c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561045257818101518382015260200161043a565b838111156100f95750506000910152565b6000806040838503121561047657600080fd5b61047f83610405565b60208401519092506001600160401b038082111561049c57600080fd5b818501915085601f8301126104b057600080fd5b8151818111156104c2576104c2610421565b604051601f8201601f19908116603f011681019083821181831017156104ea576104ea610421565b8160405282815288602084870101111561050357600080fd5b610514836020830160208801610437565b80955050505050509250929050565b60006020828403121561053557600080fd5b6102c882610405565b60008251610550818460208701610437565b9190910192915050565b6020815260008251806020840152610579816040850160208701610437565b601f01601f19169190910160400192915050565b6103518061059c6000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f560279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061024c565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a5565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b60608315610210578251600003610209576001600160a01b0385163b6102095760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b508161021a565b61021a8383610222565b949350505050565b8151156102325781518083602001fd5b8060405162461bcd60e51b815260040161020091906102c1565b60006020828403121561025e57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b83811015610290578181015183820152602001610278565b8381111561029f576000848401525b50505050565b600082516102b7818460208701610275565b9190910192915050565b60208152600082518060208401526102e0816040850160208701610275565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220fe297b55fecce116ce1eb9330ed9a20786628fb8686af0694c83f972893aa55a64736f6c634300080d0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564", + "deployedBytecode": "0x60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f560279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061024c565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a5565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b60608315610210578251600003610209576001600160a01b0385163b6102095760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b508161021a565b61021a8383610222565b949350505050565b8151156102325781518083602001fd5b8060405162461bcd60e51b815260040161020091906102c1565b60006020828403121561025e57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b83811015610290578181015183820152602001610278565b8381111561029f576000848401525b50505050565b600082516102b7818460208701610275565b9190910192915050565b60208152600082518060208401526102e0816040850160208701610275565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220fe297b55fecce116ce1eb9330ed9a20786628fb8686af0694c83f972893aa55a64736f6c634300080d0033", + "devdoc": { + "details": "This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't conflict with the storage layout of the implementation behind the proxy. _Available since v3.4._", + "kind": "dev", + "methods": { + "constructor": { + "details": "Initializes the proxy with `beacon`. If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. Requirements: - `beacon` must be a contract with the interface {IBeacon}." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} diff --git a/deployments/bscmainnet/solcInputs/ad7e39c529776ba8e663b9883415bfcf.json b/deployments/bscmainnet/solcInputs/ad7e39c529776ba8e663b9883415bfcf.json new file mode 100644 index 000000000..e56a09c99 --- /dev/null +++ b/deployments/bscmainnet/solcInputs/ad7e39c529776ba8e663b9883415bfcf.json @@ -0,0 +1,285 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./OwnableUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides 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} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n function __Ownable2Step_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.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/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {\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 function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\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 /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized != type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n return _status == _ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n using AddressUpgradeable for address;\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to\n * 0 before setting it to a non-zero value.\n */\n function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n * Revert on invalid signature.\n */\n function safePermit(\n IERC20PermitUpgradeable token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return\n success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\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 ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\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 /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n /**\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n * address.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy.\n */\n function proxiableUUID() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC1967.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\n *\n * _Available since v4.8.3._\n */\ninterface IERC1967 {\n /**\n * @dev Emitted when the implementation is upgraded.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Emitted when the admin account has changed.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Emitted when the beacon is changed.\n */\n event BeaconUpgraded(address indexed beacon);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../Proxy.sol\";\nimport \"../ERC1967/ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.\n *\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\n * conflict with the storage layout of the implementation behind the proxy.\n *\n * _Available since v3.4._\n */\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\n /**\n * @dev Initializes the proxy with `beacon`.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\n * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity\n * constructor.\n *\n * Requirements:\n *\n * - `beacon` must be a contract with the interface {IBeacon}.\n */\n constructor(address beacon, bytes memory data) payable {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n\n /**\n * @dev Returns the current beacon address.\n */\n function _beacon() internal view virtual returns (address) {\n return _getBeacon();\n }\n\n /**\n * @dev Returns the current implementation address of the associated beacon.\n */\n function _implementation() internal view virtual override returns (address) {\n return IBeacon(_getBeacon()).implementation();\n }\n\n /**\n * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\n *\n * Requirements:\n *\n * - `beacon` must be a contract.\n * - The implementation returned by `beacon` must be a contract.\n */\n function _setBeacon(address beacon, bytes memory data) internal virtual {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n /**\n * @dev Must return an address that can be used as a delegate call target.\n *\n * {BeaconProxy} will check that this address is a contract.\n */\n function implementation() external view returns (address);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../../access/Ownable.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their\n * implementation contract, which is where they will delegate all function calls.\n *\n * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.\n */\ncontract UpgradeableBeacon is IBeacon, Ownable {\n address private _implementation;\n\n /**\n * @dev Emitted when the implementation returned by the beacon is changed.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the\n * beacon.\n */\n constructor(address implementation_) {\n _setImplementation(implementation_);\n }\n\n /**\n * @dev Returns the current implementation address.\n */\n function implementation() public view virtual override returns (address) {\n return _implementation;\n }\n\n /**\n * @dev Upgrades the beacon to a new implementation.\n *\n * Emits an {Upgraded} event.\n *\n * Requirements:\n *\n * - msg.sender must be the owner of the contract.\n * - `newImplementation` must be a contract.\n */\n function upgradeTo(address newImplementation) public virtual onlyOwner {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation contract address for this beacon\n *\n * Requirements:\n *\n * - `newImplementation` must be a contract.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"UpgradeableBeacon: implementation is not a contract\");\n _implementation = newImplementation;\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/IERC1967.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n */\nabstract contract ERC1967Upgrade is IERC1967 {\n // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation address.\n */\n function _getImplementation() internal view returns (address) {\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 implementation slot.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n }\n\n /**\n * @dev Perform implementation upgrade\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Perform implementation upgrade with additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {\n _upgradeTo(newImplementation);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(newImplementation, data);\n }\n }\n\n /**\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {\n // Upgrades from old implementations will perform a rollback test. This test requires the new\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n // this special case will break upgrade paths from old UUPS implementation to new ones.\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n _setImplementation(newImplementation);\n } else {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n } catch {\n revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n }\n _upgradeToAndCall(newImplementation, data, forceCall);\n }\n }\n\n /**\n * @dev Storage slot with the admin of the contract.\n * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /**\n * @dev Returns the current admin.\n */\n function _getAdmin() internal view returns (address) {\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 admin slot.\n */\n function _setAdmin(address newAdmin) private {\n require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n */\n function _changeAdmin(address newAdmin) internal {\n emit AdminChanged(_getAdmin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n */\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n /**\n * @dev Returns the current beacon.\n */\n function _getBeacon() internal view returns (address) {\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n }\n\n /**\n * @dev Stores a new beacon in the EIP1967 beacon slot.\n */\n function _setBeacon(address newBeacon) private {\n require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n require(\n Address.isContract(IBeacon(newBeacon).implementation()),\n \"ERC1967: beacon implementation is not a contract\"\n );\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n }\n\n /**\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n *\n * Emits a {BeaconUpgraded} event.\n */\n function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {\n _setBeacon(newBeacon);\n emit BeaconUpgraded(newBeacon);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n /**\n * @dev Delegates the current call to `implementation`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _delegate(address implementation) internal virtual {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n /**\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n * and {_fallback} should delegate.\n */\n function _implementation() internal view virtual returns (address);\n\n /**\n * @dev Delegates the current call to the address returned by `_implementation()`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _fallback() internal virtual {\n _beforeFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n * function in the contract matches the call data.\n */\n fallback() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n * is empty.\n */\n receive() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n * call, or as part of the Solidity `fallback` or `receive` functions.\n *\n * If overridden should call `super._beforeFallback()`.\n */\n function _beforeFallback() internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(address from, address to, uint256 amount) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n // decrementing then incrementing.\n _balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n unchecked {\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n _balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n // Overflow not possible: amount <= accountBalance <= totalSupply.\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(address owner, address spender, uint256 amount) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1, \"Math: mulDiv overflow\");\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/utils/StorageSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._\n * _Available since v4.9 for `string`, `bytes`._\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := store.slot\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toString(int256 value) internal pure returns (string memory) {\n return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return keccak256(bytes(a)) == keccak256(bytes(b));\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title Venus Access Control Contract.\n * @dev The AccessControlledV8 contract is a wrapper around the OpenZeppelin AccessControl contract\n * It provides a standardized way to control access to methods within the Venus Smart Contract Ecosystem.\n * The contract allows the owner to set an AccessControlManager contract address.\n * It can restrict method calls based on the sender's role and the method's signature.\n */\n\nabstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {\n /// @notice Access control manager contract\n IAccessControlManagerV8 private _accessControlManager;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when access control manager contract address is changed\n event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);\n\n /// @notice Thrown when the action is prohibited by AccessControlManager\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Sets the address of AccessControlManager\n * @dev Admin function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n * @custom:event Emits NewAccessControlManager event\n * @custom:access Only Governance\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Returns the address of the access control manager contract\n */\n function accessControlManager() external view returns (IAccessControlManagerV8) {\n return _accessControlManager;\n }\n\n /**\n * @dev Internal function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n */\n function _setAccessControlManager(address accessControlManager_) internal {\n require(address(accessControlManager_) != address(0), \"invalid acess control manager address\");\n address oldAccessControlManager = address(_accessControlManager);\n _accessControlManager = IAccessControlManagerV8(accessControlManager_);\n emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);\n }\n\n /**\n * @notice Reverts if the call is not allowed by AccessControlManager\n * @param signature Method signature\n */\n function _checkAccessAllowed(string memory signature) internal view {\n bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title Venus Access Control Contract\n * @author venus\n * @dev This contract is a wrapper of OpenZeppelin AccessControl\n *\t\textending it in a way to standartize access control\n *\t\twithin Venus Smart Contract Ecosystem\n */\ncontract AccessControlManager is AccessControl, IAccessControlManagerV8 {\n /// @notice Emitted when an account is given a permission to a certain contract function\n /// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and\n /// can call any contract function with this signature\n event PermissionGranted(address account, address contractAddress, string functionSig);\n\n /// @notice Emitted when an account is revoked a permission to a certain contract function\n event PermissionRevoked(address account, address contractAddress, string functionSig);\n\n constructor() {\n // Grant the contract deployer the default admin role: it will be able\n // to grant and revoke any roles\n _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n /**\n * @notice Gives a function call permission to one single account\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * @param contractAddress address of contract for which call permissions will be granted\n * @dev if contractAddress is zero address, the account can access the specified function\n * on **any** contract managed by this ACL\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @param accountToPermit account that will be given access to the contract function\n * @custom:event Emits a {RoleGranted} and {PermissionGranted} events.\n */\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n grantRole(role, accountToPermit);\n emit PermissionGranted(accountToPermit, contractAddress, functionSig);\n }\n\n /**\n * @notice Revokes an account's permission to a particular function call\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * \t\tMay emit a {RoleRevoked} event.\n * @param contractAddress address of contract for which call permissions will be revoked\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.\n */\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n revokeRole(role, accountToRevoke);\n emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender\n * @param account for which call permissions will be checked\n * @param functionSig restricted function signature e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n *\n */\n function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));\n\n if (hasRole(role, account)) {\n return true;\n } else {\n role = keccak256(abi.encodePacked(address(0), functionSig));\n return hasRole(role, account);\n }\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.\n * @param account for which call permissions will be checked against\n * @param contractAddress address of the restricted contract\n * @param functionSig signature of the restricted function e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n */\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n return hasRole(role, account);\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/FeedRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface FeedRegistryInterface {\n function latestRoundDataByName(\n string memory base,\n string memory quote\n )\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n function decimalsByName(string memory base, string memory quote) external view returns (uint8);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface OracleInterface {\n function getPrice(address asset) external view returns (uint256);\n}\n\ninterface ResilientOracleInterface is OracleInterface {\n function updatePrice(address vToken) external;\n\n function updateAssetPrice(address asset) external;\n\n function getUnderlyingPrice(address vToken) external view returns (uint256);\n}\n\ninterface TwapInterface is OracleInterface {\n function updateTwap(address asset) external returns (uint256);\n}\n\ninterface BoundValidatorInterface {\n function validatePriceWithAnchorPrice(\n address asset,\n uint256 reporterPrice,\n uint256 anchorPrice\n ) external view returns (bool);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/PublicResolverInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.13;\n\ninterface PublicResolverInterface {\n function addr(bytes32 node) external view returns (address payable);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/SIDRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.13;\n\ninterface SIDRegistryInterface {\n function resolver(bytes32 node) external view returns (address);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/VBep20Interface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\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" + }, + "@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/SIDRegistryInterface.sol\";\nimport \"../interfaces/FeedRegistryInterface.sol\";\nimport \"../interfaces/PublicResolverInterface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport \"../interfaces/OracleInterface.sol\";\n\n/**\n * @title BinanceOracle\n * @author Venus\n * @notice This oracle fetches price of assets from Binance.\n */\ncontract BinanceOracle is AccessControlledV8, OracleInterface {\n address public sidRegistryAddress;\n\n /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Max stale period configuration for assets\n mapping(string => uint256) public maxStalePeriod;\n\n /// @notice Override symbols to be compatible with Binance feed registry\n mapping(string => string) public symbols;\n\n event MaxStalePeriodAdded(string indexed asset, uint256 maxStalePeriod);\n\n event SymbolOverridden(string indexed symbol, string overriddenSymbol);\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 /// @notice Constructor for the implementation contract.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Used to set the max stale period of an asset\n * @param symbol The symbol of the asset\n * @param _maxStalePeriod The max stake period\n */\n function setMaxStalePeriod(string memory symbol, uint256 _maxStalePeriod) external {\n _checkAccessAllowed(\"setMaxStalePeriod(string,uint256)\");\n if (_maxStalePeriod == 0) revert(\"stale period can't be zero\");\n if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n maxStalePeriod[symbol] = _maxStalePeriod;\n emit MaxStalePeriodAdded(symbol, _maxStalePeriod);\n }\n\n /**\n * @notice Used to override a symbol when fetching price\n * @param symbol The symbol to override\n * @param overrideSymbol The symbol after override\n */\n function setSymbolOverride(string calldata symbol, string calldata overrideSymbol) external {\n _checkAccessAllowed(\"setSymbolOverride(string,string)\");\n if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n symbols[symbol] = overrideSymbol;\n emit SymbolOverridden(symbol, overrideSymbol);\n }\n\n /**\n * @notice Sets the contracts required to fetch prices\n * @param _sidRegistryAddress Address of SID registry\n * @param _accessControlManager Address of the access control manager contract\n */\n function initialize(\n address _sidRegistryAddress,\n address _accessControlManager\n ) external initializer notNullAddress(_sidRegistryAddress) {\n sidRegistryAddress = _sidRegistryAddress;\n __AccessControlled_init(_accessControlManager);\n }\n\n /**\n * @notice Uses Space ID to fetch the feed registry address\n * @return feedRegistryAddress Address of binance oracle feed registry.\n */\n function getFeedRegistryAddress() public view returns (address) {\n bytes32 nodeHash = 0x94fe3821e0768eb35012484db4df61890f9a6ca5bfa984ef8ff717e73139faff;\n\n SIDRegistryInterface sidRegistry = SIDRegistryInterface(sidRegistryAddress);\n address publicResolverAddress = sidRegistry.resolver(nodeHash);\n PublicResolverInterface publicResolver = PublicResolverInterface(publicResolverAddress);\n\n return publicResolver.addr(nodeHash);\n }\n\n /**\n * @notice Gets the price of a asset from the binance oracle\n * @param asset Address of the asset\n * @return Price in USD\n */\n function getPrice(address asset) public view returns (uint256) {\n string memory symbol;\n uint256 decimals;\n\n if (asset == BNB_ADDR) {\n symbol = \"BNB\";\n decimals = 18;\n } else {\n IERC20Metadata token = IERC20Metadata(asset);\n symbol = token.symbol();\n decimals = token.decimals();\n }\n\n string memory overrideSymbol = symbols[symbol];\n\n if (bytes(overrideSymbol).length != 0) {\n symbol = overrideSymbol;\n }\n\n return _getPrice(symbol, decimals);\n }\n\n function _getPrice(string memory symbol, uint256 decimals) internal view returns (uint256) {\n FeedRegistryInterface feedRegistry = FeedRegistryInterface(getFeedRegistryAddress());\n\n (, int256 answer, , uint256 updatedAt, ) = feedRegistry.latestRoundDataByName(symbol, \"USD\");\n if (answer <= 0) revert(\"invalid binance oracle price\");\n if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n uint256 deltaTime;\n unchecked {\n deltaTime = block.timestamp - updatedAt;\n }\n if (deltaTime > maxStalePeriod[symbol]) revert(\"binance oracle price expired\");\n\n uint256 decimalDelta = feedRegistry.decimalsByName(symbol, \"USD\");\n return (uint256(answer) * (10 ** (18 - decimalDelta))) * (10 ** (18 - decimals));\n }\n}\n" + }, + "@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\n/**\n * @title ChainlinkOracle\n * @author Venus\n * @notice This oracle fetches prices of assets from the Chainlink oracle.\n */\ncontract ChainlinkOracle is AccessControlledV8, OracleInterface {\n struct TokenConfig {\n /// @notice Underlying token address, which can't be a null address\n /// @notice Used to check if a token is supported\n /// @notice 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB for BNB\n address asset;\n /// @notice Chainlink feed address\n address feed;\n /// @notice Price expiration period of this asset\n uint256 maxStalePeriod;\n }\n\n /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Manually set an override price, useful under extenuating conditions such as price feed failure\n mapping(address => uint256) public prices;\n\n /// @notice Token config by assets\n mapping(address => TokenConfig) public tokenConfigs;\n\n /// @notice Emit when a price is manually set\n event PricePosted(address indexed asset, uint256 previousPriceMantissa, uint256 newPriceMantissa);\n\n /// @notice Emit when a token config is added\n event TokenConfigAdded(address indexed asset, address feed, uint256 maxStalePeriod);\n\n modifier notNullAddress(address someone) {\n if (someone == address(0)) revert(\"can't be zero address\");\n _;\n }\n\n /// @notice Constructor for the implementation contract.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Manually set the price of a given asset\n * @param asset Asset address\n * @param price Asset price in 18 decimals\n * @custom:access Only Governance\n * @custom:event Emits PricePosted event on succesfully setup of asset price\n */\n function setDirectPrice(address asset, uint256 price) external notNullAddress(asset) {\n _checkAccessAllowed(\"setDirectPrice(address,uint256)\");\n\n uint256 previousPriceMantissa = prices[asset];\n prices[asset] = price;\n emit PricePosted(asset, previousPriceMantissa, price);\n }\n\n /**\n * @notice Add multiple token configs at the same time\n * @param tokenConfigs_ config array\n * @custom:access Only Governance\n * @custom:error Zero length error thrown, if length of the array in parameter 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 Initializes the owner of the contract\n * @param accessControlManager_ Address of the access control manager contract\n */\n function initialize(address accessControlManager_) external initializer {\n __AccessControlled_init(accessControlManager_);\n }\n\n /**\n * @notice Add single token config. asset & feed cannot be null addresses and maxStalePeriod must be positive\n * @param tokenConfig Token config struct\n * @custom:access Only Governance\n * @custom:error NotNullAddress error is thrown if asset address is null\n * @custom:error NotNullAddress error is thrown if token feed address is null\n * @custom:error Range error is thrown if maxStale period of token is not greater than zero\n * @custom:event Emits TokenConfigAdded event on succesfully setting of the token config\n */\n function setTokenConfig(\n TokenConfig memory tokenConfig\n ) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.feed) {\n _checkAccessAllowed(\"setTokenConfig(TokenConfig)\");\n\n if (tokenConfig.maxStalePeriod == 0) revert(\"stale period can't be zero\");\n tokenConfigs[tokenConfig.asset] = tokenConfig;\n emit TokenConfigAdded(tokenConfig.asset, tokenConfig.feed, tokenConfig.maxStalePeriod);\n }\n\n /**\n * @notice Gets the price of a asset from the chainlink oracle\n * @param asset Address of the asset\n * @return Price in USD from Chainlink or a manually set price for the asset\n */\n function getPrice(address asset) public view returns (uint256) {\n uint256 decimals;\n\n if (asset == BNB_ADDR) {\n decimals = 18;\n } else {\n IERC20Metadata token = IERC20Metadata(asset);\n decimals = token.decimals();\n }\n\n return _getPriceInternal(asset, decimals);\n }\n\n /**\n * @notice Gets the Chainlink price for a given asset\n * @param asset address of the asset\n * @param decimals decimals of the asset\n * @return price Asset price in USD or a manually set price of the asset\n */\n function _getPriceInternal(address asset, uint256 decimals) internal view returns (uint256 price) {\n uint256 tokenPrice = prices[asset];\n if (tokenPrice != 0) {\n price = tokenPrice;\n } else {\n price = _getChainlinkPrice(asset);\n }\n\n uint256 decimalDelta = 18 - decimals;\n return price * (10 ** decimalDelta);\n }\n\n /**\n * @notice Get the Chainlink price for an asset, revert if token config doesn't exist\n * @dev The precision of the price feed is used to ensure the returned price has 18 decimals of precision\n * @param asset Address of the asset\n * @return price Price in USD, with 18 decimals of precision\n * @custom:error NotNullAddress error is thrown if the asset address is null\n * @custom:error Price error is thrown if the Chainlink price of asset is not greater than zero\n * @custom:error Timing error is thrown if current timestamp is less than the last updatedAt timestamp\n * @custom:error Timing error is thrown if time difference between current time and last updated time\n * is greater than maxStalePeriod\n */\n function _getChainlinkPrice(\n address asset\n ) private view notNullAddress(tokenConfigs[asset].asset) returns (uint256) {\n TokenConfig memory tokenConfig = tokenConfigs[asset];\n AggregatorV3Interface feed = AggregatorV3Interface(tokenConfig.feed);\n\n // note: maxStalePeriod cannot be 0\n uint256 maxStalePeriod = tokenConfig.maxStalePeriod;\n\n // Chainlink USD-denominated feeds store answers at 8 decimals, mostly\n uint256 decimalDelta = 18 - feed.decimals();\n\n (, int256 answer, , uint256 updatedAt, ) = feed.latestRoundData();\n if (answer <= 0) revert(\"chainlink price must be positive\");\n if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n uint256 deltaTime;\n unchecked {\n deltaTime = block.timestamp - updatedAt;\n }\n\n if (deltaTime > maxStalePeriod) revert(\"chainlink price expired\");\n\n return uint256(answer) * (10 ** decimalDelta);\n }\n}\n" + }, + "contracts/BaseJumpRateModelV2.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\n\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { EXP_SCALE, MANTISSA_ONE } from \"./lib/constants.sol\";\n\n/**\n * @title Logic for Compound's JumpRateModel Contract V2.\n * @author Compound (modified by Dharma Labs, Arr00 and Venus)\n * @notice An interest rate model with a steep increase after a certain utilization threshold called **kink** is reached.\n * The parameters of this interest rate model can be adjusted by the owner. Version 2 modifies Version 1 by enabling updateable parameters.\n */\nabstract contract BaseJumpRateModelV2 is InterestRateModel {\n /**\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\n */\n uint256 public immutable blocksPerYear;\n /**\n * @notice The address of the AccessControlManager contract\n */\n IAccessControlManagerV8 public accessControlManager;\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public baseRatePerBlock;\n\n /**\n * @notice The multiplier per block after hitting a specified utilization point\n */\n uint256 public jumpMultiplierPerBlock;\n\n /**\n * @notice The utilization point at which the jump multiplier is applied\n */\n uint256 public kink;\n\n event NewInterestParams(\n uint256 baseRatePerBlock,\n uint256 multiplierPerBlock,\n uint256 jumpMultiplierPerBlock,\n uint256 kink\n );\n\n /**\n * @notice Thrown when the action is prohibited by AccessControlManager\n */\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n /**\n * @notice Construct an interest rate model\n * @param blocksPerYear_ The approximate number of blocks per year that is assumed by the interest rate model.\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @param accessControlManager_ The address of the AccessControlManager contract\n */\n constructor(\n uint256 blocksPerYear_,\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n IAccessControlManagerV8 accessControlManager_\n ) {\n require(address(accessControlManager_) != address(0), \"invalid ACM address\");\n require(blocksPerYear_ != 0, \"Invalid blocks per year\");\n accessControlManager = accessControlManager_;\n blocksPerYear = blocksPerYear_;\n\n _updateJumpRateModel(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @custom:error Unauthorized if the sender is not allowed to call this function\n * @custom:access Controlled by AccessControlManager\n */\n function updateJumpRateModel(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) external virtual {\n string memory signature = \"updateJumpRateModel(uint256,uint256,uint256,uint256)\";\n bool isAllowedToCall = accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n\n _updateJumpRateModel(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) public view virtual override returns (uint256) {\n uint256 oneMinusReserveFactor = MANTISSA_ONE - reserveFactorMantissa;\n uint256 borrowRate = _getBorrowRate(cash, borrows, reserves, badDebt);\n uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / EXP_SCALE;\n uint256 incomeToDistribute = borrows * rateToPool;\n uint256 supply = cash + borrows + badDebt - reserves;\n return incomeToDistribute / supply;\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `(borrows + badDebt) / (cash + borrows + badDebt - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @param badDebt The amount of badDebt in the market\n * @return The utilization rate as a mantissa between [0, MANTISSA_ONE]\n */\n function utilizationRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public pure returns (uint256) {\n // Utilization rate is 0 when there are no borrows and badDebt\n if ((borrows + badDebt) == 0) {\n return 0;\n }\n\n uint256 rate = ((borrows + badDebt) * EXP_SCALE) / (cash + borrows + badDebt - reserves);\n\n if (rate > EXP_SCALE) {\n rate = EXP_SCALE;\n }\n\n return rate;\n }\n\n /**\n * @notice Internal function to update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n */\n function _updateJumpRateModel(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) internal {\n baseRatePerBlock = baseRatePerYear / blocksPerYear;\n multiplierPerBlock = multiplierPerYear / blocksPerYear;\n jumpMultiplierPerBlock = jumpMultiplierPerYear / blocksPerYear;\n kink = kink_;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function _getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) internal view returns (uint256) {\n uint256 util = utilizationRate(cash, borrows, reserves, badDebt);\n uint256 kink_ = kink;\n\n if (util <= kink_) {\n return ((util * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n }\n uint256 normalRate = ((kink_ * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n uint256 excessUtil;\n unchecked {\n excessUtil = util - kink_;\n }\n return ((excessUtil * jumpMultiplierPerBlock) / EXP_SCALE) + normalRate;\n }\n}\n" + }, + "contracts/Comptroller.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { ComptrollerStorage } from \"./ComptrollerStorage.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\nimport { MaxLoopsLimitHelper } from \"./MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title Comptroller\n * @author Venus\n * @notice The Comptroller is designed to provide checks for all minting, redeeming, transferring, borrowing, lending, repaying, liquidating,\n * and seizing done by the `vToken` contract. Each pool has one `Comptroller` checking these interactions across markets. When a user interacts\n * with a given market by one of these main actions, a call is made to a corresponding hook in the associated `Comptroller`, which either allows\n * or reverts the transaction. These hooks also update supply and borrow rewards as they are called. The comptroller holds the logic for assessing\n * liquidity snapshots of an account via the collateral factor and liquidation threshold. This check determines the collateral needed for a borrow,\n * as well as how much of a borrow may be liquidated. A user may borrow a portion of their collateral with the maximum amount determined by the\n * markets collateral factor. However, if their borrowed amount exceeds an amount calculated using the market’s corresponding liquidation threshold,\n * the borrow is eligible for liquidation.\n *\n * The `Comptroller` also includes two functions `liquidateAccount()` and `healAccount()`, which are meant to handle accounts that do not exceed\n * the `minLiquidatableCollateral` for the `Comptroller`:\n *\n * - `healAccount()`: This function is called to seize all of a given user’s collateral, requiring the `msg.sender` repay a certain percentage\n * of the debt calculated by `collateral/(borrows*liquidationIncentive)`. The function can only be called if the calculated percentage does not exceed\n * 100%, because otherwise no `badDebt` would be created and `liquidateAccount()` should be used instead. The difference in the actual amount of debt\n * and debt paid off is recorded as `badDebt` for each market, which can then be auctioned off for the risk reserves of the associated pool.\n * - `liquidateAccount()`: This function can only be called if the collateral seized will cover all borrows of an account, as well as the liquidation\n * incentive. Otherwise, the pool will incur bad debt, in which case the function `healAccount()` should be used instead. This function skips the logic\n * verifying that the repay amount does not exceed the close factor.\n */\ncontract Comptroller is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n ComptrollerStorage,\n ComptrollerInterface,\n ExponentialNoError,\n MaxLoopsLimitHelper\n{\n // PoolRegistry, immutable to save on gas\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable poolRegistry;\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(VToken indexed vToken, address indexed account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(VToken indexed vToken, address indexed account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint256 oldCloseFactorMantissa, uint256 newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(VToken vToken, uint256 oldCollateralFactorMantissa, uint256 newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation threshold is changed by admin\n event NewLiquidationThreshold(\n VToken vToken,\n uint256 oldLiquidationThresholdMantissa,\n uint256 newLiquidationThresholdMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint256 oldLiquidationIncentiveMantissa, uint256 newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(ResilientOracleInterface oldPriceOracle, ResilientOracleInterface newPriceOracle);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPausedMarket(VToken vToken, Action action, bool pauseState);\n\n /// @notice Emitted when borrow cap for a vToken is changed\n event NewBorrowCap(VToken indexed vToken, uint256 newBorrowCap);\n\n /// @notice Emitted when the collateral threshold (in USD) for non-batch liquidations is changed\n event NewMinLiquidatableCollateral(uint256 oldMinLiquidatableCollateral, uint256 newMinLiquidatableCollateral);\n\n /// @notice Emitted when supply cap for a vToken is changed\n event NewSupplyCap(VToken indexed vToken, uint256 newSupplyCap);\n\n /// @notice Emitted when a rewards distributor is added\n event NewRewardsDistributor(address indexed rewardsDistributor, address indexed rewardToken);\n\n /// @notice Emitted when a market is supported\n event MarketSupported(VToken vToken);\n\n /// @notice Thrown when collateral factor exceeds the upper bound\n error InvalidCollateralFactor();\n\n /// @notice Thrown when liquidation threshold exceeds the collateral factor\n error InvalidLiquidationThreshold();\n\n /// @notice Thrown when the action is only available to specific sender, but the real sender was different\n error UnexpectedSender(address expectedSender, address actualSender);\n\n /// @notice Thrown when the oracle returns an invalid price for some asset\n error PriceError(address vToken);\n\n /// @notice Thrown if VToken unexpectedly returned a nonzero error code while trying to get account snapshot\n error SnapshotError(address vToken, address user);\n\n /// @notice Thrown when the market is not listed\n error MarketNotListed(address market);\n\n /// @notice Thrown when a market has an unexpected comptroller\n error ComptrollerMismatch();\n\n /// @notice Thrown when user is not member of market\n error MarketNotCollateral(address vToken, address user);\n\n /**\n * @notice Thrown during the liquidation if user's total collateral amount is lower than\n * a predefined threshold. In this case only batch liquidations (either liquidateAccount\n * or healAccount) are available.\n */\n error MinimalCollateralViolated(uint256 expectedGreaterThan, uint256 actual);\n error CollateralExceedsThreshold(uint256 expectedLessThanOrEqualTo, uint256 actual);\n error InsufficientCollateral(uint256 collateralToSeize, uint256 availableCollateral);\n\n /// @notice Thrown when the account doesn't have enough liquidity to redeem or borrow\n error InsufficientLiquidity();\n\n /// @notice Thrown when trying to liquidate a healthy account\n error InsufficientShortfall();\n\n /// @notice Thrown when trying to repay more than allowed by close factor\n error TooMuchRepay();\n\n /// @notice Thrown if the user is trying to exit a market in which they have an outstanding debt\n error NonzeroBorrowBalance();\n\n /// @notice Thrown when trying to perform an action that is paused\n error ActionPaused(address market, Action action);\n\n /// @notice Thrown when trying to add a market that is already listed\n error MarketAlreadyListed(address market);\n\n /// @notice Thrown if the supply cap is exceeded\n error SupplyCapExceeded(address market, uint256 cap);\n\n /// @notice Thrown if the borrow cap is exceeded\n error BorrowCapExceeded(address market, uint256 cap);\n\n /// @param poolRegistry_ Pool registry address\n /// @custom:oz-upgrades-unsafe-allow constructor\n /// @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n constructor(address poolRegistry_) {\n ensureNonzeroAddress(poolRegistry_);\n\n poolRegistry = poolRegistry_;\n _disableInitializers();\n }\n\n /**\n * @param loopLimit Limit for the loops can iterate to avoid the DOS\n * @param accessControlManager Access control manager contract address\n */\n function initialize(uint256 loopLimit, address accessControlManager) external initializer {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager);\n\n _setMaxLoopsLimit(loopLimit);\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation; enabling them to be used as collateral\n * @param vTokens The list of addresses of the vToken markets to be enabled\n * @return errors An array of NO_ERROR for compatibility with Venus core tooling\n * @custom:event MarketEntered is emitted for each market on success\n * @custom:error ActionPaused error is thrown if entering any of the markets is paused\n * @custom:error MarketNotListed error is thrown if any of the markets is not listed\n * @custom:access Not restricted\n */\n function enterMarkets(address[] memory vTokens) external override returns (uint256[] memory) {\n uint256 len = vTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i; i < len; ++i) {\n VToken vToken = VToken(vTokens[i]);\n\n _addToMarket(vToken, msg.sender);\n results[i] = NO_ERROR;\n }\n\n return results;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation; disabling them as collateral\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing necessary collateral for an outstanding borrow.\n * @param vTokenAddress The address of the asset to be removed\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event MarketExited is emitted on success\n * @custom:error ActionPaused error is thrown if exiting the market is paused\n * @custom:error NonzeroBorrowBalance error is thrown if the user has an outstanding borrow in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if exiting the market would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function exitMarket(address vTokenAddress) external override returns (uint256) {\n _checkActionPauseState(vTokenAddress, Action.EXIT_MARKET);\n VToken vToken = VToken(vTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the vToken */\n (uint256 tokensHeld, uint256 amountOwed, ) = _safeGetAccountSnapshot(vToken, msg.sender);\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n revert NonzeroBorrowBalance();\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n _checkRedeemAllowed(vTokenAddress, msg.sender, tokensHeld);\n\n Market storage marketToExit = markets[address(vToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return NO_ERROR;\n }\n\n /* Set vToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete vToken from the account’s list of assets */\n // load into memory for faster iteration\n VToken[] memory userAssetList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n\n uint256 assetIndex = len;\n for (uint256 i; i < len; ++i) {\n if (userAssetList[i] == vToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n VToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.pop();\n\n emit MarketExited(vToken, msg.sender);\n\n return NO_ERROR;\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param vToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @custom:error ActionPaused error is thrown if supplying to this market is paused\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error SupplyCapExceeded error is thrown if the total supply exceeds the cap after minting\n * @custom:access Not restricted\n */\n function preMintHook(address vToken, address minter, uint256 mintAmount) external override {\n _checkActionPauseState(vToken, Action.MINT);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n uint256 supplyCap = supplyCaps[vToken];\n // Skipping the cap check for uncapped coins to save some gas\n if (supplyCap != type(uint256).max) {\n uint256 vTokenSupply = VToken(vToken).totalSupply();\n Exp memory exchangeRate = Exp({ mantissa: VToken(vToken).exchangeRateStored() });\n uint256 nextTotalSupply = mul_ScalarTruncateAddUInt(exchangeRate, vTokenSupply, mintAmount);\n if (nextTotalSupply > supplyCap) {\n revert SupplyCapExceeded(vToken, supplyCap);\n }\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, minter);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param vToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of vTokens to exchange for the underlying asset in the market\n * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function preRedeemHook(address vToken, address redeemer, uint256 redeemTokens) external override {\n _checkActionPauseState(vToken, Action.REDEEM);\n\n _checkRedeemAllowed(vToken, redeemer, redeemTokens);\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, redeemer);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param vToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @custom:error ActionPaused error is thrown if borrowing is paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if there is not enough collateral to borrow\n * @custom:error BorrowCapExceeded is thrown if the borrow cap will be exceeded should this borrow succeed\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted if vToken is enabled as collateral, otherwise only vToken\n */\n /// disable-eslint\n function preBorrowHook(address vToken, address borrower, uint256 borrowAmount) external override {\n _checkActionPauseState(vToken, Action.BORROW);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n if (!markets[vToken].accountMembership[borrower]) {\n // only vTokens may call borrowAllowed if borrower not in market\n _checkSenderIs(vToken);\n\n // attempt to add borrower to the market or revert\n _addToMarket(VToken(msg.sender), borrower);\n }\n\n // Update the prices of tokens\n updatePrices(borrower);\n\n if (oracle.getUnderlyingPrice(vToken) == 0) {\n revert PriceError(address(vToken));\n }\n\n uint256 borrowCap = borrowCaps[vToken];\n // Skipping the cap check for uncapped coins to save some gas\n if (borrowCap != type(uint256).max) {\n uint256 totalBorrows = VToken(vToken).totalBorrows();\n uint256 badDebt = VToken(vToken).badDebt();\n uint256 nextTotalBorrows = totalBorrows + borrowAmount + badDebt;\n if (nextTotalBorrows > borrowCap) {\n revert BorrowCapExceeded(vToken, borrowCap);\n }\n }\n\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n borrower,\n VToken(vToken),\n 0,\n borrowAmount,\n _getCollateralFactor\n );\n\n if (snapshot.shortfall > 0) {\n revert InsufficientLiquidity();\n }\n\n Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param vToken The market to verify the repay against\n * @param borrower The account which would borrowed the asset\n * @custom:error ActionPaused error is thrown if repayments are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:access Not restricted\n */\n function preRepayHook(address vToken, address borrower) external override {\n _checkActionPauseState(vToken, Action.REPAY);\n\n oracle.updatePrice(vToken);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param vTokenBorrowed Asset which was borrowed by the borrower\n * @param vTokenCollateral Asset which was used as collateral and will be seized\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n * @param skipLiquidityCheck Allows the borrow to be liquidated regardless of the account liquidity\n * @custom:error ActionPaused error is thrown if liquidations are paused in this market\n * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n * @custom:error TooMuchRepay error is thrown if the liquidator is trying to repay more than allowed by close factor\n * @custom:error MinimalCollateralViolated is thrown if the users' total collateral is lower than the threshold for non-batch liquidations\n * @custom:error InsufficientShortfall is thrown when trying to liquidate a healthy account\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n */\n function preLiquidateHook(\n address vTokenBorrowed,\n address vTokenCollateral,\n address borrower,\n uint256 repayAmount,\n bool skipLiquidityCheck\n ) external override {\n // Pause Action.LIQUIDATE on BORROWED TOKEN to prevent liquidating it.\n // If we want to pause liquidating to vTokenCollateral, we should pause\n // Action.SEIZE on it\n _checkActionPauseState(vTokenBorrowed, Action.LIQUIDATE);\n\n // Update the prices of tokens\n updatePrices(borrower);\n\n if (!markets[vTokenBorrowed].isListed) {\n revert MarketNotListed(address(vTokenBorrowed));\n }\n if (!markets[vTokenCollateral].isListed) {\n revert MarketNotListed(address(vTokenCollateral));\n }\n\n uint256 borrowBalance = VToken(vTokenBorrowed).borrowBalanceStored(borrower);\n\n /* Allow accounts to be liquidated if the market is deprecated or it is a forced liquidation */\n if (skipLiquidityCheck || isDeprecated(VToken(vTokenBorrowed))) {\n if (repayAmount > borrowBalance) {\n revert TooMuchRepay();\n }\n return;\n }\n\n /* The borrower must have shortfall and collateral > threshold in order to be liquidatable */\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral <= minLiquidatableCollateral) {\n /* The liquidator should use either liquidateAccount or healAccount */\n revert MinimalCollateralViolated(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 maxClose = mul_ScalarTruncate(Exp({ mantissa: closeFactorMantissa }), borrowBalance);\n if (repayAmount > maxClose) {\n revert TooMuchRepay();\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param vTokenCollateral Asset which was used as collateral and will be seized\n * @param seizerContract Contract that tries to seize the asset (either borrowed vToken or Comptroller)\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @custom:error ActionPaused error is thrown if seizing this type of collateral is paused\n * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n * @custom:error ComptrollerMismatch error is when seizer contract or seized asset belong to different pools\n * @custom:access Not restricted\n */\n function preSeizeHook(\n address vTokenCollateral,\n address seizerContract,\n address liquidator,\n address borrower\n ) external override {\n // Pause Action.SEIZE on COLLATERAL to prevent seizing it.\n // If we want to pause liquidating vTokenBorrowed, we should pause\n // Action.LIQUIDATE on it\n _checkActionPauseState(vTokenCollateral, Action.SEIZE);\n\n Market storage market = markets[vTokenCollateral];\n\n if (!market.isListed) {\n revert MarketNotListed(vTokenCollateral);\n }\n\n if (seizerContract == address(this)) {\n // If Comptroller is the seizer, just check if collateral's comptroller\n // is equal to the current address\n if (address(VToken(vTokenCollateral).comptroller()) != address(this)) {\n revert ComptrollerMismatch();\n }\n } else {\n // If the seizer is not the Comptroller, check that the seizer is a\n // listed market, and that the markets' comptrollers match\n if (!markets[seizerContract].isListed) {\n revert MarketNotListed(seizerContract);\n }\n if (VToken(vTokenCollateral).comptroller() != VToken(seizerContract).comptroller()) {\n revert ComptrollerMismatch();\n }\n }\n\n if (!market.accountMembership[borrower]) {\n revert MarketNotCollateral(vTokenCollateral, borrower);\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vTokenCollateral);\n rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, borrower);\n rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, liquidator);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param vToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of vTokens to transfer\n * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function preTransferHook(address vToken, address src, address dst, uint256 transferTokens) external override {\n _checkActionPauseState(vToken, Action.TRANSFER);\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n _checkRedeemAllowed(vToken, src, transferTokens);\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, src);\n rewardsDistributor.distributeSupplierRewardToken(vToken, dst);\n }\n }\n\n /*** Pool-level operations ***/\n\n /**\n * @notice Seizes all the remaining collateral, makes msg.sender repay the existing\n * borrows, and treats the rest of the debt as bad debt (for each market).\n * The sender has to repay a certain percentage of the debt, computed as\n * collateral / (borrows * liquidationIncentive).\n * @param user account to heal\n * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for healing\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function healAccount(address user) external {\n VToken[] memory userAssets = accountAssets[user];\n uint256 userAssetsCount = userAssets.length;\n\n address liquidator = msg.sender;\n {\n ResilientOracleInterface oracle_ = oracle;\n // We need all user's markets to be fresh for the computations to be correct\n for (uint256 i; i < userAssetsCount; ++i) {\n userAssets[i].accrueInterest();\n oracle_.updatePrice(address(userAssets[i]));\n }\n }\n\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(user, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral > minLiquidatableCollateral) {\n revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n // percentage = collateral / (borrows * liquidation incentive)\n Exp memory collateral = Exp({ mantissa: snapshot.totalCollateral });\n Exp memory scaledBorrows = mul_(\n Exp({ mantissa: snapshot.borrows }),\n Exp({ mantissa: liquidationIncentiveMantissa })\n );\n\n Exp memory percentage = div_(collateral, scaledBorrows);\n if (lessThanExp(Exp({ mantissa: MANTISSA_ONE }), percentage)) {\n revert CollateralExceedsThreshold(scaledBorrows.mantissa, collateral.mantissa);\n }\n\n for (uint256 i; i < userAssetsCount; ++i) {\n VToken market = userAssets[i];\n\n (uint256 tokens, uint256 borrowBalance, ) = _safeGetAccountSnapshot(market, user);\n uint256 repaymentAmount = mul_ScalarTruncate(percentage, borrowBalance);\n\n // Seize the entire collateral\n if (tokens != 0) {\n market.seize(liquidator, user, tokens);\n }\n // Repay a certain percentage of the borrow, forgive the rest\n if (borrowBalance != 0) {\n market.healBorrow(liquidator, user, repaymentAmount);\n }\n }\n }\n\n /**\n * @notice Liquidates all borrows of the borrower. Callable only if the collateral is less than\n * a predefined threshold, and the account collateral can be seized to cover all borrows. If\n * the collateral is higher than the threshold, use regular liquidations. If the collateral is\n * below the threshold, and the account is insolvent, use healAccount.\n * @param borrower the borrower address\n * @param orders an array of liquidation orders\n * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for a batch liquidation\n * @custom:error InsufficientCollateral error is thrown when there is not enough collateral to cover the debt\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function liquidateAccount(address borrower, LiquidationOrder[] calldata orders) external {\n // We will accrue interest and update the oracle prices later during the liquidation\n\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral > minLiquidatableCollateral) {\n // You should use the regular vToken.liquidateBorrow(...) call\n revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n uint256 collateralToSeize = mul_ScalarTruncate(\n Exp({ mantissa: liquidationIncentiveMantissa }),\n snapshot.borrows\n );\n if (collateralToSeize >= snapshot.totalCollateral) {\n // There is not enough collateral to seize. Use healBorrow to repay some part of the borrow\n // and record bad debt.\n revert InsufficientCollateral(collateralToSeize, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n uint256 ordersCount = orders.length;\n\n _ensureMaxLoops(ordersCount / 2);\n\n for (uint256 i; i < ordersCount; ++i) {\n if (!markets[address(orders[i].vTokenBorrowed)].isListed) {\n revert MarketNotListed(address(orders[i].vTokenBorrowed));\n }\n if (!markets[address(orders[i].vTokenCollateral)].isListed) {\n revert MarketNotListed(address(orders[i].vTokenCollateral));\n }\n\n LiquidationOrder calldata order = orders[i];\n order.vTokenBorrowed.forceLiquidateBorrow(\n msg.sender,\n borrower,\n order.repayAmount,\n order.vTokenCollateral,\n true\n );\n }\n\n VToken[] memory borrowMarkets = accountAssets[borrower];\n uint256 marketsCount = borrowMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n (, uint256 borrowBalance, ) = _safeGetAccountSnapshot(borrowMarkets[i], borrower);\n require(borrowBalance == 0, \"Nonzero borrow balance after liquidation\");\n }\n }\n\n /**\n * @notice Sets the closeFactor to use when liquidating borrows\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @custom:event Emits NewCloseFactor on success\n * @custom:access Controlled by AccessControlManager\n */\n function setCloseFactor(uint256 newCloseFactorMantissa) external {\n _checkAccessAllowed(\"setCloseFactor(uint256)\");\n require(MAX_CLOSE_FACTOR_MANTISSA >= newCloseFactorMantissa, \"Close factor greater than maximum close factor\");\n require(MIN_CLOSE_FACTOR_MANTISSA <= newCloseFactorMantissa, \"Close factor smaller than minimum close factor\");\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, newCloseFactorMantissa);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev This function is restricted by the AccessControlManager\n * @param vToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @param newLiquidationThresholdMantissa The new liquidation threshold, scaled by 1e18\n * @custom:event Emits NewCollateralFactor when collateral factor is updated\n * and NewLiquidationThreshold when liquidation threshold is updated\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InvalidCollateralFactor error is thrown when collateral factor is too high\n * @custom:error InvalidLiquidationThreshold error is thrown when liquidation threshold is lower than collateral factor\n * @custom:error PriceError is thrown when the oracle returns an invalid price for the asset\n * @custom:access Controlled by AccessControlManager\n */\n function setCollateralFactor(\n VToken vToken,\n uint256 newCollateralFactorMantissa,\n uint256 newLiquidationThresholdMantissa\n ) external {\n _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n\n // Verify market is listed\n Market storage market = markets[address(vToken)];\n if (!market.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n // Check collateral factor <= 0.9\n if (newCollateralFactorMantissa > MAX_COLLATERAL_FACTOR_MANTISSA) {\n revert InvalidCollateralFactor();\n }\n\n // Ensure that liquidation threshold <= 1\n if (newLiquidationThresholdMantissa > MANTISSA_ONE) {\n revert InvalidLiquidationThreshold();\n }\n\n // Ensure that liquidation threshold >= CF\n if (newLiquidationThresholdMantissa < newCollateralFactorMantissa) {\n revert InvalidLiquidationThreshold();\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(address(vToken)) == 0) {\n revert PriceError(address(vToken));\n }\n\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n if (newCollateralFactorMantissa != oldCollateralFactorMantissa) {\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n emit NewCollateralFactor(vToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n }\n\n uint256 oldLiquidationThresholdMantissa = market.liquidationThresholdMantissa;\n if (newLiquidationThresholdMantissa != oldLiquidationThresholdMantissa) {\n market.liquidationThresholdMantissa = newLiquidationThresholdMantissa;\n emit NewLiquidationThreshold(vToken, oldLiquidationThresholdMantissa, newLiquidationThresholdMantissa);\n }\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev This function is restricted by the AccessControlManager\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @custom:event Emits NewLiquidationIncentive on success\n * @custom:access Controlled by AccessControlManager\n */\n function setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) external {\n require(newLiquidationIncentiveMantissa >= MANTISSA_ONE, \"liquidation incentive should be greater than 1e18\");\n\n _checkAccessAllowed(\"setLiquidationIncentive(uint256)\");\n\n // Save current value for use in log\n uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Only callable by the PoolRegistry\n * @param vToken The address of the market (token) to list\n * @custom:error MarketAlreadyListed is thrown if the market is already listed in this pool\n * @custom:access Only PoolRegistry\n */\n function supportMarket(VToken vToken) external {\n _checkSenderIs(poolRegistry);\n\n if (markets[address(vToken)].isListed) {\n revert MarketAlreadyListed(address(vToken));\n }\n\n require(vToken.isVToken(), \"Comptroller: Invalid vToken\"); // Sanity check to make sure its really a VToken\n\n Market storage newMarket = markets[address(vToken)];\n newMarket.isListed = true;\n newMarket.collateralFactorMantissa = 0;\n newMarket.liquidationThresholdMantissa = 0;\n\n _addMarket(address(vToken));\n\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n rewardsDistributors[i].initializeMarket(address(vToken));\n }\n\n emit MarketSupported(vToken);\n }\n\n /**\n * @notice Set the given borrow caps for the given vToken markets. Borrowing that brings total borrows to or above borrow cap will revert.\n * @dev This function is restricted by the AccessControlManager\n * @dev A borrow cap of type(uint256).max corresponds to unlimited borrowing.\n * @dev Borrow caps smaller than the current total borrows are accepted. This way, new borrows will not be allowed\n until the total borrows amount goes below the new borrow cap\n * @param vTokens The addresses of the markets (tokens) to change the borrow caps for\n * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited borrowing.\n * @custom:access Controlled by AccessControlManager\n */\n function setMarketBorrowCaps(VToken[] calldata vTokens, uint256[] calldata newBorrowCaps) external {\n _checkAccessAllowed(\"setMarketBorrowCaps(address[],uint256[])\");\n\n uint256 numMarkets = vTokens.length;\n uint256 numBorrowCaps = newBorrowCaps.length;\n\n require(numMarkets != 0 && numMarkets == numBorrowCaps, \"invalid input\");\n\n _ensureMaxLoops(numMarkets);\n\n for (uint256 i; i < numMarkets; ++i) {\n borrowCaps[address(vTokens[i])] = newBorrowCaps[i];\n emit NewBorrowCap(vTokens[i], newBorrowCaps[i]);\n }\n }\n\n /**\n * @notice Set the given supply caps for the given vToken markets. Supply that brings total Supply to or above supply cap will revert.\n * @dev This function is restricted by the AccessControlManager\n * @dev A supply cap of type(uint256).max corresponds to unlimited supply.\n * @dev Supply caps smaller than the current total supplies are accepted. This way, new supplies will not be allowed\n until the total supplies amount goes below the new supply cap\n * @param vTokens The addresses of the markets (tokens) to change the supply caps for\n * @param newSupplyCaps The new supply cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited supply.\n * @custom:access Controlled by AccessControlManager\n */\n function setMarketSupplyCaps(VToken[] calldata vTokens, uint256[] calldata newSupplyCaps) external {\n _checkAccessAllowed(\"setMarketSupplyCaps(address[],uint256[])\");\n uint256 vTokensCount = vTokens.length;\n\n require(vTokensCount != 0, \"invalid number of markets\");\n require(vTokensCount == newSupplyCaps.length, \"invalid number of markets\");\n\n _ensureMaxLoops(vTokensCount);\n\n for (uint256 i; i < vTokensCount; ++i) {\n supplyCaps[address(vTokens[i])] = newSupplyCaps[i];\n emit NewSupplyCap(vTokens[i], newSupplyCaps[i]);\n }\n }\n\n /**\n * @notice Pause/unpause specified actions\n * @dev This function is restricted by the AccessControlManager\n * @param marketsList Markets to pause/unpause the actions on\n * @param actionsList List of action ids to pause/unpause\n * @param paused The new paused state (true=paused, false=unpaused)\n * @custom:access Controlled by AccessControlManager\n */\n function setActionsPaused(VToken[] calldata marketsList, Action[] calldata actionsList, bool paused) external {\n _checkAccessAllowed(\"setActionsPaused(address[],uint256[],bool)\");\n\n uint256 marketsCount = marketsList.length;\n uint256 actionsCount = actionsList.length;\n\n _ensureMaxLoops(marketsCount * actionsCount);\n\n for (uint256 marketIdx; marketIdx < marketsCount; ++marketIdx) {\n for (uint256 actionIdx; actionIdx < actionsCount; ++actionIdx) {\n _setActionPaused(address(marketsList[marketIdx]), actionsList[actionIdx], paused);\n }\n }\n }\n\n /**\n * @notice Set the given collateral threshold for non-batch liquidations. Regular liquidations\n * will fail if the collateral amount is less than this threshold. Liquidators should use batch\n * operations like liquidateAccount or healAccount.\n * @dev This function is restricted by the AccessControlManager\n * @param newMinLiquidatableCollateral The new min liquidatable collateral (in USD).\n * @custom:access Controlled by AccessControlManager\n */\n function setMinLiquidatableCollateral(uint256 newMinLiquidatableCollateral) external {\n _checkAccessAllowed(\"setMinLiquidatableCollateral(uint256)\");\n\n uint256 oldMinLiquidatableCollateral = minLiquidatableCollateral;\n minLiquidatableCollateral = newMinLiquidatableCollateral;\n emit NewMinLiquidatableCollateral(oldMinLiquidatableCollateral, newMinLiquidatableCollateral);\n }\n\n /**\n * @notice Add a new RewardsDistributor and initialize it with all markets. We can add several RewardsDistributor\n * contracts with the same rewardToken, and there could be overlaping among them considering the last reward block\n * @dev Only callable by the admin\n * @param _rewardsDistributor Address of the RewardDistributor contract to add\n * @custom:access Only Governance\n * @custom:event Emits NewRewardsDistributor with distributor address\n */\n function addRewardsDistributor(RewardsDistributor _rewardsDistributor) external onlyOwner {\n require(!rewardsDistributorExists[address(_rewardsDistributor)], \"already exists\");\n\n uint256 rewardsDistributorsLen = rewardsDistributors.length;\n _ensureMaxLoops(rewardsDistributorsLen + 1);\n\n rewardsDistributors.push(_rewardsDistributor);\n rewardsDistributorExists[address(_rewardsDistributor)] = true;\n\n uint256 marketsCount = allMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n _rewardsDistributor.initializeMarket(address(allMarkets[i]));\n }\n\n emit NewRewardsDistributor(address(_rewardsDistributor), address(_rewardsDistributor.rewardToken()));\n }\n\n /**\n * @notice Sets a new price oracle for the Comptroller\n * @dev Only callable by the admin\n * @param newOracle Address of the new price oracle to set\n * @custom:event Emits NewPriceOracle on success\n * @custom:error ZeroAddressNotAllowed is thrown when the new oracle address is zero\n */\n function setPriceOracle(ResilientOracleInterface newOracle) external onlyOwner {\n ensureNonzeroAddress(address(newOracle));\n\n ResilientOracleInterface oldOracle = oracle;\n oracle = newOracle;\n emit NewPriceOracle(oldOracle, newOracle);\n }\n\n /**\n * @notice Set the for loop iteration limit to avoid DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Determine the current account liquidity with respect to liquidation threshold requirements\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param account The account get liquidity for\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Account liquidity in excess of liquidation threshold requirements,\n * @return shortfall Account shortfall below liquidation threshold requirements\n */\n function getAccountLiquidity(\n address account\n ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getLiquidationThreshold);\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity with respect to collateral requirements\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param account The account get liquidity for\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Account liquidity in excess of collateral requirements,\n * @return shortfall Account shortfall below collateral requirements\n */\n function getBorrowingPower(\n address account\n ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getCollateralFactor);\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param vTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Hypothetical account liquidity in excess of collateral requirements,\n * @return shortfall Hypothetical account shortfall below collateral requirements\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address vTokenModify,\n uint256 redeemTokens,\n uint256 borrowAmount\n ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n account,\n VToken(vTokenModify),\n redeemTokens,\n borrowAmount,\n _getCollateralFactor\n );\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return markets The list of market addresses\n */\n function getAllMarkets() external view override returns (VToken[] memory) {\n return allMarkets;\n }\n\n /**\n * @notice Check if a market is marked as listed (active)\n * @param vToken vToken Address for the market to check\n * @return listed True if listed otherwise false\n */\n function isMarketListed(VToken vToken) external view returns (bool) {\n return markets[address(vToken)].isListed;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (VToken[] memory) {\n VToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in a given market\n * @param account The address of the account to check\n * @param vToken The vToken to check\n * @return True if the account is in the market specified, otherwise false.\n */\n function checkMembership(address account, VToken vToken) external view returns (bool) {\n return markets[address(vToken)].accountMembership[account];\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in vToken.liquidateBorrowFresh)\n * @param vTokenBorrowed The address of the borrowed vToken\n * @param vTokenCollateral The address of the collateral vToken\n * @param actualRepayAmount The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return tokensToSeize Number of vTokenCollateral tokens to be seized in a liquidation\n * @custom:error PriceError if the oracle returns an invalid price\n */\n function liquidateCalculateSeizeTokens(\n address vTokenBorrowed,\n address vTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256 error, uint256 tokensToSeize) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = _safeGetUnderlyingPrice(VToken(vTokenBorrowed));\n uint256 priceCollateralMantissa = _safeGetUnderlyingPrice(VToken(vTokenCollateral));\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint256 exchangeRateMantissa = VToken(vTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n\n numerator = mul_(Exp({ mantissa: liquidationIncentiveMantissa }), Exp({ mantissa: priceBorrowedMantissa }));\n denominator = mul_(Exp({ mantissa: priceCollateralMantissa }), Exp({ mantissa: exchangeRateMantissa }));\n ratio = div_(numerator, denominator);\n\n seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n return (NO_ERROR, seizeTokens);\n }\n\n /**\n * @notice Returns reward speed given a vToken\n * @param vToken The vToken to get the reward speeds for\n * @return rewardSpeeds Array of total supply and borrow speeds and reward token for all reward distributors\n */\n function getRewardsByMarket(address vToken) external view returns (RewardSpeeds[] memory rewardSpeeds) {\n uint256 rewardsDistributorsLength = rewardsDistributors.length;\n rewardSpeeds = new RewardSpeeds[](rewardsDistributorsLength);\n for (uint256 i; i < rewardsDistributorsLength; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n address rewardToken = address(rewardsDistributor.rewardToken());\n rewardSpeeds[i] = RewardSpeeds({\n rewardToken: rewardToken,\n supplySpeed: rewardsDistributor.rewardTokenSupplySpeeds(vToken),\n borrowSpeed: rewardsDistributor.rewardTokenBorrowSpeeds(vToken)\n });\n }\n return rewardSpeeds;\n }\n\n /**\n * @notice Return all reward distributors for this pool\n * @return Array of RewardDistributor addresses\n */\n function getRewardDistributors() external view returns (RewardsDistributor[] memory) {\n return rewardsDistributors;\n }\n\n /**\n * @notice A marker method that returns true for a valid Comptroller contract\n * @return Always true\n */\n function isComptroller() external pure override returns (bool) {\n return true;\n }\n\n /**\n * @notice Update the prices of all the tokens associated with the provided account\n * @param account Address of the account to get associated tokens with\n */\n function updatePrices(address account) public {\n VToken[] memory vTokens = accountAssets[account];\n uint256 vTokensCount = vTokens.length;\n\n ResilientOracleInterface oracle_ = oracle;\n\n for (uint256 i; i < vTokensCount; ++i) {\n oracle_.updatePrice(address(vTokens[i]));\n }\n }\n\n /**\n * @notice Checks if a certain action is paused on a market\n * @param market vToken address\n * @param action Action to check\n * @return paused True if the action is paused otherwise false\n */\n function actionPaused(address market, Action action) public view returns (bool) {\n return _actionPaused[market][action];\n }\n\n /**\n * @notice Check if a vToken market has been deprecated\n * @dev All borrows in a deprecated vToken market can be immediately liquidated\n * @param vToken The market to check if deprecated\n * @return deprecated True if the given vToken market has been deprecated\n */\n function isDeprecated(VToken vToken) public view returns (bool) {\n return\n markets[address(vToken)].collateralFactorMantissa == 0 &&\n actionPaused(address(vToken), Action.BORROW) &&\n vToken.reserveFactorMantissa() == MANTISSA_ONE;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param vToken The market to enter\n * @param borrower The address of the account to modify\n */\n function _addToMarket(VToken vToken, address borrower) internal {\n _checkActionPauseState(address(vToken), Action.ENTER_MARKET);\n Market storage marketToJoin = markets[address(vToken)];\n\n if (!marketToJoin.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n if (marketToJoin.accountMembership[borrower]) {\n // already joined\n return;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(vToken);\n\n emit MarketEntered(vToken, borrower);\n }\n\n /**\n * @notice Internal function to validate that a market hasn't already been added\n * and if it hasn't adds it\n * @param vToken The market to support\n */\n function _addMarket(address vToken) internal {\n uint256 marketsCount = allMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n if (allMarkets[i] == VToken(vToken)) {\n revert MarketAlreadyListed(vToken);\n }\n }\n allMarkets.push(VToken(vToken));\n marketsCount = allMarkets.length;\n _ensureMaxLoops(marketsCount);\n }\n\n /**\n * @dev Pause/unpause an action on a market\n * @param market Market to pause/unpause the action on\n * @param action Action id to pause/unpause\n * @param paused The new paused state (true=paused, false=unpaused)\n */\n function _setActionPaused(address market, Action action, bool paused) internal {\n require(markets[market].isListed, \"cannot pause a market that is not listed\");\n _actionPaused[market][action] = paused;\n emit ActionPausedMarket(VToken(market), action, paused);\n }\n\n /**\n * @dev Internal function to check that vTokens can be safely redeemed for the underlying asset.\n * @param vToken Address of the vTokens to redeem\n * @param redeemer Account redeeming the tokens\n * @param redeemTokens The number of tokens to redeem\n */\n function _checkRedeemAllowed(address vToken, address redeemer, uint256 redeemTokens) internal {\n Market storage market = markets[vToken];\n\n if (!market.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!market.accountMembership[redeemer]) {\n return;\n }\n\n // Update the prices of tokens\n updatePrices(redeemer);\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n redeemer,\n VToken(vToken),\n redeemTokens,\n 0,\n _getCollateralFactor\n );\n if (snapshot.shortfall > 0) {\n revert InsufficientLiquidity();\n }\n }\n\n /**\n * @notice Get the total collateral, weighted collateral, borrow balance, liquidity, shortfall\n * @param account The account to get the snapshot for\n * @param weight The function to compute the weight of the collateral – either collateral factor or\n * liquidation threshold. Accepts the address of the vToken and returns the weight as Exp.\n * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n * without calculating accumulated interest.\n * @return snapshot Account liquidity snapshot\n */\n function _getCurrentLiquiditySnapshot(\n address account,\n function(VToken) internal view returns (Exp memory) weight\n ) internal view returns (AccountLiquiditySnapshot memory snapshot) {\n return _getHypotheticalLiquiditySnapshot(account, VToken(address(0)), 0, 0, weight);\n }\n\n /**\n * @notice Determine what the supply/borrow balances would be if the given amounts were redeemed/borrowed\n * @param vTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @param weight The function to compute the weight of the collateral – either collateral factor or\n liquidation threshold. Accepts the address of the VToken and returns the weight\n * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n * without calculating accumulated interest.\n * @return snapshot Account liquidity snapshot\n */\n function _getHypotheticalLiquiditySnapshot(\n address account,\n VToken vTokenModify,\n uint256 redeemTokens,\n uint256 borrowAmount,\n function(VToken) internal view returns (Exp memory) weight\n ) internal view returns (AccountLiquiditySnapshot memory snapshot) {\n // For each asset the account is in\n VToken[] memory assets = accountAssets[account];\n uint256 assetsCount = assets.length;\n\n for (uint256 i; i < assetsCount; ++i) {\n VToken asset = assets[i];\n\n // Read the balances and exchange rate from the vToken\n (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) = _safeGetAccountSnapshot(\n asset,\n account\n );\n\n // Get the normalized price of the asset\n Exp memory oraclePrice = Exp({ mantissa: _safeGetUnderlyingPrice(asset) });\n\n // Pre-compute conversion factors from vTokens -> usd\n Exp memory vTokenPrice = mul_(Exp({ mantissa: exchangeRateMantissa }), oraclePrice);\n Exp memory weightedVTokenPrice = mul_(weight(asset), vTokenPrice);\n\n // weightedCollateral += weightedVTokenPrice * vTokenBalance\n snapshot.weightedCollateral = mul_ScalarTruncateAddUInt(\n weightedVTokenPrice,\n vTokenBalance,\n snapshot.weightedCollateral\n );\n\n // totalCollateral += vTokenPrice * vTokenBalance\n snapshot.totalCollateral = mul_ScalarTruncateAddUInt(vTokenPrice, vTokenBalance, snapshot.totalCollateral);\n\n // borrows += oraclePrice * borrowBalance\n snapshot.borrows = mul_ScalarTruncateAddUInt(oraclePrice, borrowBalance, snapshot.borrows);\n\n // Calculate effects of interacting with vTokenModify\n if (asset == vTokenModify) {\n // redeem effect\n // effects += tokensToDenom * redeemTokens\n snapshot.effects = mul_ScalarTruncateAddUInt(weightedVTokenPrice, redeemTokens, snapshot.effects);\n\n // borrow effect\n // effects += oraclePrice * borrowAmount\n snapshot.effects = mul_ScalarTruncateAddUInt(oraclePrice, borrowAmount, snapshot.effects);\n }\n }\n\n uint256 borrowPlusEffects = snapshot.borrows + snapshot.effects;\n // These are safe, as the underflow condition is checked first\n unchecked {\n if (snapshot.weightedCollateral > borrowPlusEffects) {\n snapshot.liquidity = snapshot.weightedCollateral - borrowPlusEffects;\n snapshot.shortfall = 0;\n } else {\n snapshot.liquidity = 0;\n snapshot.shortfall = borrowPlusEffects - snapshot.weightedCollateral;\n }\n }\n\n return snapshot;\n }\n\n /**\n * @dev Retrieves price from oracle for an asset and checks it is nonzero\n * @param asset Address for asset to query price\n * @return Underlying price\n */\n function _safeGetUnderlyingPrice(VToken asset) internal view returns (uint256) {\n uint256 oraclePriceMantissa = oracle.getUnderlyingPrice(address(asset));\n if (oraclePriceMantissa == 0) {\n revert PriceError(address(asset));\n }\n return oraclePriceMantissa;\n }\n\n /**\n * @dev Return collateral factor for a market\n * @param asset Address for asset\n * @return Collateral factor as exponential\n */\n function _getCollateralFactor(VToken asset) internal view returns (Exp memory) {\n return Exp({ mantissa: markets[address(asset)].collateralFactorMantissa });\n }\n\n /**\n * @dev Retrieves liquidation threshold for a market as an exponential\n * @param asset Address for asset to liquidation threshold\n * @return Liquidation threshold as exponential\n */\n function _getLiquidationThreshold(VToken asset) internal view returns (Exp memory) {\n return Exp({ mantissa: markets[address(asset)].liquidationThresholdMantissa });\n }\n\n /**\n * @dev Returns supply and borrow balances of user in vToken, reverts on failure\n * @param vToken Market to query\n * @param user Account address\n * @return vTokenBalance Balance of vTokens, the same as vToken.balanceOf(user)\n * @return borrowBalance Borrowed amount, including the interest\n * @return exchangeRateMantissa Stored exchange rate\n */\n function _safeGetAccountSnapshot(\n VToken vToken,\n address user\n ) internal view returns (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) {\n uint256 err;\n (err, vTokenBalance, borrowBalance, exchangeRateMantissa) = vToken.getAccountSnapshot(user);\n if (err != 0) {\n revert SnapshotError(address(vToken), user);\n }\n return (vTokenBalance, borrowBalance, exchangeRateMantissa);\n }\n\n /// @notice Reverts if the call is not from expectedSender\n /// @param expectedSender Expected transaction sender\n function _checkSenderIs(address expectedSender) internal view {\n if (msg.sender != expectedSender) {\n revert UnexpectedSender(expectedSender, msg.sender);\n }\n }\n\n /// @notice Reverts if a certain action is paused on a market\n /// @param market Market to check\n /// @param action Action to check\n function _checkActionPauseState(address market, Action action) private view {\n if (actionPaused(market, action)) {\n revert ActionPaused(market, action);\n }\n }\n}\n" + }, + "contracts/ComptrollerInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\n/**\n * @title ComptrollerInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract.\n */\ninterface ComptrollerInterface {\n /*** Assets You Are In ***/\n\n function enterMarkets(address[] calldata vTokens) external returns (uint256[] memory);\n\n function exitMarket(address vToken) external returns (uint256);\n\n /*** Policy Hooks ***/\n\n function preMintHook(address vToken, address minter, uint256 mintAmount) external;\n\n function preRedeemHook(address vToken, address redeemer, uint256 redeemTokens) external;\n\n function preBorrowHook(address vToken, address borrower, uint256 borrowAmount) external;\n\n function preRepayHook(address vToken, address borrower) external;\n\n function preLiquidateHook(\n address vTokenBorrowed,\n address vTokenCollateral,\n address borrower,\n uint256 repayAmount,\n bool skipLiquidityCheck\n ) external;\n\n function preSeizeHook(\n address vTokenCollateral,\n address vTokenBorrowed,\n address liquidator,\n address borrower\n ) external;\n\n function preTransferHook(address vToken, address src, address dst, uint256 transferTokens) external;\n\n function isComptroller() external view returns (bool);\n\n /*** Liquidity/Liquidation Calculations ***/\n\n function liquidateCalculateSeizeTokens(\n address vTokenBorrowed,\n address vTokenCollateral,\n uint256 repayAmount\n ) external view returns (uint256, uint256);\n\n function getAllMarkets() external view returns (VToken[] memory);\n}\n\n/**\n * @title ComptrollerViewInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract, including only some util view functions.\n */\ninterface ComptrollerViewInterface {\n function markets(address) external view returns (bool, uint256);\n\n function oracle() external view returns (ResilientOracleInterface);\n\n function getAssetsIn(address) external view returns (VToken[] memory);\n\n function closeFactorMantissa() external view returns (uint256);\n\n function liquidationIncentiveMantissa() external view returns (uint256);\n\n function minLiquidatableCollateral() external view returns (uint256);\n\n function getRewardDistributors() external view returns (RewardsDistributor[] memory);\n\n function getAllMarkets() external view returns (VToken[] memory);\n\n function borrowCaps(address) external view returns (uint256);\n\n function supplyCaps(address) external view returns (uint256);\n}\n" + }, + "contracts/ComptrollerStorage.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\n/**\n * @title ComptrollerStorage\n * @author Venus\n * @notice Storage layout for the `Comptroller` contract.\n */\ncontract ComptrollerStorage {\n struct LiquidationOrder {\n VToken vTokenCollateral;\n VToken vTokenBorrowed;\n uint256 repayAmount;\n }\n\n struct AccountLiquiditySnapshot {\n uint256 totalCollateral;\n uint256 weightedCollateral;\n uint256 borrows;\n uint256 effects;\n uint256 liquidity;\n uint256 shortfall;\n }\n\n struct RewardSpeeds {\n address rewardToken;\n uint256 supplySpeed;\n uint256 borrowSpeed;\n }\n\n struct Market {\n // Whether or not this market is listed\n bool isListed;\n // Multiplier representing the most one can borrow against their collateral in this market.\n // For instance, 0.9 to allow borrowing 90% of collateral value.\n // Must be between 0 and 1, and stored as a mantissa.\n uint256 collateralFactorMantissa;\n // Multiplier representing the collateralization after which the borrow is eligible\n // for liquidation. For instance, 0.8 liquidate when the borrow is 80% of collateral\n // value. Must be between 0 and collateral factor, stored as a mantissa.\n uint256 liquidationThresholdMantissa;\n // Per-market mapping of \"accounts in this asset\"\n mapping(address => bool) accountMembership;\n }\n\n enum Action {\n MINT,\n REDEEM,\n BORROW,\n REPAY,\n SEIZE,\n LIQUIDATE,\n TRANSFER,\n ENTER_MARKET,\n EXIT_MARKET\n }\n\n /**\n * @notice Oracle which gives the price of any given asset\n */\n ResilientOracleInterface public oracle;\n\n /**\n * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow\n */\n uint256 public closeFactorMantissa;\n\n /**\n * @notice Multiplier representing the discount on collateral that a liquidator receives\n */\n uint256 public liquidationIncentiveMantissa;\n\n /**\n * @notice Per-account mapping of \"assets you are in\"\n */\n mapping(address => VToken[]) public accountAssets;\n\n /**\n * @notice Official mapping of vTokens -> Market metadata\n * @dev Used e.g. to determine if a market is supported\n */\n mapping(address => Market) public markets;\n\n /// @notice A list of all markets\n VToken[] public allMarkets;\n\n /// @notice Borrow caps enforced by borrowAllowed for each vToken address. Defaults to zero which restricts borrowing.\n mapping(address => uint256) public borrowCaps;\n\n /// @notice Minimal collateral required for regular (non-batch) liquidations\n uint256 public minLiquidatableCollateral;\n\n /// @notice Supply caps enforced by mintAllowed for each vToken address. Defaults to zero which corresponds to minting not allowed\n mapping(address => uint256) public supplyCaps;\n\n /// @notice True if a certain action is paused on a certain market\n mapping(address => mapping(Action => bool)) internal _actionPaused;\n\n // List of Reward Distributors added\n RewardsDistributor[] internal rewardsDistributors;\n\n // Used to check if rewards distributor is added\n mapping(address => bool) internal rewardsDistributorExists;\n\n uint256 internal constant NO_ERROR = 0;\n\n // closeFactorMantissa must be strictly greater than this value\n uint256 internal constant MIN_CLOSE_FACTOR_MANTISSA = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant MAX_CLOSE_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant MAX_COLLATERAL_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "contracts/ErrorReporter.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title TokenErrorReporter\n * @author Venus\n * @notice Errors that can be thrown by the `VToken` contract.\n */\ncontract TokenErrorReporter {\n uint256 public constant NO_ERROR = 0; // support legacy return codes\n\n error TransferNotAllowed();\n\n error MintFreshnessCheck();\n\n error RedeemFreshnessCheck();\n error RedeemTransferOutNotPossible();\n\n error BorrowFreshnessCheck();\n error BorrowCashNotAvailable();\n\n error RepayBorrowFreshnessCheck();\n\n error HealBorrowUnauthorized();\n error ForceLiquidateBorrowUnauthorized();\n\n error LiquidateFreshnessCheck();\n error LiquidateCollateralFreshnessCheck();\n error LiquidateAccrueCollateralInterestFailed(uint256 errorCode);\n error LiquidateLiquidatorIsBorrower();\n error LiquidateCloseAmountIsZero();\n error LiquidateCloseAmountIsUintMax();\n\n error LiquidateSeizeLiquidatorIsBorrower();\n\n error ProtocolSeizeShareTooBig();\n\n error SetReserveFactorFreshCheck();\n error SetReserveFactorBoundsCheck();\n\n error AddReservesFactorFreshCheck(uint256 actualAddAmount);\n\n error ReduceReservesFreshCheck();\n error ReduceReservesCashNotAvailable();\n error ReduceReservesCashValidation();\n\n error SetInterestRateModelFreshCheck();\n}\n" + }, + "contracts/ExponentialNoError.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { EXP_SCALE as EXP_SCALE_, MANTISSA_ONE as MANTISSA_ONE_ } from \"./lib/constants.sol\";\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author Compound\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\n * `Exp({mantissa: 5100000000000000000})`.\n */\ncontract ExponentialNoError {\n struct Exp {\n uint256 mantissa;\n }\n\n struct Double {\n uint256 mantissa;\n }\n\n uint256 internal constant EXP_SCALE = EXP_SCALE_;\n uint256 internal constant DOUBLE_SCALE = 1e36;\n uint256 internal constant HALF_EXP_SCALE = EXP_SCALE / 2;\n uint256 internal constant MANTISSA_ONE = MANTISSA_ONE_;\n\n /**\n * @dev Truncates the given exp to a whole number value.\n * For example, truncate(Exp{mantissa: 15 * EXP_SCALE}) = 15\n */\n function truncate(Exp memory exp) internal pure returns (uint256) {\n // Note: We are not using careful math here as we're performing a division that cannot fail\n return exp.mantissa / EXP_SCALE;\n }\n\n /**\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\n */\n // solhint-disable-next-line func-name-mixedcase\n function mul_ScalarTruncate(Exp memory a, uint256 scalar) internal pure returns (uint256) {\n Exp memory product = mul_(a, scalar);\n return truncate(product);\n }\n\n /**\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\n */\n // solhint-disable-next-line func-name-mixedcase\n function mul_ScalarTruncateAddUInt(Exp memory a, uint256 scalar, uint256 addend) internal pure returns (uint256) {\n Exp memory product = mul_(a, scalar);\n return add_(truncate(product), addend);\n }\n\n /**\n * @dev Checks if first Exp is less than second Exp.\n */\n function lessThanExp(Exp memory left, Exp memory right) internal pure returns (bool) {\n return left.mantissa < right.mantissa;\n }\n\n function safe224(uint256 n, string memory errorMessage) internal pure returns (uint224) {\n require(n <= type(uint224).max, errorMessage);\n return uint224(n);\n }\n\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n <= type(uint32).max, errorMessage);\n return uint32(n);\n }\n\n function add_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: add_(a.mantissa, b.mantissa) });\n }\n\n function add_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: add_(a.mantissa, b.mantissa) });\n }\n\n function add_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n function sub_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: sub_(a.mantissa, b.mantissa) });\n }\n\n function sub_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: sub_(a.mantissa, b.mantissa) });\n }\n\n function sub_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n function mul_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: mul_(a.mantissa, b.mantissa) / EXP_SCALE });\n }\n\n function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n return Exp({ mantissa: mul_(a.mantissa, b) });\n }\n\n function mul_(uint256 a, Exp memory b) internal pure returns (uint256) {\n return mul_(a, b.mantissa) / EXP_SCALE;\n }\n\n function mul_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: mul_(a.mantissa, b.mantissa) / DOUBLE_SCALE });\n }\n\n function mul_(Double memory a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: mul_(a.mantissa, b) });\n }\n\n function mul_(uint256 a, Double memory b) internal pure returns (uint256) {\n return mul_(a, b.mantissa) / DOUBLE_SCALE;\n }\n\n function mul_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n function div_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: div_(mul_(a.mantissa, EXP_SCALE), b.mantissa) });\n }\n\n function div_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n return Exp({ mantissa: div_(a.mantissa, b) });\n }\n\n function div_(uint256 a, Exp memory b) internal pure returns (uint256) {\n return div_(mul_(a, EXP_SCALE), b.mantissa);\n }\n\n function div_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(mul_(a.mantissa, DOUBLE_SCALE), b.mantissa) });\n }\n\n function div_(Double memory a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(a.mantissa, b) });\n }\n\n function div_(uint256 a, Double memory b) internal pure returns (uint256) {\n return div_(mul_(a, DOUBLE_SCALE), b.mantissa);\n }\n\n function div_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n function fraction(uint256 a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(mul_(a, DOUBLE_SCALE), b) });\n }\n}\n" + }, + "contracts/InterestRateModel.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title Compound's InterestRateModel Interface\n * @author Compound\n */\nabstract contract InterestRateModel {\n /**\n * @notice Calculates the current borrow interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) external view virtual returns (uint256);\n\n /**\n * @notice Calculates the current supply interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param reserveFactorMantissa The current reserve factor the market has\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate per block (as a percentage, and scaled by 1e18)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) external view virtual returns (uint256);\n\n /**\n * @notice Indicator that this is an InterestRateModel contract (for inspection)\n * @return Always true\n */\n function isInterestRateModel() external pure virtual returns (bool) {\n return true;\n }\n}\n" + }, + "contracts/IPancakeswapV2Router.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface IPancakeswapV2Router {\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n}\n" + }, + "contracts/JumpRateModelV2.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\n\nimport { BaseJumpRateModelV2 } from \"./BaseJumpRateModelV2.sol\";\n\n/**\n * @title Compound's JumpRateModel Contract V2 for V2 vTokens\n * @author Arr00\n * @notice Supports only for V2 vTokens\n */\ncontract JumpRateModelV2 is BaseJumpRateModelV2 {\n constructor(\n uint256 blocksPerYear_,\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n IAccessControlManagerV8 accessControlManager_\n )\n BaseJumpRateModelV2(\n blocksPerYear_,\n baseRatePerYear,\n multiplierPerYear,\n jumpMultiplierPerYear,\n kink_,\n accessControlManager_\n )\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n /**\n * @notice Calculates the current borrow rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) external view override returns (uint256) {\n return _getBorrowRate(cash, borrows, reserves, badDebt);\n }\n}\n" + }, + "contracts/Lens/PoolLens.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { RewardsDistributor } from \"../Rewards/RewardsDistributor.sol\";\n\n/**\n * @title PoolLens\n * @author Venus\n * @notice The `PoolLens` contract is designed to retrieve important information for each registered pool. A list of essential information\n * for all pools within the lending protocol can be acquired through the function `getAllPools()`. Additionally, the following records can be\n * looked up for specific pools and markets:\n- the vToken balance of a given user;\n- the pool data (oracle address, associated vToken, liquidation incentive, etc) of a pool via its associated comptroller address;\n- the vToken address in a pool for a given asset;\n- a list of all pools that support an asset;\n- the underlying asset price of a vToken;\n- the metadata (exchange/borrow/supply rate, total supply, collateral factor, etc) of any vToken.\n */\ncontract PoolLens is ExponentialNoError {\n /**\n * @dev Struct for PoolDetails.\n */\n struct PoolData {\n string name;\n address creator;\n address comptroller;\n uint256 blockPosted;\n uint256 timestampPosted;\n string category;\n string logoURL;\n string description;\n address priceOracle;\n uint256 closeFactor;\n uint256 liquidationIncentive;\n uint256 minLiquidatableCollateral;\n VTokenMetadata[] vTokens;\n }\n\n /**\n * @dev Struct for VToken.\n */\n struct VTokenMetadata {\n address vToken;\n uint256 exchangeRateCurrent;\n uint256 supplyRatePerBlock;\n uint256 borrowRatePerBlock;\n uint256 reserveFactorMantissa;\n uint256 supplyCaps;\n uint256 borrowCaps;\n uint256 totalBorrows;\n uint256 totalReserves;\n uint256 totalSupply;\n uint256 totalCash;\n bool isListed;\n uint256 collateralFactorMantissa;\n address underlyingAssetAddress;\n uint256 vTokenDecimals;\n uint256 underlyingDecimals;\n }\n\n /**\n * @dev Struct for VTokenBalance.\n */\n struct VTokenBalances {\n address vToken;\n uint256 balanceOf;\n uint256 borrowBalanceCurrent;\n uint256 balanceOfUnderlying;\n uint256 tokenBalance;\n uint256 tokenAllowance;\n }\n\n /**\n * @dev Struct for underlyingPrice of VToken.\n */\n struct VTokenUnderlyingPrice {\n address vToken;\n uint256 underlyingPrice;\n }\n\n /**\n * @dev Struct with pending reward info for a market.\n */\n struct PendingReward {\n address vTokenAddress;\n uint256 amount;\n }\n\n /**\n * @dev Struct with reward distribution totals for a single reward token and distributor.\n */\n struct RewardSummary {\n address distributorAddress;\n address rewardTokenAddress;\n uint256 totalRewards;\n PendingReward[] pendingRewards;\n }\n\n /**\n * @dev Struct used in RewardDistributor to save last updated market state.\n */\n struct RewardTokenState {\n // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n uint224 index;\n // The block number the index was last updated at\n uint32 block;\n // The block number at which to stop rewards\n uint32 lastRewardingBlock;\n }\n\n /**\n * @dev Struct with bad debt of a market denominated\n */\n struct BadDebt {\n address vTokenAddress;\n uint256 badDebtUsd;\n }\n\n /**\n * @dev Struct with bad debt total denominated in usd for a pool and an array of BadDebt structs for each market\n */\n struct BadDebtSummary {\n address comptroller;\n uint256 totalBadDebtUsd;\n BadDebt[] badDebts;\n }\n\n /**\n * @notice Queries the user's supply/borrow balances in vTokens\n * @param vTokens The list of vToken addresses\n * @param account The user Account\n * @return A list of structs containing balances data\n */\n function vTokenBalancesAll(VToken[] calldata vTokens, address account) external returns (VTokenBalances[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenBalances[] memory res = new VTokenBalances[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenBalances(vTokens[i], account);\n }\n return res;\n }\n\n /**\n * @notice Queries all pools with addtional details for each of them\n * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @return Arrays of all Venus pools' data\n */\n function getAllPools(address poolRegistryAddress) external view returns (PoolData[] memory) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n PoolRegistry.VenusPool[] memory venusPools = poolRegistryInterface.getAllPools();\n uint256 poolLength = venusPools.length;\n\n PoolData[] memory poolDataItems = new PoolData[](poolLength);\n\n for (uint256 i; i < poolLength; ++i) {\n PoolRegistry.VenusPool memory venusPool = venusPools[i];\n PoolData memory poolData = getPoolDataFromVenusPool(poolRegistryAddress, venusPool);\n poolDataItems[i] = poolData;\n }\n\n return poolDataItems;\n }\n\n /**\n * @notice Queries the details of a pool identified by Comptroller address\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param comptroller The Comptroller implementation address\n * @return PoolData structure containing the details of the pool\n */\n function getPoolByComptroller(\n address poolRegistryAddress,\n address comptroller\n ) external view returns (PoolData memory) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return getPoolDataFromVenusPool(poolRegistryAddress, poolRegistryInterface.getPoolByComptroller(comptroller));\n }\n\n /**\n * @notice Returns vToken holding the specified underlying asset in the specified pool\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param comptroller The pool comptroller\n * @param asset The underlyingAsset of VToken\n * @return Address of the vToken\n */\n function getVTokenForAsset(\n address poolRegistryAddress,\n address comptroller,\n address asset\n ) external view returns (address) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return poolRegistryInterface.getVTokenForAsset(comptroller, asset);\n }\n\n /**\n * @notice Returns all pools that support the specified underlying asset\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param asset The underlying asset of vToken\n * @return A list of Comptroller contracts\n */\n function getPoolsSupportedByAsset(\n address poolRegistryAddress,\n address asset\n ) external view returns (address[] memory) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return poolRegistryInterface.getPoolsSupportedByAsset(asset);\n }\n\n /**\n * @notice Returns the price data for the underlying assets of the specified vTokens\n * @param vTokens The list of vToken addresses\n * @return An array containing the price data for each asset\n */\n function vTokenUnderlyingPriceAll(\n VToken[] calldata vTokens\n ) external view returns (VTokenUnderlyingPrice[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenUnderlyingPrice[] memory res = new VTokenUnderlyingPrice[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenUnderlyingPrice(vTokens[i]);\n }\n return res;\n }\n\n /**\n * @notice Returns the pending rewards for a user for a given pool.\n * @param account The user account.\n * @param comptrollerAddress address\n * @return Pending rewards array\n */\n function getPendingRewards(\n address account,\n address comptrollerAddress\n ) external view returns (RewardSummary[] memory) {\n VToken[] memory markets = ComptrollerInterface(comptrollerAddress).getAllMarkets();\n RewardsDistributor[] memory rewardsDistributors = ComptrollerViewInterface(comptrollerAddress)\n .getRewardDistributors();\n RewardSummary[] memory rewardSummary = new RewardSummary[](rewardsDistributors.length);\n for (uint256 i; i < rewardsDistributors.length; ++i) {\n RewardSummary memory reward;\n reward.distributorAddress = address(rewardsDistributors[i]);\n reward.rewardTokenAddress = address(rewardsDistributors[i].rewardToken());\n reward.totalRewards = rewardsDistributors[i].rewardTokenAccrued(account);\n reward.pendingRewards = _calculateNotDistributedAwards(account, markets, rewardsDistributors[i]);\n rewardSummary[i] = reward;\n }\n return rewardSummary;\n }\n\n /**\n * @notice Returns a summary of a pool's bad debt broken down by market\n *\n * @param comptrollerAddress Address of the comptroller\n *\n * @return badDebtSummary A struct with comptroller address, total bad debut denominated in usd, and\n * a break down of bad debt by market\n */\n function getPoolBadDebt(address comptrollerAddress) external view returns (BadDebtSummary memory) {\n uint256 totalBadDebtUsd;\n\n // Get every market in the pool\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n VToken[] memory markets = comptroller.getAllMarkets();\n ResilientOracleInterface priceOracle = comptroller.oracle();\n\n BadDebt[] memory badDebts = new BadDebt[](markets.length);\n\n BadDebtSummary memory badDebtSummary;\n badDebtSummary.comptroller = comptrollerAddress;\n badDebtSummary.badDebts = badDebts;\n\n // // Calculate the bad debt is USD per market\n for (uint256 i; i < markets.length; ++i) {\n BadDebt memory badDebt;\n badDebt.vTokenAddress = address(markets[i]);\n badDebt.badDebtUsd =\n (VToken(address(markets[i])).badDebt() * priceOracle.getUnderlyingPrice(address(markets[i]))) /\n EXP_SCALE;\n badDebtSummary.badDebts[i] = badDebt;\n totalBadDebtUsd = totalBadDebtUsd + badDebt.badDebtUsd;\n }\n\n badDebtSummary.totalBadDebtUsd = totalBadDebtUsd;\n\n return badDebtSummary;\n }\n\n /**\n * @notice Queries the user's supply/borrow balances in the specified vToken\n * @param vToken vToken address\n * @param account The user Account\n * @return A struct containing the balances data\n */\n function vTokenBalances(VToken vToken, address account) public returns (VTokenBalances memory) {\n uint256 balanceOf = vToken.balanceOf(account);\n uint256 borrowBalanceCurrent = vToken.borrowBalanceCurrent(account);\n uint256 balanceOfUnderlying = vToken.balanceOfUnderlying(account);\n uint256 tokenBalance;\n uint256 tokenAllowance;\n\n IERC20 underlying = IERC20(vToken.underlying());\n tokenBalance = underlying.balanceOf(account);\n tokenAllowance = underlying.allowance(account, address(vToken));\n\n return\n VTokenBalances({\n vToken: address(vToken),\n balanceOf: balanceOf,\n borrowBalanceCurrent: borrowBalanceCurrent,\n balanceOfUnderlying: balanceOfUnderlying,\n tokenBalance: tokenBalance,\n tokenAllowance: tokenAllowance\n });\n }\n\n /**\n * @notice Queries additional information for the pool\n * @param poolRegistryAddress Address of the PoolRegistry\n * @param venusPool The VenusPool Object from PoolRegistry\n * @return Enriched PoolData\n */\n function getPoolDataFromVenusPool(\n address poolRegistryAddress,\n PoolRegistry.VenusPool memory venusPool\n ) public view returns (PoolData memory) {\n // Get tokens in the Pool\n ComptrollerInterface comptrollerInstance = ComptrollerInterface(venusPool.comptroller);\n\n VToken[] memory vTokens = comptrollerInstance.getAllMarkets();\n\n VTokenMetadata[] memory vTokenMetadataItems = vTokenMetadataAll(vTokens);\n\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n\n PoolRegistry.VenusPoolMetaData memory venusPoolMetaData = poolRegistryInterface.getVenusPoolMetadata(\n venusPool.comptroller\n );\n\n ComptrollerViewInterface comptrollerViewInstance = ComptrollerViewInterface(venusPool.comptroller);\n\n PoolData memory poolData = PoolData({\n name: venusPool.name,\n creator: venusPool.creator,\n comptroller: venusPool.comptroller,\n blockPosted: venusPool.blockPosted,\n timestampPosted: venusPool.timestampPosted,\n category: venusPoolMetaData.category,\n logoURL: venusPoolMetaData.logoURL,\n description: venusPoolMetaData.description,\n vTokens: vTokenMetadataItems,\n priceOracle: address(comptrollerViewInstance.oracle()),\n closeFactor: comptrollerViewInstance.closeFactorMantissa(),\n liquidationIncentive: comptrollerViewInstance.liquidationIncentiveMantissa(),\n minLiquidatableCollateral: comptrollerViewInstance.minLiquidatableCollateral()\n });\n\n return poolData;\n }\n\n /**\n * @notice Returns the metadata of VToken\n * @param vToken The address of vToken\n * @return VTokenMetadata struct\n */\n function vTokenMetadata(VToken vToken) public view returns (VTokenMetadata memory) {\n uint256 exchangeRateCurrent = vToken.exchangeRateStored();\n address comptrollerAddress = address(vToken.comptroller());\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n (bool isListed, uint256 collateralFactorMantissa) = comptroller.markets(address(vToken));\n\n address underlyingAssetAddress = vToken.underlying();\n uint256 underlyingDecimals = IERC20Metadata(underlyingAssetAddress).decimals();\n\n return\n VTokenMetadata({\n vToken: address(vToken),\n exchangeRateCurrent: exchangeRateCurrent,\n supplyRatePerBlock: vToken.supplyRatePerBlock(),\n borrowRatePerBlock: vToken.borrowRatePerBlock(),\n reserveFactorMantissa: vToken.reserveFactorMantissa(),\n supplyCaps: comptroller.supplyCaps(address(vToken)),\n borrowCaps: comptroller.borrowCaps(address(vToken)),\n totalBorrows: vToken.totalBorrows(),\n totalReserves: vToken.totalReserves(),\n totalSupply: vToken.totalSupply(),\n totalCash: vToken.getCash(),\n isListed: isListed,\n collateralFactorMantissa: collateralFactorMantissa,\n underlyingAssetAddress: underlyingAssetAddress,\n vTokenDecimals: vToken.decimals(),\n underlyingDecimals: underlyingDecimals\n });\n }\n\n /**\n * @notice Returns the metadata of all VTokens\n * @param vTokens The list of vToken addresses\n * @return An array of VTokenMetadata structs\n */\n function vTokenMetadataAll(VToken[] memory vTokens) public view returns (VTokenMetadata[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenMetadata[] memory res = new VTokenMetadata[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenMetadata(vTokens[i]);\n }\n return res;\n }\n\n /**\n * @notice Returns the price data for the underlying asset of the specified vToken\n * @param vToken vToken address\n * @return The price data for each asset\n */\n function vTokenUnderlyingPrice(VToken vToken) public view returns (VTokenUnderlyingPrice memory) {\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(address(vToken.comptroller()));\n ResilientOracleInterface priceOracle = comptroller.oracle();\n\n return\n VTokenUnderlyingPrice({\n vToken: address(vToken),\n underlyingPrice: priceOracle.getUnderlyingPrice(address(vToken))\n });\n }\n\n function _calculateNotDistributedAwards(\n address account,\n VToken[] memory markets,\n RewardsDistributor rewardsDistributor\n ) internal view returns (PendingReward[] memory) {\n PendingReward[] memory pendingRewards = new PendingReward[](markets.length);\n for (uint256 i; i < markets.length; ++i) {\n // Market borrow and supply state we will modify update in-memory, in order to not modify storage\n RewardTokenState memory borrowState;\n (borrowState.index, borrowState.block, borrowState.lastRewardingBlock) = rewardsDistributor\n .rewardTokenBorrowState(address(markets[i]));\n RewardTokenState memory supplyState;\n (supplyState.index, supplyState.block, supplyState.lastRewardingBlock) = rewardsDistributor\n .rewardTokenSupplyState(address(markets[i]));\n Exp memory marketBorrowIndex = Exp({ mantissa: markets[i].borrowIndex() });\n\n // Update market supply and borrow index in-memory\n updateMarketBorrowIndex(address(markets[i]), rewardsDistributor, borrowState, marketBorrowIndex);\n updateMarketSupplyIndex(address(markets[i]), rewardsDistributor, supplyState);\n\n // Calculate pending rewards\n uint256 borrowReward = calculateBorrowerReward(\n address(markets[i]),\n rewardsDistributor,\n account,\n borrowState,\n marketBorrowIndex\n );\n uint256 supplyReward = calculateSupplierReward(\n address(markets[i]),\n rewardsDistributor,\n account,\n supplyState\n );\n\n PendingReward memory pendingReward;\n pendingReward.vTokenAddress = address(markets[i]);\n pendingReward.amount = borrowReward + supplyReward;\n pendingRewards[i] = pendingReward;\n }\n return pendingRewards;\n }\n\n function updateMarketBorrowIndex(\n address vToken,\n RewardsDistributor rewardsDistributor,\n RewardTokenState memory borrowState,\n Exp memory marketBorrowIndex\n ) internal view {\n uint256 borrowSpeed = rewardsDistributor.rewardTokenBorrowSpeeds(vToken);\n uint256 blockNumber = block.number;\n\n if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n blockNumber = borrowState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n // Remove the total earned interest rate since the opening of the market from total borrows\n uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n uint256 tokensAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0 ? fraction(tokensAccrued, borrowAmount) : Double({ mantissa: 0 });\n Double memory index = add_(Double({ mantissa: borrowState.index }), ratio);\n borrowState.index = safe224(index.mantissa, \"new index overflows\");\n borrowState.block = safe32(blockNumber, \"block number overflows\");\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block number overflows\");\n }\n }\n\n function updateMarketSupplyIndex(\n address vToken,\n RewardsDistributor rewardsDistributor,\n RewardTokenState memory supplyState\n ) internal view {\n uint256 supplySpeed = rewardsDistributor.rewardTokenSupplySpeeds(vToken);\n uint256 blockNumber = block.number;\n\n if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n blockNumber = supplyState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = VToken(vToken).totalSupply();\n uint256 tokensAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(tokensAccrued, supplyTokens) : Double({ mantissa: 0 });\n Double memory index = add_(Double({ mantissa: supplyState.index }), ratio);\n supplyState.index = safe224(index.mantissa, \"new index overflows\");\n supplyState.block = safe32(blockNumber, \"block number overflows\");\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number overflows\");\n }\n }\n\n function calculateBorrowerReward(\n address vToken,\n RewardsDistributor rewardsDistributor,\n address borrower,\n RewardTokenState memory borrowState,\n Exp memory marketBorrowIndex\n ) internal view returns (uint256) {\n Double memory borrowIndex = Double({ mantissa: borrowState.index });\n Double memory borrowerIndex = Double({\n mantissa: rewardsDistributor.rewardTokenBorrowerIndex(vToken, borrower)\n });\n if (borrowerIndex.mantissa == 0 && borrowIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n // Covers the case where users borrowed tokens before the market's borrow state index was set\n borrowerIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n }\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n return borrowerDelta;\n }\n\n function calculateSupplierReward(\n address vToken,\n RewardsDistributor rewardsDistributor,\n address supplier,\n RewardTokenState memory supplyState\n ) internal view returns (uint256) {\n Double memory supplyIndex = Double({ mantissa: supplyState.index });\n Double memory supplierIndex = Double({\n mantissa: rewardsDistributor.rewardTokenSupplierIndex(vToken, supplier)\n });\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n // Covers the case where users supplied tokens before the market's supply state index was set\n supplierIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n }\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n return supplierDelta;\n }\n}\n" + }, + "contracts/lib/ApproveOrRevert.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nlibrary ApproveOrRevert {\n /// @notice Thrown if a contract is unable to approve a transfer\n error ApproveFailed();\n\n /// @notice Approves a transfer, ensuring that it is successful. This function supports non-compliant\n /// tokens like the ones that don't return a boolean value on success. Thus, such approve call supports\n /// three different kinds of tokens:\n /// * Compliant tokens that revert on failure\n /// * Compliant tokens that return false on failure\n /// * Non-compliant tokens that don't return a value\n /// @param token The contract address of the token which will be transferred\n /// @param spender The spender contract address\n /// @param amount The value of the transfer\n function approveOrRevert(IERC20Upgradeable token, address spender, uint256 amount) internal {\n bytes memory callData = abi.encodeCall(token.approve, (spender, amount));\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory result) = address(token).call(callData);\n\n if (!success || (result.length != 0 && !abi.decode(result, (bool)))) {\n revert ApproveFailed();\n }\n }\n}\n" + }, + "contracts/lib/constants.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\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" + }, + "contracts/lib/imports.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n// This file is needed to make hardhat and typechain generate artifacts for\n// contracts we depend on (e.g. in tests or deployments) but not use directly.\n// Another way to do this would be to use hardhat-dependency-compiler, but\n// since we only have a couple of dependencies, installing a separate package\n// seems an overhead.\n\nimport { UpgradeableBeacon } from \"@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol\";\nimport { BeaconProxy } from \"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\";\n" + }, + "contracts/lib/TokenDebtTracker.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n/**\n * @title TokenDebtTracker\n * @author Venus\n * @notice TokenDebtTracker is an abstract contract that handles transfers _out_ of the inheriting contract.\n * If there is an error transferring out (due to any reason, e.g. the token contract restricted the user from\n * receiving incoming transfers), the amount is recorded as a debt that can be claimed later.\n * @dev Note that the inheriting contract keeps some amount of users' tokens on its balance, so be careful when\n * using balanceOf(address(this))!\n */\nabstract contract TokenDebtTracker is Initializable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /**\n * @notice Mapping (IERC20Upgradeable token => (address user => uint256 amount)).\n * Tracks failed transfers: when a token transfer fails, we record the\n * amount of the transfer, so that the user can redeem this debt later.\n */\n mapping(IERC20Upgradeable => mapping(address => uint256)) public tokenDebt;\n\n /**\n * @notice Mapping (IERC20Upgradeable token => uint256 amount) shows how many\n * tokens the contract owes to all users. This is useful for accounting to\n * understand how much of balanceOf(address(this)) is already owed to users.\n */\n mapping(IERC20Upgradeable => uint256) public totalTokenDebt;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[48] private __gap;\n\n /**\n * @notice Emitted when the contract's debt to the user is increased due to a failed transfer\n * @param token Token address\n * @param user User address\n * @param amount The amount of debt added\n */\n event TokenDebtAdded(address indexed token, address indexed user, uint256 amount);\n\n /**\n * @notice Emitted when a user claims tokens that the contract owes them\n * @param token Token address\n * @param user User address\n * @param amount The amount transferred\n */\n event TokenDebtClaimed(address indexed token, address indexed user, uint256 amount);\n\n /**\n * @notice Thrown if the user tries to claim more tokens than they are owed\n * @param token The token the user is trying to claim\n * @param owedAmount The amount of tokens the contract owes to the user\n * @param amount The amount of tokens the user is trying to claim\n */\n error InsufficientDebt(address token, address user, uint256 owedAmount, uint256 amount);\n\n /**\n * @notice Thrown if trying to transfer more tokens than the contract currently has\n * @param token The token the contract is trying to transfer\n * @param recipient The recipient of the transfer\n * @param amount The amount of tokens the contract is trying to transfer\n * @param availableBalance The amount of tokens the contract currently has\n */\n error InsufficientBalance(address token, address recipient, uint256 amount, uint256 availableBalance);\n\n /**\n * @notice Transfers the tokens we owe to msg.sender, if any\n * @param token The token to claim\n * @param amount_ The amount of tokens to claim (or max uint256 to claim all)\n * @custom:error InsufficientDebt The contract doesn't have enough debt to the user\n */\n function claimTokenDebt(IERC20Upgradeable token, uint256 amount_) external {\n uint256 owedAmount = tokenDebt[token][msg.sender];\n uint256 amount = (amount_ == type(uint256).max ? owedAmount : amount_);\n if (amount > owedAmount) {\n revert InsufficientDebt(address(token), msg.sender, owedAmount, amount);\n }\n unchecked {\n // Safe because we revert if amount > owedAmount above\n tokenDebt[token][msg.sender] = owedAmount - amount;\n }\n totalTokenDebt[token] -= amount;\n emit TokenDebtClaimed(address(token), msg.sender, amount);\n token.safeTransfer(msg.sender, amount);\n }\n\n // solhint-disable-next-line func-name-mixedcase\n function __TokenDebtTracker_init() internal onlyInitializing {\n __TokenDebtTracker_init_unchained();\n }\n\n // solhint-disable-next-line func-name-mixedcase, no-empty-blocks\n function __TokenDebtTracker_init_unchained() internal onlyInitializing {}\n\n /**\n * @dev Transfers tokens to the recipient if the contract has enough balance, or\n * records the debt if the transfer fails due to reasons unrelated to the contract's\n * balance (e.g. if the token forbids transfers to the recipient).\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n * @custom:error InsufficientBalance The contract doesn't have enough balance to transfer\n */\n function _transferOutOrTrackDebt(IERC20Upgradeable token, address to, uint256 amount) internal {\n uint256 balance = token.balanceOf(address(this));\n if (balance < amount) {\n revert InsufficientBalance(address(token), address(this), amount, balance);\n }\n _transferOutOrTrackDebtSkippingBalanceCheck(token, to, amount);\n }\n\n /**\n * @dev Transfers tokens to the recipient, or records the debt if the transfer fails\n * due to any reason, including insufficient balance.\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n */\n function _transferOutOrTrackDebtSkippingBalanceCheck(IERC20Upgradeable token, address to, uint256 amount) internal {\n // We can't use safeTransfer here because we can't try-catch internal calls\n bool success = _tryTransferOut(token, to, amount);\n if (!success) {\n tokenDebt[token][to] += amount;\n totalTokenDebt[token] += amount;\n emit TokenDebtAdded(address(token), to, amount);\n }\n }\n\n /**\n * @dev Either transfers tokens to the recepient or returns false. Supports tokens\n * thet revert or return false to indicate failure, and the non-compliant ones\n * that do not return any value.\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n * @return true if the transfer succeeded, false otherwise\n */\n function _tryTransferOut(IERC20Upgradeable token, address to, uint256 amount) private returns (bool) {\n bytes memory callData = abi.encodeCall(token.transfer, (to, amount));\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(callData);\n return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n }\n}\n" + }, + "contracts/lib/validators.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n}\n" + }, + "contracts/MaxLoopsLimitHelper.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title MaxLoopsLimitHelper\n * @author Venus\n * @notice Abstract contract used to avoid collection with too many items that would generate gas errors and DoS.\n */\nabstract contract MaxLoopsLimitHelper {\n // Limit for the loops to avoid the DOS\n uint256 public maxLoopsLimit;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when max loops limit is set\n event MaxLoopsLimitUpdated(uint256 oldMaxLoopsLimit, uint256 newmaxLoopsLimit);\n\n /// @notice Thrown an error on maxLoopsLimit exceeds for any loop\n error MaxLoopsLimitExceeded(uint256 loopsLimit, uint256 requiredLoops);\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function _setMaxLoopsLimit(uint256 limit) internal {\n require(limit > maxLoopsLimit, \"Comptroller: Invalid maxLoopsLimit\");\n\n uint256 oldMaxLoopsLimit = maxLoopsLimit;\n maxLoopsLimit = limit;\n\n emit MaxLoopsLimitUpdated(oldMaxLoopsLimit, limit);\n }\n\n /**\n * @notice Compare the maxLoopsLimit with number of the times loop iterate\n * @param len Length of the loops iterate\n * @custom:error MaxLoopsLimitExceeded error is thrown when loops length exceeds maxLoopsLimit\n */\n function _ensureMaxLoops(uint256 len) internal view {\n if (len > maxLoopsLimit) {\n revert MaxLoopsLimitExceeded(maxLoopsLimit, len);\n }\n }\n}\n" + }, + "contracts/Pool/PoolRegistry.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { PoolRegistryInterface } from \"./PoolRegistryInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\n/**\n * @title PoolRegistry\n * @author Venus\n * @notice The Isolated Pools architecture centers around the `PoolRegistry` contract. The `PoolRegistry` maintains a directory of isolated lending\n * pools and can perform actions like creating and registering new pools, adding new markets to existing pools, setting and updating the pool's required\n * metadata, and providing the getter methods to get information on the pools.\n *\n * Isolated lending has three main components: PoolRegistry, pools, and markets. The PoolRegistry is responsible for managing pools.\n * It can create new pools, update pool metadata and manage markets within pools. PoolRegistry contains getter methods to get the details of\n * any existing pool like `getVTokenForAsset` and `getPoolsSupportedByAsset`. It also contains methods for updating pool metadata (`updatePoolMetadata`)\n * and setting pool name (`setPoolName`).\n *\n * The directory of pools is managed through two mappings: `_poolByComptroller` which is a hashmap with the comptroller address as the key and `VenusPool` as\n * the value and `_poolsByID` which is an array of comptroller addresses. Individual pools can be accessed by calling `getPoolByComptroller` with the pool's\n * comptroller address. `_poolsByID` is used to iterate through all of the pools.\n *\n * PoolRegistry also contains a map of asset addresses called `_supportedPools` that maps to an array of assets suppored by each pool. This array of pools by\n * asset is retrieved by calling `getPoolsSupportedByAsset`.\n *\n * PoolRegistry registers new isolated pools in the directory with the `createRegistryPool` method. Isolated pools are composed of independent markets with\n * specific assets and custom risk management configurations according to their markets.\n */\ncontract PoolRegistry is Ownable2StepUpgradeable, AccessControlledV8, PoolRegistryInterface {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n struct AddMarketInput {\n VToken vToken;\n uint256 collateralFactor;\n uint256 liquidationThreshold;\n uint256 initialSupply;\n address vTokenReceiver;\n uint256 supplyCap;\n uint256 borrowCap;\n }\n\n uint256 internal constant MAX_POOL_NAME_LENGTH = 100;\n\n /**\n * @notice Maps pool's comptroller address to metadata.\n */\n mapping(address => VenusPoolMetaData) public metadata;\n\n /**\n * @dev Maps pool ID to pool's comptroller address\n */\n mapping(uint256 => address) private _poolsByID;\n\n /**\n * @dev Total number of pools created.\n */\n uint256 private _numberOfPools;\n\n /**\n * @dev Maps comptroller address to Venus pool Index.\n */\n mapping(address => VenusPool) private _poolByComptroller;\n\n /**\n * @dev Maps pool's comptroller address to asset to vToken.\n */\n mapping(address => mapping(address => address)) private _vTokens;\n\n /**\n * @dev Maps asset to list of supported pools.\n */\n mapping(address => address[]) private _supportedPools;\n\n /**\n * @notice Emitted when a new Venus pool is added to the directory.\n */\n event PoolRegistered(address indexed comptroller, VenusPool pool);\n\n /**\n * @notice Emitted when a pool name is set.\n */\n event PoolNameSet(address indexed comptroller, string oldName, string newName);\n\n /**\n * @notice Emitted when a pool metadata is updated.\n */\n event PoolMetadataUpdated(\n address indexed comptroller,\n VenusPoolMetaData oldMetadata,\n VenusPoolMetaData newMetadata\n );\n\n /**\n * @notice Emitted when a Market is added to the pool.\n */\n event MarketAdded(address indexed comptroller, address indexed vTokenAddress);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner\n * @param accessControlManager_ AccessControlManager contract address\n */\n function initialize(address accessControlManager_) external initializer {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n /**\n * @notice Adds a new Venus pool to the directory\n * @dev Price oracle must be configured before adding a pool\n * @param name The name of the pool\n * @param comptroller Pool's Comptroller contract\n * @param closeFactor The pool's close factor (scaled by 1e18)\n * @param liquidationIncentive The pool's liquidation incentive (scaled by 1e18)\n * @param minLiquidatableCollateral Minimal collateral for regular (non-batch) liquidations flow\n * @return index The index of the registered Venus pool\n * @custom:error ZeroAddressNotAllowed is thrown when Comptroller address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when price oracle address is zero\n */\n function addPool(\n string calldata name,\n Comptroller comptroller,\n uint256 closeFactor,\n uint256 liquidationIncentive,\n uint256 minLiquidatableCollateral\n ) external virtual returns (uint256 index) {\n _checkAccessAllowed(\"addPool(string,address,uint256,uint256,uint256)\");\n // Input validation\n ensureNonzeroAddress(address(comptroller));\n ensureNonzeroAddress(address(comptroller.oracle()));\n\n uint256 poolId = _registerPool(name, address(comptroller));\n\n // Set Venus pool parameters\n comptroller.setCloseFactor(closeFactor);\n comptroller.setLiquidationIncentive(liquidationIncentive);\n comptroller.setMinLiquidatableCollateral(minLiquidatableCollateral);\n\n return poolId;\n }\n\n /**\n * @notice Add a market to an existing pool and then mint to provide initial supply\n * @param input The structure describing the parameters for adding a market to a pool\n * @custom:error ZeroAddressNotAllowed is thrown when vToken address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when vTokenReceiver address is zero\n */\n function addMarket(AddMarketInput memory input) external {\n _checkAccessAllowed(\"addMarket(AddMarketInput)\");\n ensureNonzeroAddress(address(input.vToken));\n ensureNonzeroAddress(input.vTokenReceiver);\n require(input.initialSupply > 0, \"PoolRegistry: initialSupply is zero\");\n\n VToken vToken = input.vToken;\n address vTokenAddress = address(vToken);\n address comptrollerAddress = address(vToken.comptroller());\n Comptroller comptroller = Comptroller(comptrollerAddress);\n address underlyingAddress = vToken.underlying();\n IERC20Upgradeable underlying = IERC20Upgradeable(underlyingAddress);\n\n require(_poolByComptroller[comptrollerAddress].creator != address(0), \"PoolRegistry: Pool not registered\");\n // solhint-disable-next-line reason-string\n require(\n _vTokens[comptrollerAddress][underlyingAddress] == address(0),\n \"PoolRegistry: Market already added for asset comptroller combination\"\n );\n\n comptroller.supportMarket(vToken);\n comptroller.setCollateralFactor(vToken, input.collateralFactor, input.liquidationThreshold);\n\n uint256[] memory newSupplyCaps = new uint256[](1);\n uint256[] memory newBorrowCaps = new uint256[](1);\n VToken[] memory vTokens = new VToken[](1);\n\n newSupplyCaps[0] = input.supplyCap;\n newBorrowCaps[0] = input.borrowCap;\n vTokens[0] = vToken;\n\n comptroller.setMarketSupplyCaps(vTokens, newSupplyCaps);\n comptroller.setMarketBorrowCaps(vTokens, newBorrowCaps);\n\n _vTokens[comptrollerAddress][underlyingAddress] = vTokenAddress;\n _supportedPools[underlyingAddress].push(comptrollerAddress);\n\n uint256 amountToSupply = _transferIn(underlying, msg.sender, input.initialSupply);\n underlying.approve(vTokenAddress, 0);\n underlying.approve(vTokenAddress, amountToSupply);\n vToken.mintBehalf(input.vTokenReceiver, amountToSupply);\n\n emit MarketAdded(comptrollerAddress, vTokenAddress);\n }\n\n /**\n * @notice Modify existing Venus pool name\n * @param comptroller Pool's Comptroller\n * @param name New pool name\n */\n function setPoolName(address comptroller, string calldata name) external {\n _checkAccessAllowed(\"setPoolName(address,string)\");\n _ensureValidName(name);\n VenusPool storage pool = _poolByComptroller[comptroller];\n string memory oldName = pool.name;\n pool.name = name;\n emit PoolNameSet(comptroller, oldName, name);\n }\n\n /**\n * @notice Update metadata of an existing pool\n * @param comptroller Pool's Comptroller\n * @param metadata_ New pool metadata\n */\n function updatePoolMetadata(address comptroller, VenusPoolMetaData calldata metadata_) external {\n _checkAccessAllowed(\"updatePoolMetadata(address,VenusPoolMetaData)\");\n VenusPoolMetaData memory oldMetadata = metadata[comptroller];\n metadata[comptroller] = metadata_;\n emit PoolMetadataUpdated(comptroller, oldMetadata, metadata_);\n }\n\n /**\n * @notice Returns arrays of all Venus pools' data\n * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n * @return A list of all pools within PoolRegistry, with details for each pool\n */\n function getAllPools() external view override returns (VenusPool[] memory) {\n uint256 numberOfPools_ = _numberOfPools; // storage load to save gas\n VenusPool[] memory _pools = new VenusPool[](numberOfPools_);\n for (uint256 i = 1; i <= numberOfPools_; ++i) {\n address comptroller = _poolsByID[i];\n _pools[i - 1] = (_poolByComptroller[comptroller]);\n }\n return _pools;\n }\n\n /**\n * @param comptroller The comptroller proxy address associated to the pool\n * @return Returns Venus pool\n */\n function getPoolByComptroller(address comptroller) external view override returns (VenusPool memory) {\n return _poolByComptroller[comptroller];\n }\n\n /**\n * @param comptroller comptroller of Venus pool\n * @return Returns Metadata of Venus pool\n */\n function getVenusPoolMetadata(address comptroller) external view override returns (VenusPoolMetaData memory) {\n return metadata[comptroller];\n }\n\n function getVTokenForAsset(address comptroller, address asset) external view override returns (address) {\n return _vTokens[comptroller][asset];\n }\n\n function getPoolsSupportedByAsset(address asset) external view override returns (address[] memory) {\n return _supportedPools[asset];\n }\n\n /**\n * @dev Adds a new Venus pool to the directory (without checking msg.sender).\n * @param name The name of the pool\n * @param comptroller The pool's Comptroller proxy contract address\n * @return The index of the registered Venus pool\n */\n function _registerPool(string calldata name, address comptroller) internal returns (uint256) {\n VenusPool storage storedPool = _poolByComptroller[comptroller];\n\n require(storedPool.creator == address(0), \"PoolRegistry: Pool already exists in the directory.\");\n _ensureValidName(name);\n\n ++_numberOfPools;\n uint256 numberOfPools_ = _numberOfPools; // cache on stack to save storage read gas\n\n VenusPool memory pool = VenusPool(name, msg.sender, comptroller, block.number, block.timestamp);\n\n _poolsByID[numberOfPools_] = comptroller;\n _poolByComptroller[comptroller] = pool;\n\n emit PoolRegistered(comptroller, pool);\n return numberOfPools_;\n }\n\n function _transferIn(IERC20Upgradeable token, address from, uint256 amount) internal returns (uint256) {\n uint256 balanceBefore = token.balanceOf(address(this));\n token.safeTransferFrom(from, address(this), amount);\n uint256 balanceAfter = token.balanceOf(address(this));\n return balanceAfter - balanceBefore;\n }\n\n function _ensureValidName(string calldata name) internal pure {\n require(bytes(name).length <= MAX_POOL_NAME_LENGTH, \"Pool's name is too large\");\n }\n}\n" + }, + "contracts/Pool/PoolRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title PoolRegistryInterface\n * @author Venus\n * @notice Interface implemented by `PoolRegistry`.\n */\ninterface PoolRegistryInterface {\n /**\n * @notice Struct for a Venus interest rate pool.\n */\n struct VenusPool {\n string name;\n address creator;\n address comptroller;\n uint256 blockPosted;\n uint256 timestampPosted;\n }\n\n /**\n * @notice Struct for a Venus interest rate pool metadata.\n */\n struct VenusPoolMetaData {\n string category;\n string logoURL;\n string description;\n }\n\n /// @notice Get all pools in PoolRegistry\n function getAllPools() external view returns (VenusPool[] memory);\n\n /// @notice Get a pool by comptroller address\n function getPoolByComptroller(address comptroller) external view returns (VenusPool memory);\n\n /// @notice Get the address of the VToken contract in the Pool where the underlying token is the provided 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 /// @notice Get the metadata of a Pool by comptroller address\n function getVenusPoolMetadata(address comptroller) external view returns (VenusPoolMetaData memory);\n}\n" + }, + "contracts/Rewards/RewardsDistributor.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\n\n/**\n * @title `RewardsDistributor`\n * @author Venus\n * @notice Contract used to configure, track and distribute rewards to users based on their actions (borrows and supplies) in the protocol.\n * Users can receive additional rewards through a `RewardsDistributor`. Each `RewardsDistributor` proxy is initialized with a specific reward\n * token and `Comptroller`, which can then distribute the reward token to users that supply or borrow in the associated pool.\n * Authorized users can set the reward token borrow and supply speeds for each market in the pool. This sets a fixed amount of reward\n * token to be released each block for borrowers and suppliers, which is distributed based on a user’s percentage of the borrows or supplies\n * respectively. The owner can also set up reward distributions to contributor addresses (distinct from suppliers and borrowers) by setting\n * their contributor reward token speed, which similarly allocates a fixed amount of reward token per block.\n *\n * The owner has the ability to transfer any amount of reward tokens held by the contract to any other address. Rewards are not distributed\n * automatically and must be claimed by a user calling `claimRewardToken()`. Users should be aware that it is up to the owner and other centralized\n * entities to ensure that the `RewardsDistributor` holds enough tokens to distribute the accumulated rewards of users and contributors.\n */\ncontract RewardsDistributor is ExponentialNoError, Ownable2StepUpgradeable, AccessControlledV8, MaxLoopsLimitHelper {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n struct RewardToken {\n // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n uint224 index;\n // The block number the index was last updated at\n uint32 block;\n // The block number at which to stop rewards\n uint32 lastRewardingBlock;\n }\n\n /// @notice The initial REWARD TOKEN index for a market\n uint224 public constant INITIAL_INDEX = 1e36;\n\n /// @notice The REWARD TOKEN market supply state for each market\n mapping(address => RewardToken) public rewardTokenSupplyState;\n\n /// @notice The REWARD TOKEN borrow index for each market for each supplier as of the last time they accrued REWARD TOKEN\n mapping(address => mapping(address => uint256)) public rewardTokenSupplierIndex;\n\n /// @notice The REWARD TOKEN accrued but not yet transferred to each user\n mapping(address => uint256) public rewardTokenAccrued;\n\n /// @notice The rate at which rewardToken is distributed to the corresponding borrow market (per block)\n mapping(address => uint256) public rewardTokenBorrowSpeeds;\n\n /// @notice The rate at which rewardToken is distributed to the corresponding supply market (per block)\n mapping(address => uint256) public rewardTokenSupplySpeeds;\n\n /// @notice The REWARD TOKEN market borrow state for each market\n mapping(address => RewardToken) public rewardTokenBorrowState;\n\n /// @notice The portion of REWARD TOKEN that each contributor receives per block\n mapping(address => uint256) public rewardTokenContributorSpeeds;\n\n /// @notice Last block at which a contributor's REWARD TOKEN rewards have been allocated\n mapping(address => uint256) public lastContributorBlock;\n\n /// @notice The REWARD TOKEN borrow index for each market for each borrower as of the last time they accrued REWARD TOKEN\n mapping(address => mapping(address => uint256)) public rewardTokenBorrowerIndex;\n\n Comptroller private comptroller;\n\n IERC20Upgradeable public rewardToken;\n\n /// @notice Emitted when REWARD TOKEN is distributed to a supplier\n event DistributedSupplierRewardToken(\n VToken indexed vToken,\n address indexed supplier,\n uint256 rewardTokenDelta,\n uint256 rewardTokenTotal,\n uint256 rewardTokenSupplyIndex\n );\n\n /// @notice Emitted when REWARD TOKEN is distributed to a borrower\n event DistributedBorrowerRewardToken(\n VToken indexed vToken,\n address indexed borrower,\n uint256 rewardTokenDelta,\n uint256 rewardTokenTotal,\n uint256 rewardTokenBorrowIndex\n );\n\n /// @notice Emitted when a new supply-side REWARD TOKEN speed is calculated for a market\n event RewardTokenSupplySpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n /// @notice Emitted when a new borrow-side REWARD TOKEN speed is calculated for a market\n event RewardTokenBorrowSpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n /// @notice Emitted when REWARD TOKEN is granted by admin\n event RewardTokenGranted(address indexed recipient, uint256 amount);\n\n /// @notice Emitted when a new REWARD TOKEN speed is set for a contributor\n event ContributorRewardTokenSpeedUpdated(address indexed contributor, uint256 newSpeed);\n\n /// @notice Emitted when a market is initialized\n event MarketInitialized(address indexed vToken);\n\n /// @notice Emitted when a reward token supply index is updated\n event RewardTokenSupplyIndexUpdated(address indexed vToken);\n\n /// @notice Emitted when a reward token borrow index is updated\n event RewardTokenBorrowIndexUpdated(address indexed vToken, Exp marketBorrowIndex);\n\n /// @notice Emitted when a reward for contributor is updated\n event ContributorRewardsUpdated(address indexed contributor, uint256 rewardAccrued);\n\n /// @notice Emitted when a reward token last rewarding block for supply is updated\n event SupplyLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n /// @notice Emitted when a reward token last rewarding block for borrow is updated\n event BorrowLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n modifier onlyComptroller() {\n require(address(comptroller) == msg.sender, \"Only comptroller can call this function\");\n _;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice RewardsDistributor initializer\n * @dev Initializes the deployer to owner\n * @param comptroller_ Comptroller to attach the reward distributor to\n * @param rewardToken_ Reward token to distribute\n * @param loopsLimit_ Maximum number of iterations for the loops in this contract\n * @param accessControlManager_ AccessControlManager contract address\n */\n function initialize(\n Comptroller comptroller_,\n IERC20Upgradeable rewardToken_,\n uint256 loopsLimit_,\n address accessControlManager_\n ) external initializer {\n comptroller = comptroller_;\n rewardToken = rewardToken_;\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n\n _setMaxLoopsLimit(loopsLimit_);\n }\n\n function initializeMarket(address vToken) external onlyComptroller {\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n\n /*\n * Update market state indices\n */\n if (supplyState.index == 0) {\n // Initialize supply state index with default value\n supplyState.index = INITIAL_INDEX;\n }\n\n if (borrowState.index == 0) {\n // Initialize borrow state index with default value\n borrowState.index = INITIAL_INDEX;\n }\n\n /*\n * Update market state block numbers\n */\n supplyState.block = borrowState.block = blockNumber;\n\n emit MarketInitialized(vToken);\n }\n\n /*** Reward Token Distribution ***/\n\n /**\n * @notice Calculate reward token accrued by a borrower and possibly transfer it to them\n * Borrowers will begin to accrue after the first interaction with the protocol.\n * @dev This function should only be called when the user has a borrow position in the market\n * (e.g. Comptroller.preBorrowHook, and Comptroller.preRepayHook)\n * We avoid an external call to check if they are in the market to save gas because this function is called in many places\n * @param vToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute REWARD TOKEN to\n * @param marketBorrowIndex The current global borrow index of vToken\n */\n function distributeBorrowerRewardToken(\n address vToken,\n address borrower,\n Exp memory marketBorrowIndex\n ) external onlyComptroller {\n _distributeBorrowerRewardToken(vToken, borrower, marketBorrowIndex);\n }\n\n function updateRewardTokenSupplyIndex(address vToken) external onlyComptroller {\n _updateRewardTokenSupplyIndex(vToken);\n }\n\n /**\n * @notice Transfer REWARD TOKEN to the recipient\n * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all\n * @param recipient The address of the recipient to transfer REWARD TOKEN to\n * @param amount The amount of REWARD TOKEN to (possibly) transfer\n */\n function grantRewardToken(address recipient, uint256 amount) external onlyOwner {\n uint256 amountLeft = _grantRewardToken(recipient, amount);\n require(amountLeft == 0, \"insufficient rewardToken for grant\");\n emit RewardTokenGranted(recipient, amount);\n }\n\n function updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) external onlyComptroller {\n _updateRewardTokenBorrowIndex(vToken, marketBorrowIndex);\n }\n\n /**\n * @notice Set REWARD TOKEN borrow and supply speeds for the specified markets\n * @param vTokens The markets whose REWARD TOKEN speed to update\n * @param supplySpeeds New supply-side REWARD TOKEN speed for the corresponding market\n * @param borrowSpeeds New borrow-side REWARD TOKEN speed for the corresponding market\n */\n function setRewardTokenSpeeds(\n VToken[] memory vTokens,\n uint256[] memory supplySpeeds,\n uint256[] memory borrowSpeeds\n ) external {\n _checkAccessAllowed(\"setRewardTokenSpeeds(address[],uint256[],uint256[])\");\n uint256 numTokens = vTokens.length;\n require(numTokens == supplySpeeds.length && numTokens == borrowSpeeds.length, \"invalid setRewardTokenSpeeds\");\n\n for (uint256 i; i < numTokens; ++i) {\n _setRewardTokenSpeed(vTokens[i], supplySpeeds[i], borrowSpeeds[i]);\n }\n }\n\n /**\n * @notice Set REWARD TOKEN last rewarding block for the specified markets\n * @param vTokens The markets whose REWARD TOKEN last rewarding block to update\n * @param supplyLastRewardingBlocks New supply-side REWARD TOKEN last rewarding block for the corresponding market\n * @param borrowLastRewardingBlocks New borrow-side REWARD TOKEN last rewarding block for the corresponding market\n */\n function setLastRewardingBlocks(\n VToken[] calldata vTokens,\n uint32[] calldata supplyLastRewardingBlocks,\n uint32[] calldata borrowLastRewardingBlocks\n ) external {\n _checkAccessAllowed(\"setLastRewardingBlock(address[],uint32[],uint32[])\");\n uint256 numTokens = vTokens.length;\n require(\n numTokens == supplyLastRewardingBlocks.length && numTokens == borrowLastRewardingBlocks.length,\n \"RewardsDistributor::setLastRewardingBlocks invalid input\"\n );\n\n for (uint256 i; i < numTokens; ) {\n _setLastRewardingBlock(vTokens[i], supplyLastRewardingBlocks[i], borrowLastRewardingBlocks[i]);\n unchecked {\n ++i;\n }\n }\n }\n\n /**\n * @notice Set REWARD TOKEN speed for a single contributor\n * @param contributor The contributor whose REWARD TOKEN speed to update\n * @param rewardTokenSpeed New REWARD TOKEN speed for contributor\n */\n function setContributorRewardTokenSpeed(address contributor, uint256 rewardTokenSpeed) external onlyOwner {\n // note that REWARD TOKEN speed could be set to 0 to halt liquidity rewards for a contributor\n updateContributorRewards(contributor);\n if (rewardTokenSpeed == 0) {\n // release storage\n delete lastContributorBlock[contributor];\n } else {\n lastContributorBlock[contributor] = getBlockNumber();\n }\n rewardTokenContributorSpeeds[contributor] = rewardTokenSpeed;\n\n emit ContributorRewardTokenSpeedUpdated(contributor, rewardTokenSpeed);\n }\n\n function distributeSupplierRewardToken(address vToken, address supplier) external onlyComptroller {\n _distributeSupplierRewardToken(vToken, supplier);\n }\n\n /**\n * @notice Claim all the rewardToken accrued by holder in all markets\n * @param holder The address to claim REWARD TOKEN for\n */\n function claimRewardToken(address holder) external {\n return claimRewardToken(holder, comptroller.getAllMarkets());\n }\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Calculate additional accrued REWARD TOKEN for a contributor since last accrual\n * @param contributor The address to calculate contributor rewards for\n */\n function updateContributorRewards(address contributor) public {\n uint256 rewardTokenSpeed = rewardTokenContributorSpeeds[contributor];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, lastContributorBlock[contributor]);\n if (deltaBlocks > 0 && rewardTokenSpeed > 0) {\n uint256 newAccrued = mul_(deltaBlocks, rewardTokenSpeed);\n uint256 contributorAccrued = add_(rewardTokenAccrued[contributor], newAccrued);\n\n rewardTokenAccrued[contributor] = contributorAccrued;\n lastContributorBlock[contributor] = blockNumber;\n\n emit ContributorRewardsUpdated(contributor, rewardTokenAccrued[contributor]);\n }\n }\n\n /**\n * @notice Claim all the rewardToken accrued by holder in the specified markets\n * @param holder The address to claim REWARD TOKEN for\n * @param vTokens The list of markets to claim REWARD TOKEN in\n */\n function claimRewardToken(address holder, VToken[] memory vTokens) public {\n uint256 vTokensCount = vTokens.length;\n\n _ensureMaxLoops(vTokensCount);\n\n for (uint256 i; i < vTokensCount; ++i) {\n VToken vToken = vTokens[i];\n require(comptroller.isMarketListed(vToken), \"market must be listed\");\n Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n _distributeBorrowerRewardToken(address(vToken), holder, borrowIndex);\n _updateRewardTokenSupplyIndex(address(vToken));\n _distributeSupplierRewardToken(address(vToken), holder);\n }\n rewardTokenAccrued[holder] = _grantRewardToken(holder, rewardTokenAccrued[holder]);\n }\n\n function getBlockNumber() public view virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Set REWARD TOKEN last rewarding block for a single market.\n * @param vToken market's whose reward token last rewarding block to be updated\n * @param supplyLastRewardingBlock New supply-side REWARD TOKEN last rewarding block for market\n * @param borrowLastRewardingBlock New borrow-side REWARD TOKEN last rewarding block for market\n */\n function _setLastRewardingBlock(\n VToken vToken,\n uint32 supplyLastRewardingBlock,\n uint32 borrowLastRewardingBlock\n ) internal {\n require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n uint256 blockNumber = getBlockNumber();\n\n require(supplyLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n require(borrowLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n\n uint32 currentSupplyLastRewardingBlock = rewardTokenSupplyState[address(vToken)].lastRewardingBlock;\n uint32 currentBorrowLastRewardingBlock = rewardTokenBorrowState[address(vToken)].lastRewardingBlock;\n\n require(\n currentSupplyLastRewardingBlock == 0 || currentSupplyLastRewardingBlock > blockNumber,\n \"this RewardsDistributor is already locked\"\n );\n require(\n currentBorrowLastRewardingBlock == 0 || currentBorrowLastRewardingBlock > blockNumber,\n \"this RewardsDistributor is already locked\"\n );\n\n if (currentSupplyLastRewardingBlock != supplyLastRewardingBlock) {\n rewardTokenSupplyState[address(vToken)].lastRewardingBlock = supplyLastRewardingBlock;\n emit SupplyLastRewardingBlockUpdated(address(vToken), supplyLastRewardingBlock);\n }\n\n if (currentBorrowLastRewardingBlock != borrowLastRewardingBlock) {\n rewardTokenBorrowState[address(vToken)].lastRewardingBlock = borrowLastRewardingBlock;\n emit BorrowLastRewardingBlockUpdated(address(vToken), borrowLastRewardingBlock);\n }\n }\n\n /**\n * @notice Set REWARD TOKEN speed for a single market.\n * @param vToken market's whose reward token rate to be updated\n * @param supplySpeed New supply-side REWARD TOKEN speed for market\n * @param borrowSpeed New borrow-side REWARD TOKEN speed for market\n */\n function _setRewardTokenSpeed(VToken vToken, uint256 supplySpeed, uint256 borrowSpeed) internal {\n require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n if (rewardTokenSupplySpeeds[address(vToken)] != supplySpeed) {\n // Supply speed updated so let's update supply state to ensure that\n // 1. REWARD TOKEN accrued properly for the old speed, and\n // 2. REWARD TOKEN accrued at the new speed starts after this block.\n _updateRewardTokenSupplyIndex(address(vToken));\n\n // Update speed and emit event\n rewardTokenSupplySpeeds[address(vToken)] = supplySpeed;\n emit RewardTokenSupplySpeedUpdated(vToken, supplySpeed);\n }\n\n if (rewardTokenBorrowSpeeds[address(vToken)] != borrowSpeed) {\n // Borrow speed updated so let's update borrow state to ensure that\n // 1. REWARD TOKEN accrued properly for the old speed, and\n // 2. REWARD TOKEN accrued at the new speed starts after this block.\n Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n\n // Update speed and emit event\n rewardTokenBorrowSpeeds[address(vToken)] = borrowSpeed;\n emit RewardTokenBorrowSpeedUpdated(vToken, borrowSpeed);\n }\n }\n\n /**\n * @notice Calculate REWARD TOKEN accrued by a supplier and possibly transfer it to them.\n * @param vToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute REWARD TOKEN to\n */\n function _distributeSupplierRewardToken(address vToken, address supplier) internal {\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n uint256 supplyIndex = supplyState.index;\n uint256 supplierIndex = rewardTokenSupplierIndex[vToken][supplier];\n\n // Update supplier's index to the current index since we are distributing accrued REWARD TOKEN\n rewardTokenSupplierIndex[vToken][supplier] = supplyIndex;\n\n if (supplierIndex == 0 && supplyIndex >= INITIAL_INDEX) {\n // Covers the case where users supplied tokens before the market's supply state index was set.\n // Rewards the user with REWARD TOKEN accrued from the start of when supplier rewards were first\n // set for the market.\n supplierIndex = INITIAL_INDEX;\n }\n\n // Calculate change in the cumulative sum of the REWARD TOKEN per vToken accrued\n Double memory deltaIndex = Double({ mantissa: sub_(supplyIndex, supplierIndex) });\n\n uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n\n // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerVToken\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n\n uint256 supplierAccrued = add_(rewardTokenAccrued[supplier], supplierDelta);\n rewardTokenAccrued[supplier] = supplierAccrued;\n\n emit DistributedSupplierRewardToken(VToken(vToken), supplier, supplierDelta, supplierAccrued, supplyIndex);\n }\n\n /**\n * @notice Calculate reward token accrued by a borrower and possibly transfer it to them.\n * @param vToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute REWARD TOKEN to\n * @param marketBorrowIndex The current global borrow index of vToken\n */\n function _distributeBorrowerRewardToken(address vToken, address borrower, Exp memory marketBorrowIndex) internal {\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n uint256 borrowIndex = borrowState.index;\n uint256 borrowerIndex = rewardTokenBorrowerIndex[vToken][borrower];\n\n // Update borrowers's index to the current index since we are distributing accrued REWARD TOKEN\n rewardTokenBorrowerIndex[vToken][borrower] = borrowIndex;\n\n if (borrowerIndex == 0 && borrowIndex >= INITIAL_INDEX) {\n // Covers the case where users borrowed tokens before the market's borrow state index was set.\n // Rewards the user with REWARD TOKEN accrued from the start of when borrower rewards were first\n // set for the market.\n borrowerIndex = INITIAL_INDEX;\n }\n\n // Calculate change in the cumulative sum of the REWARD TOKEN per borrowed unit accrued\n Double memory deltaIndex = Double({ mantissa: sub_(borrowIndex, borrowerIndex) });\n\n uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n\n // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerBorrowedUnit\n if (borrowerAmount != 0) {\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n\n uint256 borrowerAccrued = add_(rewardTokenAccrued[borrower], borrowerDelta);\n rewardTokenAccrued[borrower] = borrowerAccrued;\n\n emit DistributedBorrowerRewardToken(VToken(vToken), borrower, borrowerDelta, borrowerAccrued, borrowIndex);\n }\n }\n\n /**\n * @notice Transfer REWARD TOKEN to the user.\n * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all.\n * @param user The address of the user to transfer REWARD TOKEN to\n * @param amount The amount of REWARD TOKEN to (possibly) transfer\n * @return The amount of REWARD TOKEN which was NOT transferred to the user\n */\n function _grantRewardToken(address user, uint256 amount) internal returns (uint256) {\n uint256 rewardTokenRemaining = rewardToken.balanceOf(address(this));\n if (amount > 0 && amount <= rewardTokenRemaining) {\n rewardToken.safeTransfer(user, amount);\n return 0;\n }\n return amount;\n }\n\n /**\n * @notice Accrue REWARD TOKEN to the market by updating the supply index\n * @param vToken The market whose supply index to update\n * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n */\n function _updateRewardTokenSupplyIndex(address vToken) internal {\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n uint256 supplySpeed = rewardTokenSupplySpeeds[vToken];\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n blockNumber = supplyState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(uint256(blockNumber), uint256(supplyState.block));\n\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = VToken(vToken).totalSupply();\n uint256 accruedSinceUpdate = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(accruedSinceUpdate, supplyTokens)\n : Double({ mantissa: 0 });\n supplyState.index = safe224(\n add_(Double({ mantissa: supplyState.index }), ratio).mantissa,\n \"new index exceeds 224 bits\"\n );\n supplyState.block = blockNumber;\n } else if (deltaBlocks > 0) {\n supplyState.block = blockNumber;\n }\n\n emit RewardTokenSupplyIndexUpdated(vToken);\n }\n\n /**\n * @notice Accrue REWARD TOKEN to the market by updating the borrow index\n * @param vToken The market whose borrow index to update\n * @param marketBorrowIndex The current global borrow index of vToken\n * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n */\n function _updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) internal {\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n uint256 borrowSpeed = rewardTokenBorrowSpeeds[vToken];\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n blockNumber = borrowState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(uint256(blockNumber), uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n uint256 accruedSinceUpdate = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(accruedSinceUpdate, borrowAmount)\n : Double({ mantissa: 0 });\n borrowState.index = safe224(\n add_(Double({ mantissa: borrowState.index }), ratio).mantissa,\n \"new index exceeds 224 bits\"\n );\n borrowState.block = blockNumber;\n } else if (deltaBlocks > 0) {\n borrowState.block = blockNumber;\n }\n\n emit RewardTokenBorrowIndexUpdated(vToken, marketBorrowIndex);\n }\n}\n" + }, + "contracts/RiskFund/IProtocolShareReserve.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IProtocolShareReserve\n * @author Venus\n * @notice Interface implemented by `ProtocolShareReserve`.\n */\ninterface IProtocolShareReserve {\n function updateAssetsState(address comptroller, address asset) external;\n}\n" + }, + "contracts/RiskFund/IRiskFund.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IRiskFund\n * @author Venus\n * @notice Interface implemented by `RiskFund`.\n */\ninterface IRiskFund {\n function swapPoolsAssets(\n address[] calldata markets,\n uint256[] calldata amountsOutMin,\n address[][] calldata paths,\n uint256 deadline\n ) external returns (uint256);\n\n function transferReserveForAuction(address comptroller, uint256 amount) external returns (uint256);\n\n function updateAssetsState(address comptroller, address asset) external;\n\n function convertibleBaseAsset() external view returns (address);\n\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256);\n}\n" + }, + "contracts/RiskFund/ProtocolShareReserve.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { IProtocolShareReserve } from \"./IProtocolShareReserve.sol\";\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\ncontract ProtocolShareReserve is ExponentialNoError, ReserveHelpers, IProtocolShareReserve {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n address public protocolIncome;\n address public riskFund;\n // Percentage of funds not sent to the RiskFund contract when the funds are released, following the project Tokenomics\n uint256 private constant PROTOCOL_SHARE_PERCENTAGE = 50;\n uint256 private constant BASE_UNIT = 100;\n\n /// @notice Emitted when funds are released\n event FundsReleased(address indexed comptroller, address indexed asset, uint256 amount);\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner.\n * @param protocolIncome_ The address protocol income will be sent to\n * @param riskFund_ Risk fund address\n * @custom:error ZeroAddressNotAllowed is thrown when protocol income address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n */\n function initialize(address protocolIncome_, address riskFund_) external initializer {\n ensureNonzeroAddress(protocolIncome_);\n ensureNonzeroAddress(riskFund_);\n\n __Ownable2Step_init();\n\n protocolIncome = protocolIncome_;\n riskFund = riskFund_;\n }\n\n /**\n * @notice Pool registry setter.\n * @param poolRegistry_ Address of the pool registry\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function setPoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Release funds\n * @param comptroller Pool's Comptroller\n * @param asset Asset to be released\n * @param amount Amount to release\n * @return Number of total released tokens\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function releaseFunds(address comptroller, address asset, uint256 amount) external nonReentrant returns (uint256) {\n ensureNonzeroAddress(asset);\n require(amount <= _poolsAssetsReserves[comptroller][asset], \"ProtocolShareReserve: Insufficient pool balance\");\n\n assetsReserves[asset] -= amount;\n _poolsAssetsReserves[comptroller][asset] -= amount;\n uint256 protocolIncomeAmount = mul_(\n Exp({ mantissa: amount }),\n div_(Exp({ mantissa: PROTOCOL_SHARE_PERCENTAGE * EXP_SCALE }), BASE_UNIT)\n ).mantissa;\n\n address riskFund_ = riskFund;\n\n emit FundsReleased(comptroller, asset, amount);\n\n IERC20Upgradeable(asset).safeTransfer(protocolIncome, protocolIncomeAmount);\n IERC20Upgradeable(asset).safeTransfer(riskFund_, amount - protocolIncomeAmount);\n\n // Update the pool asset's state in the risk fund for the above transfer.\n IRiskFund(riskFund_).updateAssetsState(comptroller, asset);\n\n return amount;\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to the protocol share reserve.\n * @param comptroller Comptroller address(pool)\n * @param asset Asset address.\n */\n function updateAssetsState(\n address comptroller,\n address asset\n ) public override(IProtocolShareReserve, ReserveHelpers) {\n super.updateAssetsState(comptroller, asset);\n }\n}\n" + }, + "contracts/RiskFund/ReserveHelpers.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\n\ncontract ReserveHelpers is Ownable2StepUpgradeable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n uint256 private constant NOT_ENTERED = 1;\n\n uint256 private constant ENTERED = 2;\n\n // Store the previous state for the asset transferred to ProtocolShareReserve combined(for all pools).\n mapping(address => uint256) public assetsReserves;\n\n // Store the asset's reserve per pool in the ProtocolShareReserve.\n // Comptroller(pool) -> Asset -> amount\n mapping(address => mapping(address => uint256)) internal _poolsAssetsReserves;\n\n // Address of pool registry contract\n address public poolRegistry;\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n uint256 internal status;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n */\n uint256[46] private __gap;\n\n /// @notice Event emitted after the update of the assets reserves.\n /// @param comptroller Pool's Comptroller address\n /// @param asset Token address\n /// @param amount An amount by which the reserves have increased\n event AssetsReservesUpdated(address indexed comptroller, address indexed asset, uint256 amount);\n\n /// @notice event emitted on sweep token success\n event SweepToken(address indexed token, address indexed to, uint256 amount);\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(status != ENTERED, \"re-entered\");\n status = ENTERED;\n _;\n status = NOT_ENTERED;\n }\n\n /**\n * @notice A public function to sweep accidental BEP-20 transfers to this contract. Tokens are sent to the address `to`, provided in input\n * @param _token The address of the BEP-20 token to sweep\n * @param _to Recipient of the output tokens.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n * @custom:access Only Owner\n */\n function sweepToken(address _token, address _to) external onlyOwner nonReentrant {\n ensureNonzeroAddress(_to);\n uint256 balanceDfference_;\n uint256 balance_ = IERC20Upgradeable(_token).balanceOf(address(this));\n\n require(balance_ > assetsReserves[_token], \"ReserveHelpers: Zero surplus tokens\");\n unchecked {\n balanceDfference_ = balance_ - assetsReserves[_token];\n }\n\n emit SweepToken(_token, _to, balanceDfference_);\n IERC20Upgradeable(_token).safeTransfer(_to, balanceDfference_);\n }\n\n /**\n * @notice Get the Amount of the asset in the risk fund for the specific pool.\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n * @return Asset's reserve in risk fund.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function getPoolAssetReserve(address comptroller, address asset) external view returns (uint256) {\n ensureNonzeroAddress(asset);\n require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n return _poolsAssetsReserves[comptroller][asset];\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to risk fund\n * and transferring funds to the protocol share reserve\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function updateAssetsState(address comptroller, address asset) public virtual {\n ensureNonzeroAddress(asset);\n require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n address poolRegistry_ = poolRegistry;\n require(poolRegistry_ != address(0), \"ReserveHelpers: Pool Registry address is not set\");\n require(\n PoolRegistryInterface(poolRegistry_).getVTokenForAsset(comptroller, asset) != address(0),\n \"ReserveHelpers: The pool doesn't support the asset\"\n );\n\n uint256 currentBalance = IERC20Upgradeable(asset).balanceOf(address(this));\n uint256 assetReserve = assetsReserves[asset];\n if (currentBalance > assetReserve) {\n uint256 balanceDifference;\n unchecked {\n balanceDifference = currentBalance - assetReserve;\n }\n assetsReserves[asset] += balanceDifference;\n _poolsAssetsReserves[comptroller][asset] += balanceDifference;\n emit AssetsReservesUpdated(comptroller, asset, balanceDifference);\n }\n }\n}\n" + }, + "contracts/RiskFund/RiskFund.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { IPancakeswapV2Router } from \"../IPancakeswapV2Router.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { ApproveOrRevert } from \"../lib/ApproveOrRevert.sol\";\n\n/**\n * @title RiskFund\n * @author Venus\n * @notice Contract with basic features to track/hold different assets for different Comptrollers.\n * @dev This contract does not support BNB.\n */\ncontract RiskFund is AccessControlledV8, ExponentialNoError, ReserveHelpers, MaxLoopsLimitHelper, IRiskFund {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using ApproveOrRevert for IERC20Upgradeable;\n\n address public convertibleBaseAsset;\n address public shortfall;\n address public pancakeSwapRouter;\n uint256 public minAmountToConvert;\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @notice Emitted when shortfall contract address is updated\n event ShortfallContractUpdated(address indexed oldShortfallContract, address indexed newShortfallContract);\n\n /// @notice Emitted when convertible base asset is updated\n event ConvertibleBaseAssetUpdated(address indexed oldConvertibleBaseAsset, address indexed newConvertibleBaseAsset);\n\n /// @notice Emitted when PancakeSwap router contract address is updated\n event PancakeSwapRouterUpdated(address indexed oldPancakeSwapRouter, address indexed newPancakeSwapRouter);\n\n /// @notice Emitted when minimum amount to convert is updated\n event MinAmountToConvertUpdated(uint256 oldMinAmountToConvert, uint256 newMinAmountToConvert);\n\n /// @notice Emitted when pools assets are swapped\n event SwappedPoolsAssets(address[] markets, uint256[] amountsOutMin, uint256 totalAmount);\n\n /// @notice Emitted when reserves are transferred for auction\n event TransferredReserveForAuction(address indexed comptroller, uint256 amount);\n\n /// @dev Note that the contract is upgradeable. Use initialize() or reinitializers\n /// to set the state variables.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner.\n * @param pancakeSwapRouter_ Address of the PancakeSwap router\n * @param minAmountToConvert_ Minimum amount assets must be worth to convert into base asset\n * @param convertibleBaseAsset_ Address of the base asset\n * @param accessControlManager_ Address of the access control contract\n * @param loopsLimit_ Limit for the loops in the contract to avoid DOS\n * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n */\n function initialize(\n address pancakeSwapRouter_,\n uint256 minAmountToConvert_,\n address convertibleBaseAsset_,\n address accessControlManager_,\n uint256 loopsLimit_\n ) external initializer {\n ensureNonzeroAddress(pancakeSwapRouter_);\n ensureNonzeroAddress(convertibleBaseAsset_);\n require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n require(loopsLimit_ > 0, \"Risk Fund: Loops limit can not be zero\");\n\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n\n pancakeSwapRouter = pancakeSwapRouter_;\n minAmountToConvert = minAmountToConvert_;\n convertibleBaseAsset = convertibleBaseAsset_;\n\n _setMaxLoopsLimit(loopsLimit_);\n }\n\n /**\n * @notice Pool registry setter\n * @param poolRegistry_ Address of the pool registry\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function setPoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Shortfall contract address setter\n * @param shortfallContractAddress_ Address of the auction contract\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n */\n function setShortfallContractAddress(address shortfallContractAddress_) external onlyOwner {\n ensureNonzeroAddress(shortfallContractAddress_);\n\n address oldShortfallContractAddress = shortfall;\n shortfall = shortfallContractAddress_;\n emit ShortfallContractUpdated(oldShortfallContractAddress, shortfallContractAddress_);\n }\n\n /**\n * @notice PancakeSwap router address setter\n * @param pancakeSwapRouter_ Address of the PancakeSwap router\n * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n */\n function setPancakeSwapRouter(address pancakeSwapRouter_) external onlyOwner {\n ensureNonzeroAddress(pancakeSwapRouter_);\n address oldPancakeSwapRouter = pancakeSwapRouter;\n pancakeSwapRouter = pancakeSwapRouter_;\n emit PancakeSwapRouterUpdated(oldPancakeSwapRouter, pancakeSwapRouter_);\n }\n\n /**\n * @notice Min amount to convert setter\n * @param minAmountToConvert_ Min amount to convert.\n */\n function setMinAmountToConvert(uint256 minAmountToConvert_) external {\n _checkAccessAllowed(\"setMinAmountToConvert(uint256)\");\n require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n uint256 oldMinAmountToConvert = minAmountToConvert;\n minAmountToConvert = minAmountToConvert_;\n emit MinAmountToConvertUpdated(oldMinAmountToConvert, minAmountToConvert_);\n }\n\n /**\n * @notice Sets a new convertible base asset\n * @param _convertibleBaseAsset Address for new convertible base asset.\n */\n function setConvertibleBaseAsset(address _convertibleBaseAsset) external {\n _checkAccessAllowed(\"setConvertibleBaseAsset(address)\");\n require(_convertibleBaseAsset != address(0), \"Risk Fund: new convertible base asset address invalid\");\n\n address oldConvertibleBaseAsset = convertibleBaseAsset;\n convertibleBaseAsset = _convertibleBaseAsset;\n\n emit ConvertibleBaseAssetUpdated(oldConvertibleBaseAsset, _convertibleBaseAsset);\n }\n\n /**\n * @notice Swap array of pool assets into base asset's tokens of at least a minimum amount\n * @param markets Array of vTokens whose assets to swap for base asset\n * @param amountsOutMin Minimum amount to receive for swap\n * @param paths A path consisting of PCS token pairs for each swap\n * @param deadline Deadline for the swap\n * @return Number of swapped tokens\n * @custom:error ZeroAddressNotAllowed is thrown if PoolRegistry contract address is not configured\n */\n function swapPoolsAssets(\n address[] calldata markets,\n uint256[] calldata amountsOutMin,\n address[][] calldata paths,\n uint256 deadline\n ) external override nonReentrant returns (uint256) {\n _checkAccessAllowed(\"swapPoolsAssets(address[],uint256[],address[][],uint256)\");\n require(deadline >= block.timestamp, \"Risk fund: deadline passed\");\n address poolRegistry_ = poolRegistry;\n ensureNonzeroAddress(poolRegistry_);\n require(markets.length == amountsOutMin.length, \"Risk fund: markets and amountsOutMin are unequal lengths\");\n require(markets.length == paths.length, \"Risk fund: markets and paths are unequal lengths\");\n\n uint256 totalAmount;\n uint256 marketsCount = markets.length;\n\n _ensureMaxLoops(marketsCount);\n\n for (uint256 i; i < marketsCount; ++i) {\n address comptroller = address(VToken(markets[i]).comptroller());\n\n PoolRegistry.VenusPool memory pool = PoolRegistry(poolRegistry_).getPoolByComptroller(comptroller);\n require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n require(Comptroller(comptroller).isMarketListed(VToken(markets[i])), \"market is not listed\");\n\n uint256 swappedTokens = _swapAsset(VToken(markets[i]), comptroller, amountsOutMin[i], paths[i]);\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] += swappedTokens;\n assetsReserves[convertibleBaseAsset] += swappedTokens;\n totalAmount = totalAmount + swappedTokens;\n }\n\n emit SwappedPoolsAssets(markets, amountsOutMin, totalAmount);\n\n return totalAmount;\n }\n\n /**\n * @notice Transfer tokens for auction.\n * @param comptroller Comptroller of the pool.\n * @param amount Amount to be transferred to auction contract.\n * @return Number reserved tokens.\n */\n function transferReserveForAuction(\n address comptroller,\n uint256 amount\n ) external override nonReentrant returns (uint256) {\n address shortfall_ = shortfall;\n require(msg.sender == shortfall_, \"Risk fund: Only callable by Shortfall contract\");\n require(\n amount <= _poolsAssetsReserves[comptroller][convertibleBaseAsset],\n \"Risk Fund: Insufficient pool reserve.\"\n );\n unchecked {\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] =\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] -\n amount;\n }\n unchecked {\n assetsReserves[convertibleBaseAsset] = assetsReserves[convertibleBaseAsset] - amount;\n }\n\n emit TransferredReserveForAuction(comptroller, amount);\n IERC20Upgradeable(convertibleBaseAsset).safeTransfer(shortfall_, amount);\n\n return amount;\n }\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Get the Amount of the Base asset in the risk fund for the specific pool.\n * @param comptroller Comptroller address(pool).\n * @return Base Asset's reserve in risk fund.\n */\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256) {\n require(ComptrollerInterface(comptroller).isComptroller(), \"Risk Fund: Comptroller address invalid\");\n return _poolsAssetsReserves[comptroller][convertibleBaseAsset];\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to risk fund.\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n */\n function updateAssetsState(address comptroller, address asset) public override(IRiskFund, ReserveHelpers) {\n super.updateAssetsState(comptroller, asset);\n }\n\n /**\n * @dev Swap single asset to base asset.\n * @param vToken VToken\n * @param comptroller Comptroller address\n * @param amountOutMin Minimum amount to receive for swap\n * @param path A path for the swap consisting of PCS token pairs\n * @return Number of swapped tokens.\n */\n function _swapAsset(\n VToken vToken,\n address comptroller,\n uint256 amountOutMin,\n address[] calldata path\n ) internal returns (uint256) {\n require(amountOutMin != 0, \"RiskFund: amountOutMin must be greater than 0 to swap vToken\");\n uint256 totalAmount;\n\n address underlyingAsset = vToken.underlying();\n address convertibleBaseAsset_ = convertibleBaseAsset;\n uint256 balanceOfUnderlyingAsset = _poolsAssetsReserves[comptroller][underlyingAsset];\n\n if (balanceOfUnderlyingAsset == 0) {\n return 0;\n }\n\n ResilientOracleInterface oracle = ComptrollerViewInterface(comptroller).oracle();\n oracle.updateAssetPrice(convertibleBaseAsset_);\n Exp memory baseAssetPrice = Exp({ mantissa: oracle.getPrice(convertibleBaseAsset_) });\n uint256 amountOutMinInUsd = mul_ScalarTruncate(baseAssetPrice, amountOutMin);\n\n require(amountOutMinInUsd >= minAmountToConvert, \"RiskFund: minAmountToConvert violated\");\n\n assetsReserves[underlyingAsset] -= balanceOfUnderlyingAsset;\n _poolsAssetsReserves[comptroller][underlyingAsset] -= balanceOfUnderlyingAsset;\n\n if (underlyingAsset != convertibleBaseAsset_) {\n require(path[0] == underlyingAsset, \"RiskFund: swap path must start with the underlying asset\");\n require(\n path[path.length - 1] == convertibleBaseAsset_,\n \"RiskFund: finally path must be convertible base asset\"\n );\n address pancakeSwapRouter_ = pancakeSwapRouter;\n IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, 0);\n IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, balanceOfUnderlyingAsset);\n uint256[] memory amounts = IPancakeswapV2Router(pancakeSwapRouter_).swapExactTokensForTokens(\n balanceOfUnderlyingAsset,\n amountOutMin,\n path,\n address(this),\n block.timestamp\n );\n totalAmount = amounts[path.length - 1];\n } else {\n totalAmount = balanceOfUnderlyingAsset;\n }\n\n return totalAmount;\n }\n}\n" + }, + "contracts/Shortfall/Shortfall.sol": { + "content": "/// @notice SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"../RiskFund/IRiskFund.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { TokenDebtTracker } from \"../lib/TokenDebtTracker.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { EXP_SCALE } from \"../lib/constants.sol\";\n\n/**\n * @title Shortfall\n * @author Venus\n * @notice Shortfall is an auction contract designed to auction off the `convertibleBaseAsset` accumulated in `RiskFund`. The `convertibleBaseAsset`\n * is auctioned in exchange for users paying off the pool's bad debt. An auction can be started by anyone once a pool's bad debt has reached a minimum value.\n * This value is set and can be changed by the authorized accounts. If the pool’s bad debt exceeds the risk fund plus a 10% incentive, then the auction winner\n * is determined by who will pay off the largest percentage of the pool's bad debt. The auction winner then exchanges for the entire risk fund. Otherwise,\n * if the risk fund covers the pool's bad debt plus the 10% incentive, then the auction winner is determined by who will take the smallest percentage of the\n * risk fund in exchange for paying off all the pool's bad debt.\n */\ncontract Shortfall is Ownable2StepUpgradeable, AccessControlledV8, ReentrancyGuardUpgradeable, TokenDebtTracker {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /// @notice Type of auction\n enum AuctionType {\n LARGE_POOL_DEBT,\n LARGE_RISK_FUND\n }\n\n /// @notice Status of auction\n enum AuctionStatus {\n NOT_STARTED,\n STARTED,\n ENDED\n }\n\n /// @notice Auction metadata\n struct Auction {\n uint256 startBlock;\n AuctionType auctionType;\n AuctionStatus status;\n VToken[] markets;\n uint256 seizedRiskFund;\n address highestBidder;\n uint256 highestBidBps;\n uint256 highestBidBlock;\n uint256 startBidBps;\n mapping(VToken => uint256) marketDebt;\n mapping(VToken => uint256) bidAmount;\n }\n\n /// @dev Max basis points i.e., 100%\n uint256 private constant MAX_BPS = 10000;\n\n uint256 private constant DEFAULT_NEXT_BIDDER_BLOCK_LIMIT = 100;\n\n uint256 private constant DEFAULT_WAIT_FOR_FIRST_BIDDER = 100;\n\n uint256 private constant DEFAULT_INCENTIVE_BPS = 1000; // 10%\n\n /// @notice Pool registry address\n address public poolRegistry;\n\n /// @notice Risk fund address\n IRiskFund public riskFund;\n\n /// @notice Minimum USD debt in pool for shortfall to trigger\n uint256 public minimumPoolBadDebt;\n\n /// @notice Incentive to auction participants, initial value set to 1000 or 10%\n uint256 public incentiveBps;\n\n /// @notice Time to wait for next bidder. Initially waits for 100 blocks\n uint256 public nextBidderBlockLimit;\n\n /// @notice Boolean of if auctions are paused\n bool public auctionsPaused;\n\n /// @notice Time to wait for first bidder. Initially waits for 100 blocks\n uint256 public waitForFirstBidder;\n\n /// @notice Auctions for each pool\n mapping(address => Auction) public auctions;\n\n /// @notice Emitted when a auction starts\n event AuctionStarted(\n address indexed comptroller,\n uint256 auctionStartBlock,\n AuctionType auctionType,\n VToken[] markets,\n uint256[] marketsDebt,\n uint256 seizedRiskFund,\n uint256 startBidBps\n );\n\n /// @notice Emitted when a bid is placed\n event BidPlaced(address indexed comptroller, uint256 auctionStartBlock, uint256 bidBps, address indexed bidder);\n\n /// @notice Emitted when a auction is completed\n event AuctionClosed(\n address indexed comptroller,\n uint256 auctionStartBlock,\n address indexed highestBidder,\n uint256 highestBidBps,\n uint256 seizedRiskFind,\n VToken[] markets,\n uint256[] marketDebt\n );\n\n /// @notice Emitted when a auction is restarted\n event AuctionRestarted(address indexed comptroller, uint256 auctionStartBlock);\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @notice Emitted when minimum pool bad debt is updated\n event MinimumPoolBadDebtUpdated(uint256 oldMinimumPoolBadDebt, uint256 newMinimumPoolBadDebt);\n\n /// @notice Emitted when wait for first bidder block count is updated\n event WaitForFirstBidderUpdated(uint256 oldWaitForFirstBidder, uint256 newWaitForFirstBidder);\n\n /// @notice Emitted when next bidder block limit is updated\n event NextBidderBlockLimitUpdated(uint256 oldNextBidderBlockLimit, uint256 newNextBidderBlockLimit);\n\n /// @notice Emitted when incentiveBps is updated\n event IncentiveBpsUpdated(uint256 oldIncentiveBps, uint256 newIncentiveBps);\n\n /// @notice Emitted when auctions are paused\n event AuctionsPaused(address sender);\n\n /// @notice Emitted when auctions are unpaused\n event AuctionsResumed(address sender);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initialize the shortfall contract\n * @param riskFund_ RiskFund contract address\n * @param minimumPoolBadDebt_ Minimum bad debt in base asset for a pool to start auction\n * @param accessControlManager_ AccessControlManager contract address\n * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n */\n function initialize(\n IRiskFund riskFund_,\n uint256 minimumPoolBadDebt_,\n address accessControlManager_\n ) external initializer {\n ensureNonzeroAddress(address(riskFund_));\n require(minimumPoolBadDebt_ != 0, \"invalid minimum pool bad debt\");\n\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n __ReentrancyGuard_init();\n __TokenDebtTracker_init();\n minimumPoolBadDebt = minimumPoolBadDebt_;\n riskFund = riskFund_;\n waitForFirstBidder = DEFAULT_WAIT_FOR_FIRST_BIDDER;\n nextBidderBlockLimit = DEFAULT_NEXT_BIDDER_BLOCK_LIMIT;\n incentiveBps = DEFAULT_INCENTIVE_BPS;\n auctionsPaused = false;\n }\n\n /**\n * @notice Place a bid greater than the previous in an ongoing auction\n * @param comptroller Comptroller address of the pool\n * @param bidBps The bid percent of the risk fund or bad debt depending on auction type\n * @param auctionStartBlock The block number when auction started\n * @custom:event Emits BidPlaced event on success\n */\n function placeBid(address comptroller, uint256 bidBps, uint256 auctionStartBlock) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(auction.startBlock == auctionStartBlock, \"auction has been restarted\");\n require(_isStarted(auction), \"no on-going auction\");\n require(!_isStale(auction), \"auction is stale, restart it\");\n require(bidBps > 0, \"basis points cannot be zero\");\n require(bidBps <= MAX_BPS, \"basis points cannot be more than 10000\");\n require(\n (auction.auctionType == AuctionType.LARGE_POOL_DEBT &&\n ((auction.highestBidder != address(0) && bidBps > auction.highestBidBps) ||\n (auction.highestBidder == address(0) && bidBps >= auction.startBidBps))) ||\n (auction.auctionType == AuctionType.LARGE_RISK_FUND &&\n ((auction.highestBidder != address(0) && bidBps < auction.highestBidBps) ||\n (auction.highestBidder == address(0) && bidBps <= auction.startBidBps))),\n \"your bid is not the highest\"\n );\n\n uint256 marketsCount = auction.markets.length;\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = VToken(address(auction.markets[i]));\n IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n if (auction.highestBidder != address(0)) {\n _transferOutOrTrackDebt(erc20, auction.highestBidder, auction.bidAmount[auction.markets[i]]);\n }\n uint256 balanceBefore = erc20.balanceOf(address(this));\n\n if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n uint256 currentBidAmount = ((auction.marketDebt[auction.markets[i]] * bidBps) / MAX_BPS);\n erc20.safeTransferFrom(msg.sender, address(this), currentBidAmount);\n } else {\n erc20.safeTransferFrom(msg.sender, address(this), auction.marketDebt[auction.markets[i]]);\n }\n\n uint256 balanceAfter = erc20.balanceOf(address(this));\n auction.bidAmount[auction.markets[i]] = balanceAfter - balanceBefore;\n }\n\n auction.highestBidder = msg.sender;\n auction.highestBidBps = bidBps;\n auction.highestBidBlock = block.number;\n\n emit BidPlaced(comptroller, auction.startBlock, bidBps, msg.sender);\n }\n\n /**\n * @notice Close an auction\n * @param comptroller Comptroller address of the pool\n * @custom:event Emits AuctionClosed event on successful close\n */\n function closeAuction(address comptroller) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(_isStarted(auction), \"no on-going auction\");\n require(\n block.number > auction.highestBidBlock + nextBidderBlockLimit && auction.highestBidder != address(0),\n \"waiting for next bidder. cannot close auction\"\n );\n\n uint256 marketsCount = auction.markets.length;\n uint256[] memory marketsDebt = new uint256[](marketsCount);\n\n auction.status = AuctionStatus.ENDED;\n\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = VToken(address(auction.markets[i]));\n IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n uint256 balanceBefore = erc20.balanceOf(address(auction.markets[i]));\n erc20.safeTransfer(address(auction.markets[i]), auction.bidAmount[auction.markets[i]]);\n uint256 balanceAfter = erc20.balanceOf(address(auction.markets[i]));\n marketsDebt[i] = balanceAfter - balanceBefore;\n\n auction.markets[i].badDebtRecovered(marketsDebt[i]);\n }\n\n uint256 riskFundBidAmount;\n\n if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n riskFundBidAmount = auction.seizedRiskFund;\n } else {\n riskFundBidAmount = (auction.seizedRiskFund * auction.highestBidBps) / MAX_BPS;\n }\n\n address convertibleBaseAsset = riskFund.convertibleBaseAsset();\n\n uint256 transferredAmount = riskFund.transferReserveForAuction(comptroller, riskFundBidAmount);\n _transferOutOrTrackDebt(IERC20Upgradeable(convertibleBaseAsset), auction.highestBidder, riskFundBidAmount);\n\n emit AuctionClosed(\n comptroller,\n auction.startBlock,\n auction.highestBidder,\n auction.highestBidBps,\n transferredAmount,\n auction.markets,\n marketsDebt\n );\n }\n\n /**\n * @notice Start a auction when there is not currently one active\n * @param comptroller Comptroller address of the pool\n * @custom:event Emits AuctionStarted event on success\n * @custom:event Errors if auctions are paused\n */\n function startAuction(address comptroller) external nonReentrant {\n require(!auctionsPaused, \"Auctions are paused\");\n _startAuction(comptroller);\n }\n\n /**\n * @notice Restart an auction\n * @param comptroller Address of the pool\n * @custom:event Emits AuctionRestarted event on successful restart\n */\n function restartAuction(address comptroller) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(!auctionsPaused, \"auctions are paused\");\n require(_isStarted(auction), \"no on-going auction\");\n require(_isStale(auction), \"you need to wait for more time for first bidder\");\n\n auction.status = AuctionStatus.ENDED;\n\n emit AuctionRestarted(comptroller, auction.startBlock);\n _startAuction(comptroller);\n }\n\n /**\n * @notice Update next bidder block limit which is used determine when an auction can be closed\n * @param _nextBidderBlockLimit New next bidder block limit\n * @custom:event Emits NextBidderBlockLimitUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateNextBidderBlockLimit(uint256 _nextBidderBlockLimit) external {\n _checkAccessAllowed(\"updateNextBidderBlockLimit(uint256)\");\n require(_nextBidderBlockLimit != 0, \"_nextBidderBlockLimit must not be 0\");\n uint256 oldNextBidderBlockLimit = nextBidderBlockLimit;\n nextBidderBlockLimit = _nextBidderBlockLimit;\n emit NextBidderBlockLimitUpdated(oldNextBidderBlockLimit, _nextBidderBlockLimit);\n }\n\n /**\n * @notice Updates the incentive BPS\n * @param _incentiveBps New incentive BPS\n * @custom:event Emits IncentiveBpsUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateIncentiveBps(uint256 _incentiveBps) external {\n _checkAccessAllowed(\"updateIncentiveBps(uint256)\");\n require(_incentiveBps != 0, \"incentiveBps must not be 0\");\n uint256 oldIncentiveBps = incentiveBps;\n incentiveBps = _incentiveBps;\n emit IncentiveBpsUpdated(oldIncentiveBps, _incentiveBps);\n }\n\n /**\n * @notice Update minimum pool bad debt to start auction\n * @param _minimumPoolBadDebt Minimum bad debt in the base asset for a pool to start auction\n * @custom:event Emits MinimumPoolBadDebtUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateMinimumPoolBadDebt(uint256 _minimumPoolBadDebt) external {\n _checkAccessAllowed(\"updateMinimumPoolBadDebt(uint256)\");\n uint256 oldMinimumPoolBadDebt = minimumPoolBadDebt;\n minimumPoolBadDebt = _minimumPoolBadDebt;\n emit MinimumPoolBadDebtUpdated(oldMinimumPoolBadDebt, _minimumPoolBadDebt);\n }\n\n /**\n * @notice Update wait for first bidder block count. If the first bid is not made within this limit, the auction is closed and needs to be restarted\n * @param _waitForFirstBidder New wait for first bidder block count\n * @custom:event Emits WaitForFirstBidderUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateWaitForFirstBidder(uint256 _waitForFirstBidder) external {\n _checkAccessAllowed(\"updateWaitForFirstBidder(uint256)\");\n uint256 oldWaitForFirstBidder = waitForFirstBidder;\n waitForFirstBidder = _waitForFirstBidder;\n emit WaitForFirstBidderUpdated(oldWaitForFirstBidder, _waitForFirstBidder);\n }\n\n /**\n * @notice Update the pool registry this shortfall supports\n * @dev After Pool Registry is deployed we need to set the pool registry address\n * @param poolRegistry_ Address of pool registry contract\n * @custom:event Emits PoolRegistryUpdated on success\n * @custom:access Restricted to owner\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function updatePoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Pause auctions. This disables starting new auctions but lets the current auction finishes\n * @custom:event Emits AuctionsPaused on success\n * @custom:error Errors is auctions are paused\n * @custom:access Restricted by ACM\n */\n function pauseAuctions() external {\n _checkAccessAllowed(\"pauseAuctions()\");\n require(!auctionsPaused, \"Auctions are already paused\");\n auctionsPaused = true;\n emit AuctionsPaused(msg.sender);\n }\n\n /**\n * @notice Resume paused auctions.\n * @custom:event Emits AuctionsResumed on success\n * @custom:error Errors is auctions are active\n * @custom:access Restricted by ACM\n */\n function resumeAuctions() external {\n _checkAccessAllowed(\"resumeAuctions()\");\n require(auctionsPaused, \"Auctions are not paused\");\n auctionsPaused = false;\n emit AuctionsResumed(msg.sender);\n }\n\n /**\n * @notice Start a auction when there is not currently one active\n * @param comptroller Comptroller address of the pool\n */\n function _startAuction(address comptroller) internal {\n PoolRegistryInterface.VenusPool memory pool = PoolRegistry(poolRegistry).getPoolByComptroller(comptroller);\n require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n\n Auction storage auction = auctions[comptroller];\n require(\n auction.status == AuctionStatus.NOT_STARTED || auction.status == AuctionStatus.ENDED,\n \"auction is on-going\"\n );\n\n auction.highestBidBps = 0;\n auction.highestBidBlock = 0;\n\n uint256 marketsCount = auction.markets.length;\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = auction.markets[i];\n auction.marketDebt[vToken] = 0;\n }\n\n delete auction.markets;\n\n VToken[] memory vTokens = _getAllMarkets(comptroller);\n marketsCount = vTokens.length;\n ResilientOracleInterface priceOracle = _getPriceOracle(comptroller);\n uint256 poolBadDebt;\n\n uint256[] memory marketsDebt = new uint256[](marketsCount);\n auction.markets = new VToken[](marketsCount);\n\n for (uint256 i; i < marketsCount; ++i) {\n uint256 marketBadDebt = vTokens[i].badDebt();\n\n priceOracle.updatePrice(address(vTokens[i]));\n uint256 usdValue = (priceOracle.getUnderlyingPrice(address(vTokens[i])) * marketBadDebt) / EXP_SCALE;\n\n poolBadDebt = poolBadDebt + usdValue;\n auction.markets[i] = vTokens[i];\n auction.marketDebt[vTokens[i]] = marketBadDebt;\n marketsDebt[i] = marketBadDebt;\n }\n\n require(poolBadDebt >= minimumPoolBadDebt, \"pool bad debt is too low\");\n\n priceOracle.updateAssetPrice(riskFund.convertibleBaseAsset());\n uint256 riskFundBalance = (priceOracle.getPrice(riskFund.convertibleBaseAsset()) *\n riskFund.getPoolsBaseAssetReserves(comptroller)) / EXP_SCALE;\n uint256 remainingRiskFundBalance = riskFundBalance;\n uint256 badDebtPlusIncentive = poolBadDebt + ((poolBadDebt * incentiveBps) / MAX_BPS);\n if (badDebtPlusIncentive >= riskFundBalance) {\n auction.startBidBps =\n (MAX_BPS * MAX_BPS * remainingRiskFundBalance) /\n (poolBadDebt * (MAX_BPS + incentiveBps));\n remainingRiskFundBalance = 0;\n auction.auctionType = AuctionType.LARGE_POOL_DEBT;\n } else {\n uint256 maxSeizeableRiskFundBalance = badDebtPlusIncentive;\n\n remainingRiskFundBalance = remainingRiskFundBalance - maxSeizeableRiskFundBalance;\n auction.auctionType = AuctionType.LARGE_RISK_FUND;\n auction.startBidBps = MAX_BPS;\n }\n\n auction.seizedRiskFund = riskFundBalance - remainingRiskFundBalance;\n auction.startBlock = block.number;\n auction.status = AuctionStatus.STARTED;\n auction.highestBidder = address(0);\n\n emit AuctionStarted(\n comptroller,\n auction.startBlock,\n auction.auctionType,\n auction.markets,\n marketsDebt,\n auction.seizedRiskFund,\n auction.startBidBps\n );\n }\n\n /**\n * @dev Returns the price oracle of the pool\n * @param comptroller Address of the pool's comptroller\n * @return oracle The pool's price oracle\n */\n function _getPriceOracle(address comptroller) internal view returns (ResilientOracleInterface) {\n return ResilientOracleInterface(ComptrollerViewInterface(comptroller).oracle());\n }\n\n /**\n * @dev Returns all markets of the pool\n * @param comptroller Address of the pool's comptroller\n * @return markets The pool's markets as VToken array\n */\n function _getAllMarkets(address comptroller) internal view returns (VToken[] memory) {\n return ComptrollerInterface(comptroller).getAllMarkets();\n }\n\n /**\n * @dev Checks if the auction has started\n * @param auction The auction to query the status for\n * @return True if the auction has started\n */\n function _isStarted(Auction storage auction) internal view returns (bool) {\n return auction.status == AuctionStatus.STARTED;\n }\n\n /**\n * @dev Checks if the auction is stale, i.e. there's no bidder and the auction\n * was started more than waitForFirstBidder blocks ago.\n * @param auction The auction to query the status for\n * @return True if the auction is stale\n */\n function _isStale(Auction storage auction) internal view returns (bool) {\n bool noBidder = auction.highestBidder == address(0);\n return noBidder && (block.number > auction.startBlock + waitForFirstBidder);\n }\n}\n" + }, + "contracts/test/ComptrollerHarness.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { Comptroller } from \"../Comptroller.sol\";\n\ncontract ComptrollerHarness is Comptroller {\n uint256 public blockNumber;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n function harnessFastForward(uint256 blocks) public returns (uint256) {\n blockNumber += blocks;\n return blockNumber;\n }\n\n function setBlockNumber(uint256 number) public {\n blockNumber = number;\n }\n}\n\ncontract EchoTypesComptroller {\n function stringy(string memory s) public pure returns (string memory) {\n return s;\n }\n\n function addresses(address a) public pure returns (address) {\n return a;\n }\n\n function booly(bool b) public pure returns (bool) {\n return b;\n }\n\n function listOInts(uint256[] memory u) public pure returns (uint256[] memory) {\n return u;\n }\n\n function reverty() public pure {\n require(false, \"gotcha sucka\");\n }\n}\n" + }, + "contracts/test/ComptrollerScenario.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\n\ncontract ComptrollerScenario is Comptroller {\n uint256 public blockNumber;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n function fastForward(uint256 blocks) public returns (uint256) {\n blockNumber += blocks;\n return blockNumber;\n }\n\n function setBlockNumber(uint256 number) public {\n blockNumber = number;\n }\n\n function unlist(VToken vToken) public {\n markets[address(vToken)].isListed = false;\n }\n\n function membershipLength(VToken vToken) public view returns (uint256) {\n return accountAssets[address(vToken)].length;\n }\n}\n" + }, + "contracts/test/ERC20.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { SafeMath } from \"./SafeMath.sol\";\n\ninterface ERC20Base {\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function totalSupply() external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function balanceOf(address who) external view returns (uint256);\n}\n\nabstract contract ERC20 is ERC20Base {\n function transfer(address to, uint256 value) external virtual returns (bool);\n\n function transferFrom(address from, address to, uint256 value) external virtual returns (bool);\n}\n\nabstract contract ERC20NS is ERC20Base {\n function transfer(address to, uint256 value) external virtual;\n\n function transferFrom(address from, address to, uint256 value) external virtual;\n}\n\n/**\n * @title Standard ERC20 token\n * @dev Implementation of the basic standard token.\n * See https://github.com/ethereum/EIPs/issues/20\n */\ncontract StandardToken is ERC20 {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external virtual override returns (bool) {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) external virtual override returns (bool) {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function approve(address _spender, uint256 amount) external virtual override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\n/**\n * @title Non-Standard ERC20 token\n * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`\n * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\ncontract NonStandardToken is ERC20NS {\n using SafeMath for uint256;\n\n string public name;\n uint8 public decimals;\n string public symbol;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external override {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n }\n\n function transferFrom(address src, address dst, uint256 amount) external override {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n }\n\n function approve(address _spender, uint256 amount) external override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\ncontract ERC20Harness is StandardToken {\n using SafeMath for uint256;\n // To support testing, we can specify addresses for which transferFrom should fail and return false\n mapping(address => bool) public failTransferFromAddresses;\n\n // To support testing, we allow the contract to always fail `transfer`.\n mapping(address => bool) public failTransferToAddresses;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferToAddresses[dst]) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferFromAddresses[src]) {\n return false;\n }\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\n failTransferFromAddresses[src] = _fail;\n }\n\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\n failTransferToAddresses[dst] = _fail;\n }\n\n function harnessSetBalance(address _account, uint256 _amount) public {\n balanceOf[_account] = _amount;\n }\n}\n" + }, + "contracts/test/EvilToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { FaucetToken } from \"./FaucetToken.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title The Compound Evil Test Token\n * @author Compound\n * @notice A simple test token that fails certain operations\n */\ncontract EvilToken is FaucetToken {\n using SafeMath for uint256;\n\n bool public fail;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) FaucetToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {\n fail = true;\n }\n\n function setFail(bool _fail) external {\n fail = _fail;\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool) {\n if (fail) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(amount);\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) external override returns (bool) {\n if (fail) {\n return false;\n }\n balanceOf[src] = balanceOf[src].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(amount);\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" + }, + "contracts/test/FaucetToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { StandardToken, NonStandardToken } from \"./ERC20.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title The Compound Faucet Test Token\n * @author Compound\n * @notice A simple test token that lets anyone get more of it.\n */\ncontract FaucetToken is StandardToken {\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf[_owner] += value;\n totalSupply += value;\n emit Transfer(address(this), _owner, value);\n }\n}\n\n/**\n * @title The Compound Faucet Test Token (non-standard)\n * @author Compound\n * @notice A simple test token that lets anyone get more of it.\n */\ncontract FaucetNonStandardToken is NonStandardToken {\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n NonStandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf[_owner] += value;\n totalSupply += value;\n emit Transfer(address(this), _owner, value);\n }\n}\n\n/**\n * @title The Compound Faucet Re-Entrant Test Token\n * @author Compound\n * @notice A test token that is malicious and tries to re-enter callers\n */\ncontract FaucetTokenReEntrantHarness {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 private totalSupply_;\n mapping(address => mapping(address => uint256)) private allowance_;\n mapping(address => uint256) private balanceOf_;\n\n bytes public reEntryCallData;\n string public reEntryFun;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n modifier reEnter(string memory funName) {\n string memory _reEntryFun = reEntryFun;\n if (compareStrings(_reEntryFun, funName)) {\n reEntryFun = \"\"; // Clear re-entry fun\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = msg.sender.call(reEntryCallData);\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 0) {\n revert(add(returndata, 0x20), returndatasize())\n }\n }\n }\n\n _;\n }\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol,\n bytes memory _reEntryCallData,\n string memory _reEntryFun\n ) {\n totalSupply_ = _initialAmount;\n balanceOf_[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n reEntryCallData = _reEntryCallData;\n reEntryFun = _reEntryFun;\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf_[_owner] += value;\n totalSupply_ += value;\n emit Transfer(address(this), _owner, value);\n }\n\n function totalSupply() public reEnter(\"totalSupply\") returns (uint256) {\n return totalSupply_;\n }\n\n function allowance(address owner, address spender) public reEnter(\"allowance\") returns (uint256 remaining) {\n return allowance_[owner][spender];\n }\n\n function approve(address spender, uint256 amount) public reEnter(\"approve\") returns (bool success) {\n _approve(msg.sender, spender, amount);\n return true;\n }\n\n function balanceOf(address owner) public reEnter(\"balanceOf\") returns (uint256 balance) {\n return balanceOf_[owner];\n }\n\n function transfer(address dst, uint256 amount) public reEnter(\"transfer\") returns (bool success) {\n _transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) public reEnter(\"transferFrom\") returns (bool success) {\n _transfer(src, dst, amount);\n _approve(src, msg.sender, allowance_[src][msg.sender].sub(amount));\n return true;\n }\n\n function _approve(address owner, address spender, uint256 amount) internal {\n require(spender != address(0), \"FaucetToken: approve to the zero address\");\n require(owner != address(0), \"FaucetToken: approve from the zero address\");\n allowance_[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n function _transfer(address src, address dst, uint256 amount) internal {\n require(dst != address(0), \"FaucetToken: transfer to the zero address\");\n balanceOf_[src] = balanceOf_[src].sub(amount);\n balanceOf_[dst] = balanceOf_[dst].add(amount);\n emit Transfer(src, dst, amount);\n }\n\n function compareStrings(string memory a, string memory b) internal pure returns (bool) {\n return keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)));\n }\n}\n" + }, + "contracts/test/FeeToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { FaucetToken } from \"./FaucetToken.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title Fee Token\n * @author Compound\n * @notice A simple test token that charges fees on transfer. Used to mock USDT.\n */\ncontract FeeToken is FaucetToken {\n using SafeMath for uint256;\n\n uint256 public basisPointFee;\n address public owner;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol,\n uint256 _basisPointFee,\n address _owner\n ) FaucetToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {\n basisPointFee = _basisPointFee;\n owner = _owner;\n }\n\n function transfer(address dst, uint256 amount) public override returns (bool) {\n uint256 fee = amount.mul(basisPointFee).div(10000);\n uint256 net = amount.sub(fee);\n balanceOf[owner] = balanceOf[owner].add(fee);\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(net);\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) public override returns (bool) {\n uint256 fee = amount.mul(basisPointFee).div(10000);\n uint256 net = amount.sub(fee);\n balanceOf[owner] = balanceOf[owner].add(fee);\n balanceOf[src] = balanceOf[src].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(net);\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" + }, + "contracts/test/HarnessMaxLoopsLimitHelper.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\n\ncontract HarnessMaxLoopsLimitHelper is MaxLoopsLimitHelper {\n function setMaxLoopsLimit(uint256 limit) external {\n _setMaxLoopsLimit(limit);\n }\n\n function ensureMaxLoops(uint256 limit) external view {\n _ensureMaxLoops(limit);\n }\n}\n" + }, + "contracts/test/lib/ApproveOrRevertHarness.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ApproveOrRevert } from \"../../lib/ApproveOrRevert.sol\";\n\ncontract ApproveOrRevertHarness {\n using ApproveOrRevert for IERC20Upgradeable;\n\n function approve(IERC20Upgradeable token, address spender, uint256 amount) external {\n token.approveOrRevert(spender, amount);\n }\n}\n" + }, + "contracts/test/lib/TokenDebtTrackerHarness.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { TokenDebtTracker } from \"../../lib/TokenDebtTracker.sol\";\n\ncontract TokenDebtTrackerHarness is TokenDebtTracker {\n function initialize() external initializer {\n __TokenDebtTracker_init();\n }\n\n function addTokenDebt(IERC20Upgradeable token, address user, uint256 amount) external {\n tokenDebt[token][user] += amount;\n totalTokenDebt[token] += amount;\n }\n\n function transferOutOrTrackDebt(IERC20Upgradeable token, address user, uint256 amount) external {\n _transferOutOrTrackDebt(token, user, amount);\n }\n\n function transferOutOrTrackDebtSkippingBalanceCheck(\n IERC20Upgradeable token,\n address user,\n uint256 amount\n ) external {\n _transferOutOrTrackDebtSkippingBalanceCheck(token, user, amount);\n }\n}\n" + }, + "contracts/test/MockDeflationaryToken.sol": { + "content": "pragma solidity 0.8.13;\n\ncontract MockDeflatingToken {\n string public constant NAME = \"Deflating Test Token\";\n string public constant SYMBOL = \"DTT\";\n uint8 public constant DECIMALS = 18;\n uint256 public totalSupply;\n mapping(address => uint256) public balanceOf;\n mapping(address => mapping(address => uint256)) public allowance;\n\n bytes32 public DOMAIN_SEPARATOR;\n // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n mapping(address => uint256) public nonces;\n\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n constructor(uint256 _totalSupply) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n DOMAIN_SEPARATOR = keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string NAME,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(NAME)),\n keccak256(bytes(\"1\")),\n chainId,\n address(this)\n )\n );\n _mint(msg.sender, _totalSupply);\n }\n\n function approve(address spender, uint256 value) external returns (bool) {\n _approve(msg.sender, spender, value);\n return true;\n }\n\n function transfer(address to, uint256 value) external returns (bool) {\n _transfer(msg.sender, to, value);\n return true;\n }\n\n function transferFrom(address from, address to, uint256 value) external returns (bool) {\n if (allowance[from][msg.sender] != type(uint256).max) {\n allowance[from][msg.sender] = allowance[from][msg.sender] - value;\n }\n _transfer(from, to, value);\n return true;\n }\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n require(deadline >= block.timestamp, \"EXPIRED\");\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR,\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))\n )\n );\n address recoveredAddress = ecrecover(digest, v, r, s);\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNATURE\");\n _approve(owner, spender, value);\n }\n\n function _mint(address to, uint256 value) internal {\n totalSupply = totalSupply + value;\n balanceOf[to] = balanceOf[to] + value;\n emit Transfer(address(0), to, value);\n }\n\n function _burn(address from, uint256 value) internal {\n balanceOf[from] = balanceOf[from] - value;\n totalSupply = totalSupply - value;\n emit Transfer(from, address(0), value);\n }\n\n function _approve(address owner, address spender, uint256 value) private {\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n function _transfer(address from, address to, uint256 value) private {\n uint256 burnAmount = value / 100;\n _burn(from, burnAmount);\n uint256 transferAmount = value - burnAmount;\n balanceOf[from] = balanceOf[from] - transferAmount;\n balanceOf[to] = balanceOf[to] + transferAmount;\n emit Transfer(from, to, transferAmount);\n }\n}\n" + }, + "contracts/test/Mocks/MockPriceOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { BinanceOracle } from \"@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol\";\nimport { ChainlinkOracle } from \"@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol\";\n\nimport { VToken } from \"../../VToken.sol\";\n\ncontract MockPriceOracle is ResilientOracleInterface {\n mapping(address => uint256) public assetPrices;\n\n //set price in 6 decimal precision\n // solhint-disable-next-line no-empty-blocks\n constructor() {}\n\n function setPrice(address asset, uint256 price) external {\n assetPrices[asset] = price;\n }\n\n // solhint-disable-next-line no-empty-blocks\n function updatePrice(address vToken) external override {}\n\n // solhint-disable-next-line no-empty-blocks\n function updateAssetPrice(address asset) external override {}\n\n function getPrice(address asset) external view returns (uint256) {\n return assetPrices[asset];\n }\n\n //https://compound.finance/docs/prices\n function getUnderlyingPrice(address vToken) public view override returns (uint256) {\n return assetPrices[VToken(vToken).underlying()];\n }\n}\n" + }, + "contracts/test/Mocks/MockToken.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockToken is ERC20 {\n uint8 private immutable _decimals;\n\n constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) {\n _decimals = decimals_;\n }\n\n function faucet(uint256 amount) external {\n _mint(msg.sender, amount);\n }\n\n function decimals() public view virtual override returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/test/SafeMath.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol\n// Subject to the MIT license.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction underflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts with custom message on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n" + }, + "contracts/test/UpgradedVToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\n/**\n * @title Venus's VToken Contract\n * @notice VTokens which wrap an EIP-20 underlying and are immutable\n * @author Venus\n */\ncontract UpgradedVToken is VToken {\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param riskManagement Addresses of risk fund contracts\n */\n\n /// @notice We added this new function to test contract upgrade\n function version() external pure returns (uint256) {\n return 2;\n }\n\n function initializeV2(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) public reinitializer(2) {\n super._initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_,\n admin_,\n accessControlManager_,\n riskManagement,\n reserveFactorMantissa_\n );\n }\n\n function getTokenUnderlying() public view returns (address) {\n return underlying;\n }\n}\n" + }, + "contracts/test/VTokenHarness.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\ncontract VTokenHarness is VToken {\n uint256 public blockNumber;\n uint256 public harnessExchangeRate;\n bool public harnessExchangeRateStored;\n\n mapping(address => bool) public failTransferToAddresses;\n\n function harnessSetAccrualBlockNumber(uint256 accrualBlockNumber_) external {\n accrualBlockNumber = accrualBlockNumber_;\n }\n\n function harnessSetBlockNumber(uint256 newBlockNumber) external {\n blockNumber = newBlockNumber;\n }\n\n function harnessFastForward(uint256 blocks) external {\n blockNumber += blocks;\n }\n\n function harnessSetBalance(address account, uint256 amount) external {\n accountTokens[account] = amount;\n }\n\n function harnessSetTotalSupply(uint256 totalSupply_) external {\n totalSupply = totalSupply_;\n }\n\n function harnessSetTotalBorrows(uint256 totalBorrows_) external {\n totalBorrows = totalBorrows_;\n }\n\n function harnessSetTotalReserves(uint256 totalReserves_) external {\n totalReserves = totalReserves_;\n }\n\n function harnessExchangeRateDetails(uint256 totalSupply_, uint256 totalBorrows_, uint256 totalReserves_) external {\n totalSupply = totalSupply_;\n totalBorrows = totalBorrows_;\n totalReserves = totalReserves_;\n }\n\n function harnessSetExchangeRate(uint256 exchangeRate) external {\n harnessExchangeRate = exchangeRate;\n harnessExchangeRateStored = true;\n }\n\n function harnessSetFailTransferToAddress(address to_, bool fail_) external {\n failTransferToAddresses[to_] = fail_;\n }\n\n function harnessMintFresh(address account, uint256 mintAmount) external {\n super._mintFresh(account, account, mintAmount);\n }\n\n function harnessRedeemFresh(address payable account, uint256 vTokenAmount, uint256 underlyingAmount) external {\n super._redeemFresh(account, vTokenAmount, underlyingAmount);\n }\n\n function harnessSetAccountBorrows(address account, uint256 principal, uint256 interestIndex) external {\n accountBorrows[account] = BorrowSnapshot({ principal: principal, interestIndex: interestIndex });\n }\n\n function harnessSetBorrowIndex(uint256 borrowIndex_) external {\n borrowIndex = borrowIndex_;\n }\n\n function harnessBorrowFresh(address payable account, uint256 borrowAmount) external {\n _borrowFresh(account, borrowAmount);\n }\n\n function harnessRepayBorrowFresh(address payer, address account, uint256 repayAmount) external {\n _repayBorrowFresh(payer, account, repayAmount);\n }\n\n function harnessLiquidateBorrowFresh(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VToken vTokenCollateral,\n bool skipLiquidityCheck\n ) external {\n _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n function harnessReduceReservesFresh(uint256 amount) external {\n return _reduceReservesFresh(amount);\n }\n\n function harnessSetReserveFactorFresh(uint256 newReserveFactorMantissa) external {\n _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n function harnessSetInterestRateModelFresh(InterestRateModel newInterestRateModel) external {\n _setInterestRateModelFresh(newInterestRateModel);\n }\n\n function harnessAccountBorrows(address account) external view returns (uint256 principal, uint256 interestIndex) {\n BorrowSnapshot memory snapshot = accountBorrows[account];\n return (snapshot.principal, snapshot.interestIndex);\n }\n\n function getBorrowRateMaxMantissa() external pure returns (uint256) {\n return MAX_BORROW_RATE_MANTISSA;\n }\n\n function harnessSetInterestRateModel(address newInterestRateModelAddress) public {\n interestRateModel = InterestRateModel(newInterestRateModelAddress);\n }\n\n function harnessCallPreBorrowHook(uint256 amount) public {\n comptroller.preBorrowHook(address(this), msg.sender, amount);\n }\n\n function _doTransferOut(address to, uint256 amount) internal override {\n require(failTransferToAddresses[to] == false, \"HARNESS_TOKEN_TRANSFER_OUT_FAILED\");\n return super._doTransferOut(to, amount);\n }\n\n function _exchangeRateStored() internal view override returns (uint256) {\n if (harnessExchangeRateStored) {\n return harnessExchangeRate;\n }\n return super._exchangeRateStored();\n }\n\n function _getBlockNumber() internal view override returns (uint256) {\n return blockNumber;\n }\n}\n" + }, + "contracts/VToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { VTokenInterface } from \"./VTokenInterfaces.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"./ComptrollerInterface.sol\";\nimport { TokenErrorReporter } from \"./ErrorReporter.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { IProtocolShareReserve } from \"./RiskFund/IProtocolShareReserve.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title VToken\n * @author Venus\n * @notice Each asset that is supported by a pool is integrated through an instance of the `VToken` contract. As outlined in the protocol overview,\n * each isolated pool creates its own `vToken` corresponding to an asset. Within a given pool, each included `vToken` is referred to as a market of\n * the pool. The main actions a user regularly interacts with in a market are:\n\n- mint/redeem of vTokens;\n- transfer of vTokens;\n- borrow/repay a loan on an underlying asset;\n- liquidate a borrow or liquidate/heal an account.\n\n * A user supplies the underlying asset to a pool by minting `vTokens`, where the corresponding `vToken` amount is determined by the `exchangeRate`.\n * The `exchangeRate` will change over time, dependent on a number of factors, some of which accrue interest. Additionally, once users have minted\n * `vToken` in a pool, they can borrow any asset in the isolated pool by using their `vToken` as collateral. In order to borrow an asset or use a `vToken`\n * as collateral, the user must be entered into each corresponding market (else, the `vToken` will not be considered collateral for a borrow). Note that\n * a user may borrow up to a portion of their collateral determined by the market’s collateral factor. However, if their borrowed amount exceeds an amount\n * calculated using the market’s corresponding liquidation threshold, the borrow is eligible for liquidation. When a user repays a borrow, they must also\n * pay off interest accrued on the borrow.\n * \n * The Venus protocol includes unique mechanisms for healing an account and liquidating an account. These actions are performed in the `Comptroller`\n * and consider all borrows and collateral for which a given account is entered within a market. These functions may only be called on an account with a\n * total collateral amount that is no larger than a universal `minLiquidatableCollateral` value, which is used for all markets within a `Comptroller`.\n * Both functions settle all of an account’s borrows, but `healAccount()` may add `badDebt` to a vToken. For more detail, see the description of\n * `healAccount()` and `liquidateAccount()` in the `Comptroller` summary section below.\n */\ncontract VToken is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n VTokenInterface,\n ExponentialNoError,\n TokenErrorReporter\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n uint256 internal constant DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA = 5e16; // 5%\n\n /*** Reentrancy Guard ***/\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(_notEntered, \"re-entered\");\n _notEntered = false;\n _;\n _notEntered = true; // get a gas-refund post-Istanbul\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param accessControlManager_ AccessControlManager contract address\n * @param riskManagement Addresses of risk & income related contracts\n * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n * @custom:error ZeroAddressNotAllowed is thrown when admin address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n */\n function initialize(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) external initializer {\n ensureNonzeroAddress(admin_);\n\n // Initialize the market\n _initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_,\n admin_,\n accessControlManager_,\n riskManagement,\n reserveFactorMantissa_\n );\n }\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return success True if the transfer succeeded, reverts otherwise\n * @custom:event Emits Transfer event on success\n * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n * @custom:access Not restricted\n */\n function transfer(address dst, uint256 amount) external override nonReentrant returns (bool) {\n _transferTokens(msg.sender, msg.sender, dst, amount);\n return true;\n }\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return success True if the transfer succeeded, reverts otherwise\n * @custom:event Emits Transfer event on success\n * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n * @custom:access Not restricted\n */\n function transferFrom(address src, address dst, uint256 amount) external override nonReentrant returns (bool) {\n _transferTokens(msg.sender, src, dst, amount);\n return true;\n }\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param amount The number of tokens that are approved (uint256.max means infinite)\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function approve(address spender, uint256 amount) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n transferAllowances[src][spender] = amount;\n emit Approval(src, spender, amount);\n return true;\n }\n\n /**\n * @notice Increase approval for `spender`\n * @param spender The address of the account which may transfer tokens\n * @param addedValue The number of additional tokens spender can transfer\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function increaseAllowance(address spender, uint256 addedValue) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n uint256 newAllowance = transferAllowances[src][spender];\n newAllowance += addedValue;\n transferAllowances[src][spender] = newAllowance;\n\n emit Approval(src, spender, newAllowance);\n return true;\n }\n\n /**\n * @notice Decreases approval for `spender`\n * @param spender The address of the account which may transfer tokens\n * @param subtractedValue The number of tokens to remove from total approval\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n uint256 currentAllowance = transferAllowances[src][spender];\n require(currentAllowance >= subtractedValue, \"decreased allowance below zero\");\n unchecked {\n currentAllowance -= subtractedValue;\n }\n\n transferAllowances[src][spender] = currentAllowance;\n\n emit Approval(src, spender, currentAllowance);\n return true;\n }\n\n /**\n * @notice Get the underlying balance of the `owner`\n * @dev This also accrues interest in a transaction\n * @param owner The address of the account to query\n * @return amount The amount of underlying owned by `owner`\n */\n function balanceOfUnderlying(address owner) external override returns (uint256) {\n Exp memory exchangeRate = Exp({ mantissa: exchangeRateCurrent() });\n return mul_ScalarTruncate(exchangeRate, accountTokens[owner]);\n }\n\n /**\n * @notice Returns the current total borrows plus accrued interest\n * @return totalBorrows The total borrows with interest\n */\n function totalBorrowsCurrent() external override nonReentrant returns (uint256) {\n accrueInterest();\n return totalBorrows;\n }\n\n /**\n * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex\n * @param account The address whose balance should be calculated after updating borrowIndex\n * @return borrowBalance The calculated balance\n */\n function borrowBalanceCurrent(address account) external override nonReentrant returns (uint256) {\n accrueInterest();\n return _borrowBalanceStored(account);\n }\n\n /**\n * @notice Sender supplies assets into the market and receives vTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param mintAmount The amount of the underlying asset to supply\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function mint(uint256 mintAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n _mintFresh(msg.sender, msg.sender, mintAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender calls on-behalf of minter. minter supplies assets into the market and receives vTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param minter User whom the supply will be attributed to\n * @param mintAmount The amount of the underlying asset to supply\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when minter address is zero\n */\n function mintBehalf(address minter, uint256 mintAmount) external override nonReentrant returns (uint256) {\n ensureNonzeroAddress(minter);\n\n accrueInterest();\n // _mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n _mintFresh(msg.sender, minter, mintAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender redeems vTokens in exchange for the underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemTokens The number of vTokens to redeem into underlying\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Redeem and Transfer events; may emit AccrueInterest\n * @custom:error RedeemTransferOutNotPossible is thrown when the protocol has insufficient cash\n * @custom:access Not restricted\n */\n function redeem(uint256 redeemTokens) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _redeemFresh emits redeem-specific logs on errors, so we don't need to\n _redeemFresh(msg.sender, redeemTokens, 0);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender redeems vTokens in exchange for a specified amount of underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemAmount The amount of underlying to receive from redeeming vTokens\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n */\n function redeemUnderlying(uint256 redeemAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _redeemFresh emits redeem-specific logs on errors, so we don't need to\n _redeemFresh(msg.sender, 0, redeemAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender borrows assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Borrow event; may emit AccrueInterest\n * @custom:error BorrowCashNotAvailable is thrown when the protocol has insufficient cash\n * @custom:access Not restricted\n */\n function borrow(uint256 borrowAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // borrowFresh emits borrow-specific logs on errors, so we don't need to\n _borrowFresh(msg.sender, borrowAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender repays their own borrow\n * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function repayBorrow(uint256 repayAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n _repayBorrowFresh(msg.sender, msg.sender, repayAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender repays a borrow belonging to borrower\n * @param borrower the account with the debt being payed off\n * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n _repayBorrowFresh(msg.sender, borrower, repayAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param borrower The borrower of this vToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n * @custom:access Not restricted\n */\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral\n ) external override returns (uint256) {\n _liquidateBorrow(msg.sender, borrower, repayAmount, vTokenCollateral, false);\n return NO_ERROR;\n }\n\n /**\n * @notice sets protocol share accumulated from liquidations\n * @dev must be equal or less than liquidation incentive - 1\n * @param newProtocolSeizeShareMantissa_ new protocol share mantissa\n * @custom:event Emits NewProtocolSeizeShare event on success\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:error ProtocolSeizeShareTooBig is thrown when the new seize share is too high\n * @custom:access Controlled by AccessControlManager\n */\n function setProtocolSeizeShare(uint256 newProtocolSeizeShareMantissa_) external {\n _checkAccessAllowed(\"setProtocolSeizeShare(uint256)\");\n uint256 liquidationIncentive = ComptrollerViewInterface(address(comptroller)).liquidationIncentiveMantissa();\n if (newProtocolSeizeShareMantissa_ + MANTISSA_ONE > liquidationIncentive) {\n revert ProtocolSeizeShareTooBig();\n }\n\n uint256 oldProtocolSeizeShareMantissa = protocolSeizeShareMantissa;\n protocolSeizeShareMantissa = newProtocolSeizeShareMantissa_;\n emit NewProtocolSeizeShare(oldProtocolSeizeShareMantissa, newProtocolSeizeShareMantissa_);\n }\n\n /**\n * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh\n * @dev Admin function to accrue interest and set a new reserve factor\n * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n * @custom:event Emits NewReserveFactor event; may emit AccrueInterest\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:error SetReserveFactorBoundsCheck is thrown when the new reserve factor is too high\n * @custom:access Controlled by AccessControlManager\n */\n function setReserveFactor(uint256 newReserveFactorMantissa) external override nonReentrant {\n _checkAccessAllowed(\"setReserveFactor(uint256)\");\n\n accrueInterest();\n _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n /**\n * @notice Accrues interest and reduces reserves by transferring to the protocol reserve contract\n * @param reduceAmount Amount of reduction to reserves\n * @custom:event Emits ReservesReduced event; may emit AccrueInterest\n * @custom:error ReduceReservesCashNotAvailable is thrown when the vToken does not have sufficient cash\n * @custom:error ReduceReservesCashValidation is thrown when trying to withdraw more cash than the reserves have\n * @custom:access Not restricted\n */\n function reduceReserves(uint256 reduceAmount) external override nonReentrant {\n accrueInterest();\n _reduceReservesFresh(reduceAmount);\n }\n\n /**\n * @notice The sender adds to reserves.\n * @param addAmount The amount of underlying token to add as reserves\n * @custom:event Emits ReservesAdded event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function addReserves(uint256 addAmount) external override nonReentrant {\n accrueInterest();\n _addReservesFresh(addAmount);\n }\n\n /**\n * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh\n * @dev Admin function to accrue interest and update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n * @custom:event Emits NewMarketInterestRateModel event; may emit AccrueInterest\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:access Controlled by AccessControlManager\n */\n function setInterestRateModel(InterestRateModel newInterestRateModel) external override {\n _checkAccessAllowed(\"setInterestRateModel(address)\");\n\n accrueInterest();\n _setInterestRateModelFresh(newInterestRateModel);\n }\n\n /**\n * @notice Repays a certain amount of debt, treats the rest of the borrow as bad debt, essentially\n * \"forgiving\" the borrower. Healing is a situation that should rarely happen. However, some pools\n * may list risky assets or be configured improperly – we want to still handle such cases gracefully.\n * We assume that Comptroller does the seizing, so this function is only available to Comptroller.\n * @dev This function does not call any Comptroller hooks (like \"healAllowed\"), because we assume\n * the Comptroller does all the necessary checks before calling this function.\n * @param payer account who repays the debt\n * @param borrower account to heal\n * @param repayAmount amount to repay\n * @custom:event Emits RepayBorrow, BadDebtIncreased events; may emit AccrueInterest\n * @custom:error HealBorrowUnauthorized is thrown when the request does not come from Comptroller\n * @custom:access Only Comptroller\n */\n function healBorrow(address payer, address borrower, uint256 repayAmount) external override nonReentrant {\n if (repayAmount != 0) {\n comptroller.preRepayHook(address(this), borrower);\n }\n\n if (msg.sender != address(comptroller)) {\n revert HealBorrowUnauthorized();\n }\n\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n uint256 totalBorrowsNew = totalBorrows;\n\n uint256 actualRepayAmount;\n if (repayAmount != 0) {\n // _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n // We violate checks-effects-interactions here to account for tokens that take transfer fees\n actualRepayAmount = _doTransferIn(payer, repayAmount);\n totalBorrowsNew = totalBorrowsNew - actualRepayAmount;\n emit RepayBorrow(\n payer,\n borrower,\n actualRepayAmount,\n accountBorrowsPrev - actualRepayAmount,\n totalBorrowsNew\n );\n }\n\n // The transaction will fail if trying to repay too much\n uint256 badDebtDelta = accountBorrowsPrev - actualRepayAmount;\n if (badDebtDelta != 0) {\n uint256 badDebtOld = badDebt;\n uint256 badDebtNew = badDebtOld + badDebtDelta;\n totalBorrowsNew = totalBorrowsNew - badDebtDelta;\n badDebt = badDebtNew;\n\n // We treat healing as \"repayment\", where vToken is the payer\n emit RepayBorrow(address(this), borrower, badDebtDelta, 0, totalBorrowsNew);\n emit BadDebtIncreased(borrower, badDebtDelta, badDebtOld, badDebtNew);\n }\n\n accountBorrows[borrower].principal = 0;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n emit HealBorrow(payer, borrower, repayAmount);\n }\n\n /**\n * @notice The extended version of liquidations, callable only by Comptroller. May skip\n * the close factor check. The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n * @custom:error ForceLiquidateBorrowUnauthorized is thrown when the request does not come from Comptroller\n * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n * @custom:access Only Comptroller\n */\n function forceLiquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) external override {\n if (msg.sender != address(comptroller)) {\n revert ForceLiquidateBorrowUnauthorized();\n }\n _liquidateBorrow(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Will fail unless called by another vToken during the process of liquidation.\n * It's absolutely critical to use msg.sender as the borrowed vToken and not a parameter.\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of vTokens to seize\n * @custom:event Emits Transfer, ReservesAdded events\n * @custom:error LiquidateSeizeLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:access Not restricted\n */\n function seize(address liquidator, address borrower, uint256 seizeTokens) external override nonReentrant {\n _seize(msg.sender, liquidator, borrower, seizeTokens);\n }\n\n /**\n * @notice Updates bad debt\n * @dev Called only when bad debt is recovered from auction\n * @param recoveredAmount_ The amount of bad debt recovered\n * @custom:event Emits BadDebtRecovered event\n * @custom:access Only Shortfall contract\n */\n function badDebtRecovered(uint256 recoveredAmount_) external {\n require(msg.sender == shortfall, \"only shortfall contract can update bad debt\");\n require(recoveredAmount_ <= badDebt, \"more than bad debt recovered from auction\");\n\n uint256 badDebtOld = badDebt;\n uint256 badDebtNew = badDebtOld - recoveredAmount_;\n badDebt = badDebtNew;\n\n emit BadDebtRecovered(badDebtOld, badDebtNew);\n }\n\n /**\n * @notice Sets protocol share reserve contract address\n * @param protocolShareReserve_ The address of the protocol share reserve contract\n * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n * @custom:access Only Governance\n */\n function setProtocolShareReserve(address payable protocolShareReserve_) external onlyOwner {\n _setProtocolShareReserve(protocolShareReserve_);\n }\n\n /**\n * @notice Sets shortfall contract address\n * @param shortfall_ The address of the shortfall contract\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n * @custom:access Only Governance\n */\n function setShortfallContract(address shortfall_) external onlyOwner {\n _setShortfallContract(shortfall_);\n }\n\n /**\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\n * @param token The address of the ERC-20 token to sweep\n * @custom:access Only Governance\n */\n function sweepToken(IERC20Upgradeable token) external override {\n require(msg.sender == owner(), \"VToken::sweepToken: only admin can sweep tokens\");\n require(address(token) != underlying, \"VToken::sweepToken: can not sweep underlying token\");\n uint256 balance = token.balanceOf(address(this));\n token.safeTransfer(owner(), balance);\n\n emit SweepToken(address(token));\n }\n\n /**\n * @notice Get the current allowance from `owner` for `spender`\n * @param owner The address of the account which owns the tokens to be spent\n * @param spender The address of the account which may transfer tokens\n * @return amount The number of tokens allowed to be spent (type(uint256).max means infinite)\n */\n function allowance(address owner, address spender) external view override returns (uint256) {\n return transferAllowances[owner][spender];\n }\n\n /**\n * @notice Get the token balance of the `owner`\n * @param owner The address of the account to query\n * @return amount The number of tokens owned by `owner`\n */\n function balanceOf(address owner) external view override returns (uint256) {\n return accountTokens[owner];\n }\n\n /**\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\n * @param account Address of the account to snapshot\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return vTokenBalance User's balance of vTokens\n * @return borrowBalance Amount owed in terms of underlying\n * @return exchangeRate Stored exchange rate\n */\n function getAccountSnapshot(\n address account\n )\n external\n view\n override\n returns (uint256 error, uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRate)\n {\n return (NO_ERROR, accountTokens[account], _borrowBalanceStored(account), _exchangeRateStored());\n }\n\n /**\n * @notice Get cash balance of this vToken in the underlying asset\n * @return cash The quantity of underlying asset owned by this contract\n */\n function getCash() external view override returns (uint256) {\n return _getCashPrior();\n }\n\n /**\n * @notice Returns the current per-block borrow interest rate for this vToken\n * @return rate The borrow interest rate per block, scaled by 1e18\n */\n function borrowRatePerBlock() external view override returns (uint256) {\n return interestRateModel.getBorrowRate(_getCashPrior(), totalBorrows, totalReserves, badDebt);\n }\n\n /**\n * @notice Returns the current per-block supply interest rate for this v\n * @return rate The supply interest rate per block, scaled by 1e18\n */\n function supplyRatePerBlock() external view override returns (uint256) {\n return\n interestRateModel.getSupplyRate(\n _getCashPrior(),\n totalBorrows,\n totalReserves,\n reserveFactorMantissa,\n badDebt\n );\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return borrowBalance The calculated balance\n */\n function borrowBalanceStored(address account) external view override returns (uint256) {\n return _borrowBalanceStored(account);\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the VToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() external view override returns (uint256) {\n return _exchangeRateStored();\n }\n\n /**\n * @notice Accrue interest then return the up-to-date exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function exchangeRateCurrent() public override nonReentrant returns (uint256) {\n accrueInterest();\n return _exchangeRateStored();\n }\n\n /**\n * @notice Applies accrued interest to total borrows and reserves\n * @dev This calculates interest accrued from the last checkpointed block\n * up to the current block and writes new checkpoint to storage.\n * @return Always NO_ERROR\n * @custom:event Emits AccrueInterest event on success\n * @custom:access Not restricted\n */\n function accrueInterest() public virtual override returns (uint256) {\n /* Remember the initial block number */\n uint256 currentBlockNumber = _getBlockNumber();\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\n\n /* Short-circuit accumulating 0 interest */\n if (accrualBlockNumberPrior == currentBlockNumber) {\n return NO_ERROR;\n }\n\n /* Read the previous values out of storage */\n uint256 cashPrior = _getCashPrior();\n uint256 borrowsPrior = totalBorrows;\n uint256 reservesPrior = totalReserves;\n uint256 borrowIndexPrior = borrowIndex;\n\n /* Calculate the current borrow interest rate */\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior, badDebt);\n require(borrowRateMantissa <= MAX_BORROW_RATE_MANTISSA, \"borrow rate is absurdly high\");\n\n /* Calculate the number of blocks elapsed since the last accrual */\n uint256 blockDelta = currentBlockNumber - accrualBlockNumberPrior;\n\n /*\n * Calculate the interest accumulated into borrows and reserves and the new index:\n * simpleInterestFactor = borrowRate * blockDelta\n * interestAccumulated = simpleInterestFactor * totalBorrows\n * totalBorrowsNew = interestAccumulated + totalBorrows\n * totalReservesNew = interestAccumulated * reserveFactor + totalReserves\n * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex\n */\n\n Exp memory simpleInterestFactor = mul_(Exp({ mantissa: borrowRateMantissa }), blockDelta);\n uint256 interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior);\n uint256 totalBorrowsNew = interestAccumulated + borrowsPrior;\n uint256 totalReservesNew = mul_ScalarTruncateAddUInt(\n Exp({ mantissa: reserveFactorMantissa }),\n interestAccumulated,\n reservesPrior\n );\n uint256 borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the previously calculated values into storage */\n accrualBlockNumber = currentBlockNumber;\n borrowIndex = borrowIndexNew;\n totalBorrows = totalBorrowsNew;\n totalReserves = totalReservesNew;\n\n /* We emit an AccrueInterest event */\n emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);\n\n return NO_ERROR;\n }\n\n /**\n * @notice User supplies assets into the market and receives vTokens in exchange\n * @dev Assumes interest has already been accrued up to the current block\n * @param payer The address of the account which is sending the assets for supply\n * @param minter The address of the account which is supplying the assets\n * @param mintAmount The amount of the underlying asset to supply\n */\n function _mintFresh(address payer, address minter, uint256 mintAmount) internal {\n /* Fail if mint not allowed */\n comptroller.preMintHook(address(this), minter, mintAmount);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert MintFreshnessCheck();\n }\n\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call `_doTransferIn` for the minter and the mintAmount.\n * `_doTransferIn` reverts if anything goes wrong, since we can't be sure if\n * side-effects occurred. The function returns the amount actually transferred,\n * in case of a fee. On success, the vToken holds an additional `actualMintAmount`\n * of cash.\n */\n uint256 actualMintAmount = _doTransferIn(payer, mintAmount);\n\n /*\n * We get the current exchange rate and calculate the number of vTokens to be minted:\n * mintTokens = actualMintAmount / exchangeRate\n */\n\n uint256 mintTokens = div_(actualMintAmount, exchangeRate);\n\n /*\n * We calculate the new total supply of vTokens and minter token balance, checking for overflow:\n * totalSupplyNew = totalSupply + mintTokens\n * accountTokensNew = accountTokens[minter] + mintTokens\n * And write them into storage\n */\n totalSupply = totalSupply + mintTokens;\n uint256 balanceAfter = accountTokens[minter] + mintTokens;\n accountTokens[minter] = balanceAfter;\n\n /* We emit a Mint event, and a Transfer event */\n emit Mint(minter, actualMintAmount, mintTokens, balanceAfter);\n emit Transfer(address(0), minter, mintTokens);\n }\n\n /**\n * @notice User redeems vTokens in exchange for the underlying asset\n * @dev Assumes interest has already been accrued up to the current block\n * @param redeemer The address of the account which is redeeming the tokens\n * @param redeemTokensIn The number of vTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n * @param redeemAmountIn The number of underlying tokens to receive from redeeming vTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n */\n function _redeemFresh(address redeemer, uint256 redeemTokensIn, uint256 redeemAmountIn) internal {\n require(redeemTokensIn == 0 || redeemAmountIn == 0, \"one of redeemTokensIn or redeemAmountIn must be zero\");\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert RedeemFreshnessCheck();\n }\n\n /* exchangeRate = invoke Exchange Rate Stored() */\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n uint256 redeemTokens;\n uint256 redeemAmount;\n\n /* If redeemTokensIn > 0: */\n if (redeemTokensIn > 0) {\n /*\n * We calculate the exchange rate and the amount of underlying to be redeemed:\n * redeemTokens = redeemTokensIn\n */\n redeemTokens = redeemTokensIn;\n } else {\n /*\n * We get the current exchange rate and calculate the amount to be redeemed:\n * redeemTokens = redeemAmountIn / exchangeRate\n */\n redeemTokens = div_(redeemAmountIn, exchangeRate);\n\n uint256 _redeemAmount = mul_(redeemTokens, exchangeRate);\n if (_redeemAmount != 0 && _redeemAmount != redeemAmountIn) redeemTokens++; // round up\n }\n\n // redeemAmount = exchangeRate * redeemTokens\n redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokens);\n\n // Revert if amount is zero\n if (redeemAmount == 0) {\n revert(\"redeemAmount is zero\");\n }\n\n /* Fail if redeem not allowed */\n comptroller.preRedeemHook(address(this), redeemer, redeemTokens);\n\n /* Fail gracefully if protocol has insufficient cash */\n if (_getCashPrior() - totalReserves < redeemAmount) {\n revert RedeemTransferOutNotPossible();\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We write the previously calculated values into storage.\n * Note: Avoid token reentrancy attacks by writing reduced supply before external transfer.\n */\n totalSupply = totalSupply - redeemTokens;\n uint256 balanceAfter = accountTokens[redeemer] - redeemTokens;\n accountTokens[redeemer] = balanceAfter;\n\n /*\n * We invoke _doTransferOut for the redeemer and the redeemAmount.\n * On success, the vToken has redeemAmount less of cash.\n * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n _doTransferOut(redeemer, redeemAmount);\n\n /* We emit a Transfer event, and a Redeem event */\n emit Transfer(redeemer, address(this), redeemTokens);\n emit Redeem(redeemer, redeemAmount, redeemTokens, balanceAfter);\n }\n\n /**\n * @notice Users borrow assets from the protocol to their own address\n * @param borrower User who borrows the assets\n * @param borrowAmount The amount of the underlying asset to borrow\n */\n function _borrowFresh(address borrower, uint256 borrowAmount) internal {\n /* Fail if borrow not allowed */\n comptroller.preBorrowHook(address(this), borrower, borrowAmount);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert BorrowFreshnessCheck();\n }\n\n /* Fail gracefully if protocol has insufficient underlying cash */\n if (_getCashPrior() - totalReserves < borrowAmount) {\n revert BorrowCashNotAvailable();\n }\n\n /*\n * We calculate the new borrower and total borrow balances, failing on overflow:\n * accountBorrowNew = accountBorrow + borrowAmount\n * totalBorrowsNew = totalBorrows + borrowAmount\n */\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n uint256 accountBorrowsNew = accountBorrowsPrev + borrowAmount;\n uint256 totalBorrowsNew = totalBorrows + borrowAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We write the previously calculated values into storage.\n * Note: Avoid token reentrancy attacks by writing increased borrow before external transfer.\n `*/\n accountBorrows[borrower].principal = accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n /*\n * We invoke _doTransferOut for the borrower and the borrowAmount.\n * On success, the vToken borrowAmount less of cash.\n * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n _doTransferOut(borrower, borrowAmount);\n\n /* We emit a Borrow event */\n emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);\n }\n\n /**\n * @notice Borrows are repaid by another user (possibly the borrower).\n * @param payer the account paying off the borrow\n * @param borrower the account with the debt being payed off\n * @param repayAmount the amount of underlying tokens being returned, or type(uint256).max for the full outstanding amount\n * @return (uint) the actual repayment amount.\n */\n function _repayBorrowFresh(address payer, address borrower, uint256 repayAmount) internal returns (uint256) {\n /* Fail if repayBorrow not allowed */\n comptroller.preRepayHook(address(this), borrower);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert RepayBorrowFreshnessCheck();\n }\n\n /* We fetch the amount the borrower owes, with accumulated interest */\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n\n uint256 repayAmountFinal = repayAmount >= accountBorrowsPrev ? accountBorrowsPrev : repayAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call _doTransferIn for the payer and the repayAmount\n * On success, the vToken holds an additional repayAmount of cash.\n * _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n * it returns the amount actually transferred, in case of a fee.\n */\n uint256 actualRepayAmount = _doTransferIn(payer, repayAmountFinal);\n\n /*\n * We calculate the new borrower and total borrow balances, failing on underflow:\n * accountBorrowsNew = accountBorrows - actualRepayAmount\n * totalBorrowsNew = totalBorrows - actualRepayAmount\n */\n uint256 accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;\n uint256 totalBorrowsNew = totalBorrows - actualRepayAmount;\n\n /* We write the previously calculated values into storage */\n accountBorrows[borrower].principal = accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n /* We emit a RepayBorrow event */\n emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew);\n\n return actualRepayAmount;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n */\n function _liquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) internal nonReentrant {\n accrueInterest();\n\n uint256 error = vTokenCollateral.accrueInterest();\n if (error != NO_ERROR) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed\n revert LiquidateAccrueCollateralInterestFailed(error);\n }\n\n // _liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\n _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n /**\n * @notice The liquidator liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n */\n function _liquidateBorrowFresh(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) internal {\n /* Fail if liquidate not allowed */\n comptroller.preLiquidateHook(\n address(this),\n address(vTokenCollateral),\n borrower,\n repayAmount,\n skipLiquidityCheck\n );\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert LiquidateFreshnessCheck();\n }\n\n /* Verify vTokenCollateral market's block number equals current block number */\n if (vTokenCollateral.accrualBlockNumber() != _getBlockNumber()) {\n revert LiquidateCollateralFreshnessCheck();\n }\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n revert LiquidateLiquidatorIsBorrower();\n }\n\n /* Fail if repayAmount = 0 */\n if (repayAmount == 0) {\n revert LiquidateCloseAmountIsZero();\n }\n\n /* Fail if repayAmount = type(uint256).max */\n if (repayAmount == type(uint256).max) {\n revert LiquidateCloseAmountIsUintMax();\n }\n\n /* Fail if repayBorrow fails */\n uint256 actualRepayAmount = _repayBorrowFresh(liquidator, borrower, repayAmount);\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We calculate the number of collateral tokens that will be seized */\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller.liquidateCalculateSeizeTokens(\n address(this),\n address(vTokenCollateral),\n actualRepayAmount\n );\n require(amountSeizeError == NO_ERROR, \"LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED\");\n\n /* Revert if borrower collateral token balance < seizeTokens */\n require(vTokenCollateral.balanceOf(borrower) >= seizeTokens, \"LIQUIDATE_SEIZE_TOO_MUCH\");\n\n // If this is also the collateral, call _seize internally to avoid re-entrancy, otherwise make an external call\n if (address(vTokenCollateral) == address(this)) {\n _seize(address(this), liquidator, borrower, seizeTokens);\n } else {\n vTokenCollateral.seize(liquidator, borrower, seizeTokens);\n }\n\n /* We emit a LiquidateBorrow event */\n emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(vTokenCollateral), seizeTokens);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another VToken.\n * It's absolutely critical to use msg.sender as the seizer vToken and not a parameter.\n * @param seizerContract The contract seizing the collateral (either borrowed vToken or Comptroller)\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of vTokens to seize\n */\n function _seize(address seizerContract, address liquidator, address borrower, uint256 seizeTokens) internal {\n /* Fail if seize not allowed */\n comptroller.preSeizeHook(address(this), seizerContract, liquidator, borrower);\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n revert LiquidateSeizeLiquidatorIsBorrower();\n }\n\n /*\n * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\n * borrowerTokensNew = accountTokens[borrower] - seizeTokens\n * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\n */\n uint256 liquidationIncentiveMantissa = ComptrollerViewInterface(address(comptroller))\n .liquidationIncentiveMantissa();\n uint256 numerator = mul_(seizeTokens, Exp({ mantissa: protocolSeizeShareMantissa }));\n uint256 protocolSeizeTokens = div_(numerator, Exp({ mantissa: liquidationIncentiveMantissa }));\n uint256 liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n uint256 protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens);\n uint256 totalReservesNew = totalReserves + protocolSeizeAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the calculated values into storage */\n totalReserves = totalReservesNew;\n totalSupply = totalSupply - protocolSeizeTokens;\n accountTokens[borrower] = accountTokens[borrower] - seizeTokens;\n accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens;\n\n /* Emit a Transfer event */\n emit Transfer(borrower, liquidator, liquidatorSeizeTokens);\n emit Transfer(borrower, address(this), protocolSeizeTokens);\n emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew);\n }\n\n function _setComptroller(ComptrollerInterface newComptroller) internal {\n ComptrollerInterface oldComptroller = comptroller;\n // Ensure invoke comptroller.isComptroller() returns true\n require(newComptroller.isComptroller(), \"marker method returned false\");\n\n // Set market's comptroller to newComptroller\n comptroller = newComptroller;\n\n // Emit NewComptroller(oldComptroller, newComptroller)\n emit NewComptroller(oldComptroller, newComptroller);\n }\n\n /**\n * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)\n * @dev Admin function to set a new reserve factor\n * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n */\n function _setReserveFactorFresh(uint256 newReserveFactorMantissa) internal {\n // Verify market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert SetReserveFactorFreshCheck();\n }\n\n // Check newReserveFactor ≤ maxReserveFactor\n if (newReserveFactorMantissa > MAX_RESERVE_FACTOR_MANTISSA) {\n revert SetReserveFactorBoundsCheck();\n }\n\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\n reserveFactorMantissa = newReserveFactorMantissa;\n\n emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);\n }\n\n /**\n * @notice Add reserves by transferring from caller\n * @dev Requires fresh interest accrual\n * @param addAmount Amount of addition to reserves\n * @return actualAddAmount The actual amount added, excluding the potential token fees\n */\n function _addReservesFresh(uint256 addAmount) internal returns (uint256) {\n // totalReserves + actualAddAmount\n uint256 totalReservesNew;\n uint256 actualAddAmount;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert AddReservesFactorFreshCheck(actualAddAmount);\n }\n\n actualAddAmount = _doTransferIn(msg.sender, addAmount);\n totalReservesNew = totalReserves + actualAddAmount;\n totalReserves = totalReservesNew;\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\n\n return actualAddAmount;\n }\n\n /**\n * @notice Reduces reserves by transferring to the protocol reserve contract\n * @dev Requires fresh interest accrual\n * @param reduceAmount Amount of reduction to reserves\n */\n function _reduceReservesFresh(uint256 reduceAmount) internal {\n // totalReserves - reduceAmount\n uint256 totalReservesNew;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert ReduceReservesFreshCheck();\n }\n\n // Fail gracefully if protocol has insufficient underlying cash\n if (_getCashPrior() < reduceAmount) {\n revert ReduceReservesCashNotAvailable();\n }\n\n // Check reduceAmount ≤ reserves[n] (totalReserves)\n if (reduceAmount > totalReserves) {\n revert ReduceReservesCashValidation();\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n totalReservesNew = totalReserves - reduceAmount;\n\n // Store reserves[n+1] = reserves[n] - reduceAmount\n totalReserves = totalReservesNew;\n\n // _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n // Transferring an underlying asset to the protocolShareReserve contract to channel the funds for different use.\n _doTransferOut(protocolShareReserve, reduceAmount);\n\n // Update the pool asset's state in the protocol share reserve for the above transfer.\n IProtocolShareReserve(protocolShareReserve).updateAssetsState(address(comptroller), underlying);\n\n emit ReservesReduced(protocolShareReserve, reduceAmount, totalReservesNew);\n }\n\n /**\n * @notice updates the interest rate model (*requires fresh interest accrual)\n * @dev Admin function to update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n */\n function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal {\n // Used to store old model for use in the event that is emitted on success\n InterestRateModel oldInterestRateModel;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert SetInterestRateModelFreshCheck();\n }\n\n // Track the market's current interest rate model\n oldInterestRateModel = interestRateModel;\n\n // Ensure invoke newInterestRateModel.isInterestRateModel() returns true\n require(newInterestRateModel.isInterestRateModel(), \"marker method returned false\");\n\n // Set the interest rate model to newInterestRateModel\n interestRateModel = newInterestRateModel;\n\n // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)\n emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);\n }\n\n /*** Safe Token ***/\n\n /**\n * @dev Similar to ERC-20 transfer, but handles tokens that have transfer fees.\n * This function returns the actual amount received,\n * which may be less than `amount` if there is a fee attached to the transfer.\n * @param from Sender of the underlying tokens\n * @param amount Amount of underlying to transfer\n * @return Actual amount received\n */\n function _doTransferIn(address from, uint256 amount) internal virtual returns (uint256) {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n uint256 balanceBefore = token.balanceOf(address(this));\n token.safeTransferFrom(from, address(this), amount);\n uint256 balanceAfter = token.balanceOf(address(this));\n // Return the amount that was *actually* transferred\n return balanceAfter - balanceBefore;\n }\n\n /**\n * @dev Just a regular ERC-20 transfer, reverts on failure\n * @param to Receiver of the underlying tokens\n * @param amount Amount of underlying to transfer\n */\n function _doTransferOut(address to, uint256 amount) internal virtual {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n token.safeTransfer(to, amount);\n }\n\n /**\n * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`\n * @dev Called by both `transfer` and `transferFrom` internally\n * @param spender The address of the account performing the transfer\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param tokens The number of tokens to transfer\n */\n function _transferTokens(address spender, address src, address dst, uint256 tokens) internal {\n /* Fail if transfer not allowed */\n comptroller.preTransferHook(address(this), src, dst, tokens);\n\n /* Do not allow self-transfers */\n if (src == dst) {\n revert TransferNotAllowed();\n }\n\n /* Get the allowance, infinite for the account owner */\n uint256 startingAllowance;\n if (spender == src) {\n startingAllowance = type(uint256).max;\n } else {\n startingAllowance = transferAllowances[src][spender];\n }\n\n /* Do the calculations, checking for {under,over}flow */\n uint256 allowanceNew = startingAllowance - tokens;\n uint256 srcTokensNew = accountTokens[src] - tokens;\n uint256 dstTokensNew = accountTokens[dst] + tokens;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n\n accountTokens[src] = srcTokensNew;\n accountTokens[dst] = dstTokensNew;\n\n /* Eat some of the allowance (if necessary) */\n if (startingAllowance != type(uint256).max) {\n transferAllowances[src][spender] = allowanceNew;\n }\n\n /* We emit a Transfer event */\n emit Transfer(src, dst, tokens);\n }\n\n /**\n * @notice Initialize the money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param accessControlManager_ AccessControlManager contract address\n * @param riskManagement Addresses of risk & income related contracts\n * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n */\n function _initialize(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n require(accrualBlockNumber == 0 && borrowIndex == 0, \"market may only be initialized once\");\n\n // Set initial exchange rate\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\n require(initialExchangeRateMantissa > 0, \"initial exchange rate must be greater than zero.\");\n\n _setComptroller(comptroller_);\n\n // Initialize block number and borrow index (block number mocks depend on comptroller being set)\n accrualBlockNumber = _getBlockNumber();\n borrowIndex = MANTISSA_ONE;\n\n // Set the interest rate model (depends on block number / borrow index)\n _setInterestRateModelFresh(interestRateModel_);\n\n _setReserveFactorFresh(reserveFactorMantissa_);\n\n name = name_;\n symbol = symbol_;\n decimals = decimals_;\n _setShortfallContract(riskManagement.shortfall);\n _setProtocolShareReserve(riskManagement.protocolShareReserve);\n protocolSeizeShareMantissa = DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA;\n\n // Set underlying and sanity check it\n underlying = underlying_;\n IERC20Upgradeable(underlying).totalSupply();\n\n // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\n _notEntered = true;\n _transferOwnership(admin_);\n }\n\n function _setShortfallContract(address shortfall_) internal {\n ensureNonzeroAddress(shortfall_);\n address oldShortfall = shortfall;\n shortfall = shortfall_;\n emit NewShortfallContract(oldShortfall, shortfall_);\n }\n\n function _setProtocolShareReserve(address payable protocolShareReserve_) internal {\n ensureNonzeroAddress(protocolShareReserve_);\n address oldProtocolShareReserve = address(protocolShareReserve);\n protocolShareReserve = protocolShareReserve_;\n emit NewProtocolShareReserve(oldProtocolShareReserve, address(protocolShareReserve_));\n }\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying tokens owned by this contract\n */\n function _getCashPrior() internal view virtual returns (uint256) {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n return token.balanceOf(address(this));\n }\n\n /**\n * @dev Function to simply retrieve block number\n * This exists mainly for inheriting test contracts to stub this result.\n * @return Current block number\n */\n function _getBlockNumber() internal view virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return borrowBalance the calculated balance\n */\n function _borrowBalanceStored(address account) internal view returns (uint256) {\n /* Get borrowBalance and borrowIndex */\n BorrowSnapshot memory borrowSnapshot = accountBorrows[account];\n\n /* If borrowBalance = 0 then borrowIndex is likely also 0.\n * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.\n */\n if (borrowSnapshot.principal == 0) {\n return 0;\n }\n\n /* Calculate new borrow balance using the interest index:\n * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex\n */\n uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex;\n\n return principalTimesIndex / borrowSnapshot.interestIndex;\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the VToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function _exchangeRateStored() internal view virtual returns (uint256) {\n uint256 _totalSupply = totalSupply;\n if (_totalSupply == 0) {\n /*\n * If there are no tokens minted:\n * exchangeRate = initialExchangeRate\n */\n return initialExchangeRateMantissa;\n }\n /*\n * Otherwise:\n * exchangeRate = (totalCash + totalBorrows + badDebt - totalReserves) / totalSupply\n */\n uint256 totalCash = _getCashPrior();\n uint256 cashPlusBorrowsMinusReserves = totalCash + totalBorrows + badDebt - totalReserves;\n uint256 exchangeRate = (cashPlusBorrowsMinusReserves * EXP_SCALE) / _totalSupply;\n\n return exchangeRate;\n }\n}\n" + }, + "contracts/VTokenInterfaces.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\n\n/**\n * @title VTokenStorage\n * @author Venus\n * @notice Storage layout used by the `VToken` contract\n */\n// solhint-disable-next-line max-states-count\ncontract VTokenStorage {\n /**\n * @notice Container for borrow balance information\n * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action\n * @member interestIndex Global borrowIndex as of the most recent balance-changing action\n */\n struct BorrowSnapshot {\n uint256 principal;\n uint256 interestIndex;\n }\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n bool internal _notEntered;\n\n /**\n * @notice Underlying asset for this VToken\n */\n address public underlying;\n\n /**\n * @notice EIP-20 token name for this token\n */\n string public name;\n\n /**\n * @notice EIP-20 token symbol for this token\n */\n string public symbol;\n\n /**\n * @notice EIP-20 token decimals for this token\n */\n uint8 public decimals;\n\n /**\n * @notice Protocol share Reserve contract address\n */\n address payable public protocolShareReserve;\n\n // Maximum borrow rate that can ever be applied (.0005% / block)\n uint256 internal constant MAX_BORROW_RATE_MANTISSA = 0.0005e16;\n\n // Maximum fraction of interest that can be set aside for reserves\n uint256 internal constant MAX_RESERVE_FACTOR_MANTISSA = 1e18;\n\n /**\n * @notice Contract which oversees inter-vToken operations\n */\n ComptrollerInterface public comptroller;\n\n /**\n * @notice Model which tells what the current interest rate should be\n */\n InterestRateModel public interestRateModel;\n\n // Initial exchange rate used when minting the first VTokens (used when totalSupply = 0)\n uint256 internal initialExchangeRateMantissa;\n\n /**\n * @notice Fraction of interest currently set aside for reserves\n */\n uint256 public reserveFactorMantissa;\n\n /**\n * @notice Block number that interest was last accrued at\n */\n uint256 public accrualBlockNumber;\n\n /**\n * @notice Accumulator of the total earned interest rate since the opening of the market\n */\n uint256 public borrowIndex;\n\n /**\n * @notice Total amount of outstanding borrows of the underlying in this market\n */\n uint256 public totalBorrows;\n\n /**\n * @notice Total amount of reserves of the underlying held in this market\n */\n uint256 public totalReserves;\n\n /**\n * @notice Total number of tokens in circulation\n */\n uint256 public totalSupply;\n\n /**\n * @notice Total bad debt of the market\n */\n uint256 public badDebt;\n\n // Official record of token balances for each account\n mapping(address => uint256) internal accountTokens;\n\n // Approved token transfer amounts on behalf of others\n mapping(address => mapping(address => uint256)) internal transferAllowances;\n\n // Mapping of account addresses to outstanding borrow balances\n mapping(address => BorrowSnapshot) internal accountBorrows;\n\n /**\n * @notice Share of seized collateral that is added to reserves\n */\n uint256 public protocolSeizeShareMantissa;\n\n /**\n * @notice Storage of Shortfall contract address\n */\n address public shortfall;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n\n/**\n * @title VTokenInterface\n * @author Venus\n * @notice Interface implemented by the `VToken` contract\n */\nabstract contract VTokenInterface is VTokenStorage {\n struct RiskManagementInit {\n address shortfall;\n address payable protocolShareReserve;\n }\n\n /*** Market Events ***/\n\n /**\n * @notice Event emitted when interest is accrued\n */\n event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when tokens are minted\n */\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens, uint256 accountBalance);\n\n /**\n * @notice Event emitted when tokens are redeemed\n */\n event Redeem(address indexed redeemer, uint256 redeemAmount, uint256 redeemTokens, uint256 accountBalance);\n\n /**\n * @notice Event emitted when underlying is borrowed\n */\n event Borrow(address indexed borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when a borrow is repaid\n */\n event RepayBorrow(\n address indexed payer,\n address indexed borrower,\n uint256 repayAmount,\n uint256 accountBorrows,\n uint256 totalBorrows\n );\n\n /**\n * @notice Event emitted when bad debt is accumulated on a market\n * @param borrower borrower to \"forgive\"\n * @param badDebtDelta amount of new bad debt recorded\n * @param badDebtOld previous bad debt value\n * @param badDebtNew new bad debt value\n */\n event BadDebtIncreased(address indexed borrower, uint256 badDebtDelta, uint256 badDebtOld, uint256 badDebtNew);\n\n /**\n * @notice Event emitted when bad debt is recovered via an auction\n * @param badDebtOld previous bad debt value\n * @param badDebtNew new bad debt value\n */\n event BadDebtRecovered(uint256 badDebtOld, uint256 badDebtNew);\n\n /**\n * @notice Event emitted when a borrow is liquidated\n */\n event LiquidateBorrow(\n address indexed liquidator,\n address indexed borrower,\n uint256 repayAmount,\n address indexed vTokenCollateral,\n uint256 seizeTokens\n );\n\n /*** Admin Events ***/\n\n /**\n * @notice Event emitted when comptroller is changed\n */\n event NewComptroller(ComptrollerInterface indexed oldComptroller, ComptrollerInterface indexed newComptroller);\n\n /**\n * @notice Event emitted when shortfall contract address is changed\n */\n event NewShortfallContract(address indexed oldShortfall, address indexed newShortfall);\n\n /**\n * @notice Event emitted when protocol share reserve contract address is changed\n */\n event NewProtocolShareReserve(address indexed oldProtocolShareReserve, address indexed newProtocolShareReserve);\n\n /**\n * @notice Event emitted when interestRateModel is changed\n */\n event NewMarketInterestRateModel(\n InterestRateModel indexed oldInterestRateModel,\n InterestRateModel indexed newInterestRateModel\n );\n\n /**\n * @notice Event emitted when protocol seize share is changed\n */\n event NewProtocolSeizeShare(uint256 oldProtocolSeizeShareMantissa, uint256 newProtocolSeizeShareMantissa);\n\n /**\n * @notice Event emitted when the reserve factor is changed\n */\n event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa);\n\n /**\n * @notice Event emitted when the reserves are added\n */\n event ReservesAdded(address indexed benefactor, uint256 addAmount, uint256 newTotalReserves);\n\n /**\n * @notice Event emitted when the reserves are reduced\n */\n event ReservesReduced(address indexed admin, uint256 reduceAmount, uint256 newTotalReserves);\n\n /**\n * @notice EIP20 Transfer event\n */\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n /**\n * @notice EIP20 Approval event\n */\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /**\n * @notice Event emitted when healing the borrow\n */\n event HealBorrow(address indexed payer, address indexed borrower, uint256 repayAmount);\n\n /**\n * @notice Event emitted when tokens are swept\n */\n event SweepToken(address indexed token);\n\n /*** User Interface ***/\n\n function mint(uint256 mintAmount) external virtual returns (uint256);\n\n function mintBehalf(address minter, uint256 mintAllowed) external virtual returns (uint256);\n\n function redeem(uint256 redeemTokens) external virtual returns (uint256);\n\n function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256);\n\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\n\n function repayBorrow(uint256 repayAmount) external virtual returns (uint256);\n\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256);\n\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral\n ) external virtual returns (uint256);\n\n function healBorrow(address payer, address borrower, uint256 repayAmount) external virtual;\n\n function forceLiquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipCloseFactorCheck\n ) external virtual;\n\n function seize(address liquidator, address borrower, uint256 seizeTokens) external virtual;\n\n function transfer(address dst, uint256 amount) external virtual returns (bool);\n\n function transferFrom(address src, address dst, uint256 amount) external virtual returns (bool);\n\n function accrueInterest() external virtual returns (uint256);\n\n function sweepToken(IERC20Upgradeable token) external virtual;\n\n /*** Admin Functions ***/\n\n function setReserveFactor(uint256 newReserveFactorMantissa) external virtual;\n\n function reduceReserves(uint256 reduceAmount) external virtual;\n\n function exchangeRateCurrent() external virtual returns (uint256);\n\n function borrowBalanceCurrent(address account) external virtual returns (uint256);\n\n function setInterestRateModel(InterestRateModel newInterestRateModel) external virtual;\n\n function addReserves(uint256 addAmount) external virtual;\n\n function totalBorrowsCurrent() external virtual returns (uint256);\n\n function balanceOfUnderlying(address owner) external virtual returns (uint256);\n\n function approve(address spender, uint256 amount) external virtual returns (bool);\n\n function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool);\n\n function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool);\n\n function allowance(address owner, address spender) external view virtual returns (uint256);\n\n function balanceOf(address owner) external view virtual returns (uint256);\n\n function getAccountSnapshot(address account) external view virtual returns (uint256, uint256, uint256, uint256);\n\n function borrowRatePerBlock() external view virtual returns (uint256);\n\n function supplyRatePerBlock() external view virtual returns (uint256);\n\n function borrowBalanceStored(address account) external view virtual returns (uint256);\n\n function exchangeRateStored() external view virtual returns (uint256);\n\n function getCash() external view virtual returns (uint256);\n\n /**\n * @notice Indicator that this is a VToken contract (for inspection)\n * @return Always true\n */\n function isVToken() external pure virtual returns (bool) {\n return true;\n }\n}\n" + }, + "contracts/WhitePaperInterestRateModel.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { EXP_SCALE, MANTISSA_ONE } from \"./lib/constants.sol\";\n\n/**\n * @title Compound's WhitePaperInterestRateModel Contract\n * @author Compound\n * @notice The parameterized model described in section 2.4 of the original Compound Protocol whitepaper\n */\ncontract WhitePaperInterestRateModel is InterestRateModel {\n /**\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\n */\n uint256 public immutable blocksPerYear;\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public immutable multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public immutable baseRatePerBlock;\n\n event NewInterestParams(uint256 baseRatePerBlock, uint256 multiplierPerBlock);\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n */\n constructor(\n uint256 blocksPerYear_,\n uint256 baseRatePerYear,\n uint256 multiplierPerYear\n ) {\n require(blocksPerYear_ != 0, \"Invalid blocks per year\");\n baseRatePerBlock = baseRatePerYear / blocksPerYear_;\n multiplierPerBlock = multiplierPerYear / blocksPerYear_;\n blocksPerYear = blocksPerYear_;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock);\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public view override returns (uint256) {\n uint256 ur = utilizationRate(cash, borrows, reserves, badDebt);\n return ((ur * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) public view override returns (uint256) {\n uint256 oneMinusReserveFactor = MANTISSA_ONE - reserveFactorMantissa;\n uint256 borrowRate = getBorrowRate(cash, borrows, reserves, badDebt);\n uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / EXP_SCALE;\n uint256 incomeToDistribute = borrows * rateToPool;\n uint256 supply = cash + borrows + badDebt - reserves;\n return incomeToDistribute / supply;\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `(borrows + badDebt) / (cash + borrows + badDebt - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @param badDebt The amount of badDebt in the market\n * @return The utilization rate as a mantissa between [0, MANTISSA_ONE]\n */\n function utilizationRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public pure returns (uint256) {\n // Utilization rate is 0 when there are no borrows and badDebt\n if ((borrows + badDebt) == 0) {\n return 0;\n }\n\n uint256 rate = ((borrows + badDebt) * EXP_SCALE) / (cash + borrows + badDebt - reserves);\n\n if (rate > EXP_SCALE) {\n rate = EXP_SCALE;\n }\n\n return rate;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200, + "details": { + "yul": true + } + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/bscmainnet/solcInputs/fe42e787f43c7b3c0c64f0274853de01.json b/deployments/bscmainnet/solcInputs/fe42e787f43c7b3c0c64f0274853de01.json new file mode 100644 index 000000000..35f1ab4d2 --- /dev/null +++ b/deployments/bscmainnet/solcInputs/fe42e787f43c7b3c0c64f0274853de01.json @@ -0,0 +1,288 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./OwnableUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides 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} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n function __Ownable2Step_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.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/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {\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 function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\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 /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized != type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n return _status == _ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n using AddressUpgradeable for address;\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to\n * 0 before setting it to a non-zero value.\n */\n function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n * Revert on invalid signature.\n */\n function safePermit(\n IERC20PermitUpgradeable token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return\n success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\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 ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\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 /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n /**\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n * address.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy.\n */\n function proxiableUUID() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC1967.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\n *\n * _Available since v4.8.3._\n */\ninterface IERC1967 {\n /**\n * @dev Emitted when the implementation is upgraded.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Emitted when the admin account has changed.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Emitted when the beacon is changed.\n */\n event BeaconUpgraded(address indexed beacon);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../Proxy.sol\";\nimport \"../ERC1967/ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.\n *\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\n * conflict with the storage layout of the implementation behind the proxy.\n *\n * _Available since v3.4._\n */\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\n /**\n * @dev Initializes the proxy with `beacon`.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\n * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity\n * constructor.\n *\n * Requirements:\n *\n * - `beacon` must be a contract with the interface {IBeacon}.\n */\n constructor(address beacon, bytes memory data) payable {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n\n /**\n * @dev Returns the current beacon address.\n */\n function _beacon() internal view virtual returns (address) {\n return _getBeacon();\n }\n\n /**\n * @dev Returns the current implementation address of the associated beacon.\n */\n function _implementation() internal view virtual override returns (address) {\n return IBeacon(_getBeacon()).implementation();\n }\n\n /**\n * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\n *\n * Requirements:\n *\n * - `beacon` must be a contract.\n * - The implementation returned by `beacon` must be a contract.\n */\n function _setBeacon(address beacon, bytes memory data) internal virtual {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n /**\n * @dev Must return an address that can be used as a delegate call target.\n *\n * {BeaconProxy} will check that this address is a contract.\n */\n function implementation() external view returns (address);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../../access/Ownable.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their\n * implementation contract, which is where they will delegate all function calls.\n *\n * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.\n */\ncontract UpgradeableBeacon is IBeacon, Ownable {\n address private _implementation;\n\n /**\n * @dev Emitted when the implementation returned by the beacon is changed.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the\n * beacon.\n */\n constructor(address implementation_) {\n _setImplementation(implementation_);\n }\n\n /**\n * @dev Returns the current implementation address.\n */\n function implementation() public view virtual override returns (address) {\n return _implementation;\n }\n\n /**\n * @dev Upgrades the beacon to a new implementation.\n *\n * Emits an {Upgraded} event.\n *\n * Requirements:\n *\n * - msg.sender must be the owner of the contract.\n * - `newImplementation` must be a contract.\n */\n function upgradeTo(address newImplementation) public virtual onlyOwner {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation contract address for this beacon\n *\n * Requirements:\n *\n * - `newImplementation` must be a contract.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"UpgradeableBeacon: implementation is not a contract\");\n _implementation = newImplementation;\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/IERC1967.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n */\nabstract contract ERC1967Upgrade is IERC1967 {\n // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation address.\n */\n function _getImplementation() internal view returns (address) {\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 implementation slot.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n }\n\n /**\n * @dev Perform implementation upgrade\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Perform implementation upgrade with additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {\n _upgradeTo(newImplementation);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(newImplementation, data);\n }\n }\n\n /**\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {\n // Upgrades from old implementations will perform a rollback test. This test requires the new\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n // this special case will break upgrade paths from old UUPS implementation to new ones.\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n _setImplementation(newImplementation);\n } else {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n } catch {\n revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n }\n _upgradeToAndCall(newImplementation, data, forceCall);\n }\n }\n\n /**\n * @dev Storage slot with the admin of the contract.\n * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /**\n * @dev Returns the current admin.\n */\n function _getAdmin() internal view returns (address) {\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 admin slot.\n */\n function _setAdmin(address newAdmin) private {\n require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n */\n function _changeAdmin(address newAdmin) internal {\n emit AdminChanged(_getAdmin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n */\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n /**\n * @dev Returns the current beacon.\n */\n function _getBeacon() internal view returns (address) {\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n }\n\n /**\n * @dev Stores a new beacon in the EIP1967 beacon slot.\n */\n function _setBeacon(address newBeacon) private {\n require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n require(\n Address.isContract(IBeacon(newBeacon).implementation()),\n \"ERC1967: beacon implementation is not a contract\"\n );\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n }\n\n /**\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n *\n * Emits a {BeaconUpgraded} event.\n */\n function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {\n _setBeacon(newBeacon);\n emit BeaconUpgraded(newBeacon);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n /**\n * @dev Delegates the current call to `implementation`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _delegate(address implementation) internal virtual {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n /**\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n * and {_fallback} should delegate.\n */\n function _implementation() internal view virtual returns (address);\n\n /**\n * @dev Delegates the current call to the address returned by `_implementation()`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _fallback() internal virtual {\n _beforeFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n * function in the contract matches the call data.\n */\n fallback() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n * is empty.\n */\n receive() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n * call, or as part of the Solidity `fallback` or `receive` functions.\n *\n * If overridden should call `super._beforeFallback()`.\n */\n function _beforeFallback() internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(address from, address to, uint256 amount) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n // decrementing then incrementing.\n _balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n unchecked {\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n _balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n // Overflow not possible: amount <= accountBalance <= totalSupply.\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(address owner, address spender, uint256 amount) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1, \"Math: mulDiv overflow\");\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/utils/StorageSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._\n * _Available since v4.9 for `string`, `bytes`._\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := store.slot\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toString(int256 value) internal pure returns (string memory) {\n return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return keccak256(bytes(a)) == keccak256(bytes(b));\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title Venus Access Control Contract.\n * @dev The AccessControlledV8 contract is a wrapper around the OpenZeppelin AccessControl contract\n * It provides a standardized way to control access to methods within the Venus Smart Contract Ecosystem.\n * The contract allows the owner to set an AccessControlManager contract address.\n * It can restrict method calls based on the sender's role and the method's signature.\n */\n\nabstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {\n /// @notice Access control manager contract\n IAccessControlManagerV8 private _accessControlManager;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when access control manager contract address is changed\n event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);\n\n /// @notice Thrown when the action is prohibited by AccessControlManager\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Sets the address of AccessControlManager\n * @dev Admin function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n * @custom:event Emits NewAccessControlManager event\n * @custom:access Only Governance\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Returns the address of the access control manager contract\n */\n function accessControlManager() external view returns (IAccessControlManagerV8) {\n return _accessControlManager;\n }\n\n /**\n * @dev Internal function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n */\n function _setAccessControlManager(address accessControlManager_) internal {\n require(address(accessControlManager_) != address(0), \"invalid acess control manager address\");\n address oldAccessControlManager = address(_accessControlManager);\n _accessControlManager = IAccessControlManagerV8(accessControlManager_);\n emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);\n }\n\n /**\n * @notice Reverts if the call is not allowed by AccessControlManager\n * @param signature Method signature\n */\n function _checkAccessAllowed(string memory signature) internal view {\n bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title Venus Access Control Contract\n * @author venus\n * @dev This contract is a wrapper of OpenZeppelin AccessControl\n *\t\textending it in a way to standartize access control\n *\t\twithin Venus Smart Contract Ecosystem\n */\ncontract AccessControlManager is AccessControl, IAccessControlManagerV8 {\n /// @notice Emitted when an account is given a permission to a certain contract function\n /// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and\n /// can call any contract function with this signature\n event PermissionGranted(address account, address contractAddress, string functionSig);\n\n /// @notice Emitted when an account is revoked a permission to a certain contract function\n event PermissionRevoked(address account, address contractAddress, string functionSig);\n\n constructor() {\n // Grant the contract deployer the default admin role: it will be able\n // to grant and revoke any roles\n _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n /**\n * @notice Gives a function call permission to one single account\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * @param contractAddress address of contract for which call permissions will be granted\n * @dev if contractAddress is zero address, the account can access the specified function\n * on **any** contract managed by this ACL\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @param accountToPermit account that will be given access to the contract function\n * @custom:event Emits a {RoleGranted} and {PermissionGranted} events.\n */\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n grantRole(role, accountToPermit);\n emit PermissionGranted(accountToPermit, contractAddress, functionSig);\n }\n\n /**\n * @notice Revokes an account's permission to a particular function call\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * \t\tMay emit a {RoleRevoked} event.\n * @param contractAddress address of contract for which call permissions will be revoked\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.\n */\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n revokeRole(role, accountToRevoke);\n emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender\n * @param account for which call permissions will be checked\n * @param functionSig restricted function signature e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n *\n */\n function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));\n\n if (hasRole(role, account)) {\n return true;\n } else {\n role = keccak256(abi.encodePacked(address(0), functionSig));\n return hasRole(role, account);\n }\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.\n * @param account for which call permissions will be checked against\n * @param contractAddress address of the restricted contract\n * @param functionSig signature of the restricted function e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n */\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n return hasRole(role, account);\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/FeedRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface FeedRegistryInterface {\n function latestRoundDataByName(\n string memory base,\n string memory quote\n )\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n function decimalsByName(string memory base, string memory quote) external view returns (uint8);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface OracleInterface {\n function getPrice(address asset) external view returns (uint256);\n}\n\ninterface ResilientOracleInterface is OracleInterface {\n function updatePrice(address vToken) external;\n\n function updateAssetPrice(address asset) external;\n\n function getUnderlyingPrice(address vToken) external view returns (uint256);\n}\n\ninterface TwapInterface is OracleInterface {\n function updateTwap(address asset) external returns (uint256);\n}\n\ninterface BoundValidatorInterface {\n function validatePriceWithAnchorPrice(\n address asset,\n uint256 reporterPrice,\n uint256 anchorPrice\n ) external view returns (bool);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/PublicResolverInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.13;\n\ninterface PublicResolverInterface {\n function addr(bytes32 node) external view returns (address payable);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/SIDRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.13;\n\ninterface SIDRegistryInterface {\n function resolver(bytes32 node) external view returns (address);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/VBep20Interface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\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" + }, + "@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/SIDRegistryInterface.sol\";\nimport \"../interfaces/FeedRegistryInterface.sol\";\nimport \"../interfaces/PublicResolverInterface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport \"../interfaces/OracleInterface.sol\";\n\n/**\n * @title BinanceOracle\n * @author Venus\n * @notice This oracle fetches price of assets from Binance.\n */\ncontract BinanceOracle is AccessControlledV8, OracleInterface {\n address public sidRegistryAddress;\n\n /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Max stale period configuration for assets\n mapping(string => uint256) public maxStalePeriod;\n\n /// @notice Override symbols to be compatible with Binance feed registry\n mapping(string => string) public symbols;\n\n event MaxStalePeriodAdded(string indexed asset, uint256 maxStalePeriod);\n\n event SymbolOverridden(string indexed symbol, string overriddenSymbol);\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 /// @notice Constructor for the implementation contract.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Used to set the max stale period of an asset\n * @param symbol The symbol of the asset\n * @param _maxStalePeriod The max stake period\n */\n function setMaxStalePeriod(string memory symbol, uint256 _maxStalePeriod) external {\n _checkAccessAllowed(\"setMaxStalePeriod(string,uint256)\");\n if (_maxStalePeriod == 0) revert(\"stale period can't be zero\");\n if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n maxStalePeriod[symbol] = _maxStalePeriod;\n emit MaxStalePeriodAdded(symbol, _maxStalePeriod);\n }\n\n /**\n * @notice Used to override a symbol when fetching price\n * @param symbol The symbol to override\n * @param overrideSymbol The symbol after override\n */\n function setSymbolOverride(string calldata symbol, string calldata overrideSymbol) external {\n _checkAccessAllowed(\"setSymbolOverride(string,string)\");\n if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n symbols[symbol] = overrideSymbol;\n emit SymbolOverridden(symbol, overrideSymbol);\n }\n\n /**\n * @notice Sets the contracts required to fetch prices\n * @param _sidRegistryAddress Address of SID registry\n * @param _accessControlManager Address of the access control manager contract\n */\n function initialize(\n address _sidRegistryAddress,\n address _accessControlManager\n ) external initializer notNullAddress(_sidRegistryAddress) {\n sidRegistryAddress = _sidRegistryAddress;\n __AccessControlled_init(_accessControlManager);\n }\n\n /**\n * @notice Uses Space ID to fetch the feed registry address\n * @return feedRegistryAddress Address of binance oracle feed registry.\n */\n function getFeedRegistryAddress() public view returns (address) {\n bytes32 nodeHash = 0x94fe3821e0768eb35012484db4df61890f9a6ca5bfa984ef8ff717e73139faff;\n\n SIDRegistryInterface sidRegistry = SIDRegistryInterface(sidRegistryAddress);\n address publicResolverAddress = sidRegistry.resolver(nodeHash);\n PublicResolverInterface publicResolver = PublicResolverInterface(publicResolverAddress);\n\n return publicResolver.addr(nodeHash);\n }\n\n /**\n * @notice Gets the price of a asset from the binance oracle\n * @param asset Address of the asset\n * @return Price in USD\n */\n function getPrice(address asset) public view returns (uint256) {\n string memory symbol;\n uint256 decimals;\n\n if (asset == BNB_ADDR) {\n symbol = \"BNB\";\n decimals = 18;\n } else {\n IERC20Metadata token = IERC20Metadata(asset);\n symbol = token.symbol();\n decimals = token.decimals();\n }\n\n string memory overrideSymbol = symbols[symbol];\n\n if (bytes(overrideSymbol).length != 0) {\n symbol = overrideSymbol;\n }\n\n return _getPrice(symbol, decimals);\n }\n\n function _getPrice(string memory symbol, uint256 decimals) internal view returns (uint256) {\n FeedRegistryInterface feedRegistry = FeedRegistryInterface(getFeedRegistryAddress());\n\n (, int256 answer, , uint256 updatedAt, ) = feedRegistry.latestRoundDataByName(symbol, \"USD\");\n if (answer <= 0) revert(\"invalid binance oracle price\");\n if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n uint256 deltaTime;\n unchecked {\n deltaTime = block.timestamp - updatedAt;\n }\n if (deltaTime > maxStalePeriod[symbol]) revert(\"binance oracle price expired\");\n\n uint256 decimalDelta = feedRegistry.decimalsByName(symbol, \"USD\");\n return (uint256(answer) * (10 ** (18 - decimalDelta))) * (10 ** (18 - decimals));\n }\n}\n" + }, + "@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\n/**\n * @title ChainlinkOracle\n * @author Venus\n * @notice This oracle fetches prices of assets from the Chainlink oracle.\n */\ncontract ChainlinkOracle is AccessControlledV8, OracleInterface {\n struct TokenConfig {\n /// @notice Underlying token address, which can't be a null address\n /// @notice Used to check if a token is supported\n /// @notice 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB for BNB\n address asset;\n /// @notice Chainlink feed address\n address feed;\n /// @notice Price expiration period of this asset\n uint256 maxStalePeriod;\n }\n\n /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Manually set an override price, useful under extenuating conditions such as price feed failure\n mapping(address => uint256) public prices;\n\n /// @notice Token config by assets\n mapping(address => TokenConfig) public tokenConfigs;\n\n /// @notice Emit when a price is manually set\n event PricePosted(address indexed asset, uint256 previousPriceMantissa, uint256 newPriceMantissa);\n\n /// @notice Emit when a token config is added\n event TokenConfigAdded(address indexed asset, address feed, uint256 maxStalePeriod);\n\n modifier notNullAddress(address someone) {\n if (someone == address(0)) revert(\"can't be zero address\");\n _;\n }\n\n /// @notice Constructor for the implementation contract.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Manually set the price of a given asset\n * @param asset Asset address\n * @param price Asset price in 18 decimals\n * @custom:access Only Governance\n * @custom:event Emits PricePosted event on succesfully setup of asset price\n */\n function setDirectPrice(address asset, uint256 price) external notNullAddress(asset) {\n _checkAccessAllowed(\"setDirectPrice(address,uint256)\");\n\n uint256 previousPriceMantissa = prices[asset];\n prices[asset] = price;\n emit PricePosted(asset, previousPriceMantissa, price);\n }\n\n /**\n * @notice Add multiple token configs at the same time\n * @param tokenConfigs_ config array\n * @custom:access Only Governance\n * @custom:error Zero length error thrown, if length of the array in parameter 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 Initializes the owner of the contract\n * @param accessControlManager_ Address of the access control manager contract\n */\n function initialize(address accessControlManager_) external initializer {\n __AccessControlled_init(accessControlManager_);\n }\n\n /**\n * @notice Add single token config. asset & feed cannot be null addresses and maxStalePeriod must be positive\n * @param tokenConfig Token config struct\n * @custom:access Only Governance\n * @custom:error NotNullAddress error is thrown if asset address is null\n * @custom:error NotNullAddress error is thrown if token feed address is null\n * @custom:error Range error is thrown if maxStale period of token is not greater than zero\n * @custom:event Emits TokenConfigAdded event on succesfully setting of the token config\n */\n function setTokenConfig(\n TokenConfig memory tokenConfig\n ) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.feed) {\n _checkAccessAllowed(\"setTokenConfig(TokenConfig)\");\n\n if (tokenConfig.maxStalePeriod == 0) revert(\"stale period can't be zero\");\n tokenConfigs[tokenConfig.asset] = tokenConfig;\n emit TokenConfigAdded(tokenConfig.asset, tokenConfig.feed, tokenConfig.maxStalePeriod);\n }\n\n /**\n * @notice Gets the price of a asset from the chainlink oracle\n * @param asset Address of the asset\n * @return Price in USD from Chainlink or a manually set price for the asset\n */\n function getPrice(address asset) public view returns (uint256) {\n uint256 decimals;\n\n if (asset == BNB_ADDR) {\n decimals = 18;\n } else {\n IERC20Metadata token = IERC20Metadata(asset);\n decimals = token.decimals();\n }\n\n return _getPriceInternal(asset, decimals);\n }\n\n /**\n * @notice Gets the Chainlink price for a given asset\n * @param asset address of the asset\n * @param decimals decimals of the asset\n * @return price Asset price in USD or a manually set price of the asset\n */\n function _getPriceInternal(address asset, uint256 decimals) internal view returns (uint256 price) {\n uint256 tokenPrice = prices[asset];\n if (tokenPrice != 0) {\n price = tokenPrice;\n } else {\n price = _getChainlinkPrice(asset);\n }\n\n uint256 decimalDelta = 18 - decimals;\n return price * (10 ** decimalDelta);\n }\n\n /**\n * @notice Get the Chainlink price for an asset, revert if token config doesn't exist\n * @dev The precision of the price feed is used to ensure the returned price has 18 decimals of precision\n * @param asset Address of the asset\n * @return price Price in USD, with 18 decimals of precision\n * @custom:error NotNullAddress error is thrown if the asset address is null\n * @custom:error Price error is thrown if the Chainlink price of asset is not greater than zero\n * @custom:error Timing error is thrown if current timestamp is less than the last updatedAt timestamp\n * @custom:error Timing error is thrown if time difference between current time and last updated time\n * is greater than maxStalePeriod\n */\n function _getChainlinkPrice(\n address asset\n ) private view notNullAddress(tokenConfigs[asset].asset) returns (uint256) {\n TokenConfig memory tokenConfig = tokenConfigs[asset];\n AggregatorV3Interface feed = AggregatorV3Interface(tokenConfig.feed);\n\n // note: maxStalePeriod cannot be 0\n uint256 maxStalePeriod = tokenConfig.maxStalePeriod;\n\n // Chainlink USD-denominated feeds store answers at 8 decimals, mostly\n uint256 decimalDelta = 18 - feed.decimals();\n\n (, int256 answer, , uint256 updatedAt, ) = feed.latestRoundData();\n if (answer <= 0) revert(\"chainlink price must be positive\");\n if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n uint256 deltaTime;\n unchecked {\n deltaTime = block.timestamp - updatedAt;\n }\n\n if (deltaTime > maxStalePeriod) revert(\"chainlink price expired\");\n\n return uint256(answer) * (10 ** decimalDelta);\n }\n}\n" + }, + "contracts/BaseJumpRateModelV2.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\n\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { BLOCKS_PER_YEAR, EXP_SCALE, MANTISSA_ONE } from \"./lib/constants.sol\";\n\n/**\n * @title Logic for Compound's JumpRateModel Contract V2.\n * @author Compound (modified by Dharma Labs, Arr00 and Venus)\n * @notice An interest rate model with a steep increase after a certain utilization threshold called **kink** is reached.\n * The parameters of this interest rate model can be adjusted by the owner. Version 2 modifies Version 1 by enabling updateable parameters.\n */\nabstract contract BaseJumpRateModelV2 is InterestRateModel {\n /**\n * @notice The address of the AccessControlManager contract\n */\n IAccessControlManagerV8 public accessControlManager;\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public baseRatePerBlock;\n\n /**\n * @notice The multiplier per block after hitting a specified utilization point\n */\n uint256 public jumpMultiplierPerBlock;\n\n /**\n * @notice The utilization point at which the jump multiplier is applied\n */\n uint256 public kink;\n\n event NewInterestParams(\n uint256 baseRatePerBlock,\n uint256 multiplierPerBlock,\n uint256 jumpMultiplierPerBlock,\n uint256 kink\n );\n\n /**\n * @notice Thrown when the action is prohibited by AccessControlManager\n */\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @param accessControlManager_ The address of the AccessControlManager contract\n */\n constructor(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n IAccessControlManagerV8 accessControlManager_\n ) {\n require(address(accessControlManager_) != address(0), \"invalid ACM address\");\n\n accessControlManager = accessControlManager_;\n\n _updateJumpRateModel(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @custom:error Unauthorized if the sender is not allowed to call this function\n * @custom:access Controlled by AccessControlManager\n */\n function updateJumpRateModel(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) external virtual {\n string memory signature = \"updateJumpRateModel(uint256,uint256,uint256,uint256)\";\n bool isAllowedToCall = accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n\n _updateJumpRateModel(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) public view virtual override returns (uint256) {\n uint256 oneMinusReserveFactor = MANTISSA_ONE - reserveFactorMantissa;\n uint256 borrowRate = _getBorrowRate(cash, borrows, reserves, badDebt);\n uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / EXP_SCALE;\n uint256 incomeToDistribute = borrows * rateToPool;\n uint256 supply = cash + borrows + badDebt - reserves;\n return incomeToDistribute / supply;\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `(borrows + badDebt) / (cash + borrows + badDebt - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @param badDebt The amount of badDebt in the market\n * @return The utilization rate as a mantissa between [0, MANTISSA_ONE]\n */\n function utilizationRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public pure returns (uint256) {\n // Utilization rate is 0 when there are no borrows and badDebt\n if ((borrows + badDebt) == 0) {\n return 0;\n }\n\n uint256 rate = ((borrows + badDebt) * EXP_SCALE) / (cash + borrows + badDebt - reserves);\n\n if (rate > EXP_SCALE) {\n rate = EXP_SCALE;\n }\n\n return rate;\n }\n\n /**\n * @notice Internal function to update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n */\n function _updateJumpRateModel(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) internal {\n baseRatePerBlock = baseRatePerYear / BLOCKS_PER_YEAR;\n multiplierPerBlock = multiplierPerYear / BLOCKS_PER_YEAR;\n jumpMultiplierPerBlock = jumpMultiplierPerYear / BLOCKS_PER_YEAR;\n kink = kink_;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function _getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) internal view returns (uint256) {\n uint256 util = utilizationRate(cash, borrows, reserves, badDebt);\n uint256 kink_ = kink;\n\n if (util <= kink_) {\n return ((util * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n }\n uint256 normalRate = ((kink_ * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n uint256 excessUtil;\n unchecked {\n excessUtil = util - kink_;\n }\n return ((excessUtil * jumpMultiplierPerBlock) / EXP_SCALE) + normalRate;\n }\n}\n" + }, + "contracts/Comptroller.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { ComptrollerStorage } from \"./ComptrollerStorage.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\nimport { MaxLoopsLimitHelper } from \"./MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title Comptroller\n * @author Venus\n * @notice The Comptroller is designed to provide checks for all minting, redeeming, transferring, borrowing, lending, repaying, liquidating,\n * and seizing done by the `vToken` contract. Each pool has one `Comptroller` checking these interactions across markets. When a user interacts\n * with a given market by one of these main actions, a call is made to a corresponding hook in the associated `Comptroller`, which either allows\n * or reverts the transaction. These hooks also update supply and borrow rewards as they are called. The comptroller holds the logic for assessing\n * liquidity snapshots of an account via the collateral factor and liquidation threshold. This check determines the collateral needed for a borrow,\n * as well as how much of a borrow may be liquidated. A user may borrow a portion of their collateral with the maximum amount determined by the\n * markets collateral factor. However, if their borrowed amount exceeds an amount calculated using the market’s corresponding liquidation threshold,\n * the borrow is eligible for liquidation.\n *\n * The `Comptroller` also includes two functions `liquidateAccount()` and `healAccount()`, which are meant to handle accounts that do not exceed\n * the `minLiquidatableCollateral` for the `Comptroller`:\n *\n * - `healAccount()`: This function is called to seize all of a given user’s collateral, requiring the `msg.sender` repay a certain percentage\n * of the debt calculated by `collateral/(borrows*liquidationIncentive)`. The function can only be called if the calculated percentage does not exceed\n * 100%, because otherwise no `badDebt` would be created and `liquidateAccount()` should be used instead. The difference in the actual amount of debt\n * and debt paid off is recorded as `badDebt` for each market, which can then be auctioned off for the risk reserves of the associated pool.\n * - `liquidateAccount()`: This function can only be called if the collateral seized will cover all borrows of an account, as well as the liquidation\n * incentive. Otherwise, the pool will incur bad debt, in which case the function `healAccount()` should be used instead. This function skips the logic\n * verifying that the repay amount does not exceed the close factor.\n */\ncontract Comptroller is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n ComptrollerStorage,\n ComptrollerInterface,\n ExponentialNoError,\n MaxLoopsLimitHelper\n{\n // PoolRegistry, immutable to save on gas\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable poolRegistry;\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(VToken indexed vToken, address indexed account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(VToken indexed vToken, address indexed account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint256 oldCloseFactorMantissa, uint256 newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(VToken vToken, uint256 oldCollateralFactorMantissa, uint256 newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation threshold is changed by admin\n event NewLiquidationThreshold(\n VToken vToken,\n uint256 oldLiquidationThresholdMantissa,\n uint256 newLiquidationThresholdMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint256 oldLiquidationIncentiveMantissa, uint256 newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(ResilientOracleInterface oldPriceOracle, ResilientOracleInterface newPriceOracle);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPausedMarket(VToken vToken, Action action, bool pauseState);\n\n /// @notice Emitted when borrow cap for a vToken is changed\n event NewBorrowCap(VToken indexed vToken, uint256 newBorrowCap);\n\n /// @notice Emitted when the collateral threshold (in USD) for non-batch liquidations is changed\n event NewMinLiquidatableCollateral(uint256 oldMinLiquidatableCollateral, uint256 newMinLiquidatableCollateral);\n\n /// @notice Emitted when supply cap for a vToken is changed\n event NewSupplyCap(VToken indexed vToken, uint256 newSupplyCap);\n\n /// @notice Emitted when a rewards distributor is added\n event NewRewardsDistributor(address indexed rewardsDistributor);\n\n /// @notice Emitted when a market is supported\n event MarketSupported(VToken vToken);\n\n /// @notice Thrown when collateral factor exceeds the upper bound\n error InvalidCollateralFactor();\n\n /// @notice Thrown when liquidation threshold exceeds the collateral factor\n error InvalidLiquidationThreshold();\n\n /// @notice Thrown when the action is only available to specific sender, but the real sender was different\n error UnexpectedSender(address expectedSender, address actualSender);\n\n /// @notice Thrown when the oracle returns an invalid price for some asset\n error PriceError(address vToken);\n\n /// @notice Thrown if VToken unexpectedly returned a nonzero error code while trying to get account snapshot\n error SnapshotError(address vToken, address user);\n\n /// @notice Thrown when the market is not listed\n error MarketNotListed(address market);\n\n /// @notice Thrown when a market has an unexpected comptroller\n error ComptrollerMismatch();\n\n /// @notice Thrown when user is not member of market\n error MarketNotCollateral(address vToken, address user);\n\n /**\n * @notice Thrown during the liquidation if user's total collateral amount is lower than\n * a predefined threshold. In this case only batch liquidations (either liquidateAccount\n * or healAccount) are available.\n */\n error MinimalCollateralViolated(uint256 expectedGreaterThan, uint256 actual);\n error CollateralExceedsThreshold(uint256 expectedLessThanOrEqualTo, uint256 actual);\n error InsufficientCollateral(uint256 collateralToSeize, uint256 availableCollateral);\n\n /// @notice Thrown when the account doesn't have enough liquidity to redeem or borrow\n error InsufficientLiquidity();\n\n /// @notice Thrown when trying to liquidate a healthy account\n error InsufficientShortfall();\n\n /// @notice Thrown when trying to repay more than allowed by close factor\n error TooMuchRepay();\n\n /// @notice Thrown if the user is trying to exit a market in which they have an outstanding debt\n error NonzeroBorrowBalance();\n\n /// @notice Thrown when trying to perform an action that is paused\n error ActionPaused(address market, Action action);\n\n /// @notice Thrown when trying to add a market that is already listed\n error MarketAlreadyListed(address market);\n\n /// @notice Thrown if the supply cap is exceeded\n error SupplyCapExceeded(address market, uint256 cap);\n\n /// @notice Thrown if the borrow cap is exceeded\n error BorrowCapExceeded(address market, uint256 cap);\n\n /// @param poolRegistry_ Pool registry address\n /// @custom:oz-upgrades-unsafe-allow constructor\n /// @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n constructor(address poolRegistry_) {\n ensureNonzeroAddress(poolRegistry_);\n\n poolRegistry = poolRegistry_;\n _disableInitializers();\n }\n\n /**\n * @param loopLimit Limit for the loops can iterate to avoid the DOS\n * @param accessControlManager Access control manager contract address\n */\n function initialize(uint256 loopLimit, address accessControlManager) external initializer {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager);\n\n _setMaxLoopsLimit(loopLimit);\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation; enabling them to be used as collateral\n * @param vTokens The list of addresses of the vToken markets to be enabled\n * @return errors An array of NO_ERROR for compatibility with Venus core tooling\n * @custom:event MarketEntered is emitted for each market on success\n * @custom:error ActionPaused error is thrown if entering any of the markets is paused\n * @custom:error MarketNotListed error is thrown if any of the markets is not listed\n * @custom:access Not restricted\n */\n function enterMarkets(address[] memory vTokens) external override returns (uint256[] memory) {\n uint256 len = vTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i; i < len; ++i) {\n VToken vToken = VToken(vTokens[i]);\n\n _addToMarket(vToken, msg.sender);\n results[i] = NO_ERROR;\n }\n\n return results;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation; disabling them as collateral\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing necessary collateral for an outstanding borrow.\n * @param vTokenAddress The address of the asset to be removed\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event MarketExited is emitted on success\n * @custom:error ActionPaused error is thrown if exiting the market is paused\n * @custom:error NonzeroBorrowBalance error is thrown if the user has an outstanding borrow in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if exiting the market would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function exitMarket(address vTokenAddress) external override returns (uint256) {\n _checkActionPauseState(vTokenAddress, Action.EXIT_MARKET);\n VToken vToken = VToken(vTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the vToken */\n (uint256 tokensHeld, uint256 amountOwed, ) = _safeGetAccountSnapshot(vToken, msg.sender);\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n revert NonzeroBorrowBalance();\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n _checkRedeemAllowed(vTokenAddress, msg.sender, tokensHeld);\n\n Market storage marketToExit = markets[address(vToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return NO_ERROR;\n }\n\n /* Set vToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete vToken from the account’s list of assets */\n // load into memory for faster iteration\n VToken[] memory userAssetList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n\n uint256 assetIndex = len;\n for (uint256 i; i < len; ++i) {\n if (userAssetList[i] == vToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n VToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.pop();\n\n emit MarketExited(vToken, msg.sender);\n\n return NO_ERROR;\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param vToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @custom:error ActionPaused error is thrown if supplying to this market is paused\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error SupplyCapExceeded error is thrown if the total supply exceeds the cap after minting\n * @custom:access Not restricted\n */\n function preMintHook(\n address vToken,\n address minter,\n uint256 mintAmount\n ) external override {\n _checkActionPauseState(vToken, Action.MINT);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n uint256 supplyCap = supplyCaps[vToken];\n // Skipping the cap check for uncapped coins to save some gas\n if (supplyCap != type(uint256).max) {\n uint256 vTokenSupply = VToken(vToken).totalSupply();\n Exp memory exchangeRate = Exp({ mantissa: VToken(vToken).exchangeRateStored() });\n uint256 nextTotalSupply = mul_ScalarTruncateAddUInt(exchangeRate, vTokenSupply, mintAmount);\n if (nextTotalSupply > supplyCap) {\n revert SupplyCapExceeded(vToken, supplyCap);\n }\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, minter);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param vToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of vTokens to exchange for the underlying asset in the market\n * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function preRedeemHook(\n address vToken,\n address redeemer,\n uint256 redeemTokens\n ) external override {\n _checkActionPauseState(vToken, Action.REDEEM);\n\n _checkRedeemAllowed(vToken, redeemer, redeemTokens);\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, redeemer);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param vToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @custom:error ActionPaused error is thrown if borrowing is paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if there is not enough collateral to borrow\n * @custom:error BorrowCapExceeded is thrown if the borrow cap will be exceeded should this borrow succeed\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted if vToken is enabled as collateral, otherwise only vToken\n */\n /// disable-eslint\n function preBorrowHook(\n address vToken,\n address borrower,\n uint256 borrowAmount\n ) external override {\n _checkActionPauseState(vToken, Action.BORROW);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n if (!markets[vToken].accountMembership[borrower]) {\n // only vTokens may call borrowAllowed if borrower not in market\n _checkSenderIs(vToken);\n\n // attempt to add borrower to the market or revert\n _addToMarket(VToken(msg.sender), borrower);\n }\n\n // Update the prices of tokens\n updatePrices(borrower);\n\n if (oracle.getUnderlyingPrice(vToken) == 0) {\n revert PriceError(address(vToken));\n }\n\n uint256 borrowCap = borrowCaps[vToken];\n // Skipping the cap check for uncapped coins to save some gas\n if (borrowCap != type(uint256).max) {\n uint256 totalBorrows = VToken(vToken).totalBorrows();\n uint256 badDebt = VToken(vToken).badDebt();\n uint256 nextTotalBorrows = totalBorrows + borrowAmount + badDebt;\n if (nextTotalBorrows > borrowCap) {\n revert BorrowCapExceeded(vToken, borrowCap);\n }\n }\n\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n borrower,\n VToken(vToken),\n 0,\n borrowAmount,\n _getCollateralFactor\n );\n\n if (snapshot.shortfall > 0) {\n revert InsufficientLiquidity();\n }\n\n Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param vToken The market to verify the repay against\n * @param borrower The account which would borrowed the asset\n * @custom:error ActionPaused error is thrown if repayments are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:access Not restricted\n */\n function preRepayHook(address vToken, address borrower) external override {\n _checkActionPauseState(vToken, Action.REPAY);\n\n oracle.updatePrice(vToken);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param vTokenBorrowed Asset which was borrowed by the borrower\n * @param vTokenCollateral Asset which was used as collateral and will be seized\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n * @param skipLiquidityCheck Allows the borrow to be liquidated regardless of the account liquidity\n * @custom:error ActionPaused error is thrown if liquidations are paused in this market\n * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n * @custom:error TooMuchRepay error is thrown if the liquidator is trying to repay more than allowed by close factor\n * @custom:error MinimalCollateralViolated is thrown if the users' total collateral is lower than the threshold for non-batch liquidations\n * @custom:error InsufficientShortfall is thrown when trying to liquidate a healthy account\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n */\n function preLiquidateHook(\n address vTokenBorrowed,\n address vTokenCollateral,\n address borrower,\n uint256 repayAmount,\n bool skipLiquidityCheck\n ) external override {\n // Pause Action.LIQUIDATE on BORROWED TOKEN to prevent liquidating it.\n // If we want to pause liquidating to vTokenCollateral, we should pause\n // Action.SEIZE on it\n _checkActionPauseState(vTokenBorrowed, Action.LIQUIDATE);\n\n // Update the prices of tokens\n updatePrices(borrower);\n\n if (!markets[vTokenBorrowed].isListed) {\n revert MarketNotListed(address(vTokenBorrowed));\n }\n if (!markets[vTokenCollateral].isListed) {\n revert MarketNotListed(address(vTokenCollateral));\n }\n\n uint256 borrowBalance = VToken(vTokenBorrowed).borrowBalanceStored(borrower);\n\n /* Allow accounts to be liquidated if the market is deprecated or it is a forced liquidation */\n if (skipLiquidityCheck || isDeprecated(VToken(vTokenBorrowed))) {\n if (repayAmount > borrowBalance) {\n revert TooMuchRepay();\n }\n return;\n }\n\n /* The borrower must have shortfall and collateral > threshold in order to be liquidatable */\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral <= minLiquidatableCollateral) {\n /* The liquidator should use either liquidateAccount or healAccount */\n revert MinimalCollateralViolated(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 maxClose = mul_ScalarTruncate(Exp({ mantissa: closeFactorMantissa }), borrowBalance);\n if (repayAmount > maxClose) {\n revert TooMuchRepay();\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param vTokenCollateral Asset which was used as collateral and will be seized\n * @param seizerContract Contract that tries to seize the asset (either borrowed vToken or Comptroller)\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @custom:error ActionPaused error is thrown if seizing this type of collateral is paused\n * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n * @custom:error ComptrollerMismatch error is when seizer contract or seized asset belong to different pools\n * @custom:access Not restricted\n */\n function preSeizeHook(\n address vTokenCollateral,\n address seizerContract,\n address liquidator,\n address borrower\n ) external override {\n // Pause Action.SEIZE on COLLATERAL to prevent seizing it.\n // If we want to pause liquidating vTokenBorrowed, we should pause\n // Action.LIQUIDATE on it\n _checkActionPauseState(vTokenCollateral, Action.SEIZE);\n\n Market storage market = markets[vTokenCollateral];\n\n if (!market.isListed) {\n revert MarketNotListed(vTokenCollateral);\n }\n\n if (seizerContract == address(this)) {\n // If Comptroller is the seizer, just check if collateral's comptroller\n // is equal to the current address\n if (address(VToken(vTokenCollateral).comptroller()) != address(this)) {\n revert ComptrollerMismatch();\n }\n } else {\n // If the seizer is not the Comptroller, check that the seizer is a\n // listed market, and that the markets' comptrollers match\n if (!markets[seizerContract].isListed) {\n revert MarketNotListed(seizerContract);\n }\n if (VToken(vTokenCollateral).comptroller() != VToken(seizerContract).comptroller()) {\n revert ComptrollerMismatch();\n }\n }\n\n if (!market.accountMembership[borrower]) {\n revert MarketNotCollateral(vTokenCollateral, borrower);\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vTokenCollateral);\n rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, borrower);\n rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, liquidator);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param vToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of vTokens to transfer\n * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function preTransferHook(\n address vToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override {\n _checkActionPauseState(vToken, Action.TRANSFER);\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n _checkRedeemAllowed(vToken, src, transferTokens);\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, src);\n rewardsDistributor.distributeSupplierRewardToken(vToken, dst);\n }\n }\n\n /*** Pool-level operations ***/\n\n /**\n * @notice Seizes all the remaining collateral, makes msg.sender repay the existing\n * borrows, and treats the rest of the debt as bad debt (for each market).\n * The sender has to repay a certain percentage of the debt, computed as\n * collateral / (borrows * liquidationIncentive).\n * @param user account to heal\n * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for healing\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function healAccount(address user) external {\n VToken[] memory userAssets = accountAssets[user];\n uint256 userAssetsCount = userAssets.length;\n\n address liquidator = msg.sender;\n {\n ResilientOracleInterface oracle_ = oracle;\n // We need all user's markets to be fresh for the computations to be correct\n for (uint256 i; i < userAssetsCount; ++i) {\n userAssets[i].accrueInterest();\n oracle_.updatePrice(address(userAssets[i]));\n }\n }\n\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(user, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral > minLiquidatableCollateral) {\n revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n // percentage = collateral / (borrows * liquidation incentive)\n Exp memory collateral = Exp({ mantissa: snapshot.totalCollateral });\n Exp memory scaledBorrows = mul_(\n Exp({ mantissa: snapshot.borrows }),\n Exp({ mantissa: liquidationIncentiveMantissa })\n );\n\n Exp memory percentage = div_(collateral, scaledBorrows);\n if (lessThanExp(Exp({ mantissa: MANTISSA_ONE }), percentage)) {\n revert CollateralExceedsThreshold(scaledBorrows.mantissa, collateral.mantissa);\n }\n\n for (uint256 i; i < userAssetsCount; ++i) {\n VToken market = userAssets[i];\n\n (uint256 tokens, uint256 borrowBalance, ) = _safeGetAccountSnapshot(market, user);\n uint256 repaymentAmount = mul_ScalarTruncate(percentage, borrowBalance);\n\n // Seize the entire collateral\n if (tokens != 0) {\n market.seize(liquidator, user, tokens);\n }\n // Repay a certain percentage of the borrow, forgive the rest\n if (borrowBalance != 0) {\n market.healBorrow(liquidator, user, repaymentAmount);\n }\n }\n }\n\n /**\n * @notice Liquidates all borrows of the borrower. Callable only if the collateral is less than\n * a predefined threshold, and the account collateral can be seized to cover all borrows. If\n * the collateral is higher than the threshold, use regular liquidations. If the collateral is\n * below the threshold, and the account is insolvent, use healAccount.\n * @param borrower the borrower address\n * @param orders an array of liquidation orders\n * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for a batch liquidation\n * @custom:error InsufficientCollateral error is thrown when there is not enough collateral to cover the debt\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function liquidateAccount(address borrower, LiquidationOrder[] calldata orders) external {\n // We will accrue interest and update the oracle prices later during the liquidation\n\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral > minLiquidatableCollateral) {\n // You should use the regular vToken.liquidateBorrow(...) call\n revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n uint256 collateralToSeize = mul_ScalarTruncate(\n Exp({ mantissa: liquidationIncentiveMantissa }),\n snapshot.borrows\n );\n if (collateralToSeize >= snapshot.totalCollateral) {\n // There is not enough collateral to seize. Use healBorrow to repay some part of the borrow\n // and record bad debt.\n revert InsufficientCollateral(collateralToSeize, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n uint256 ordersCount = orders.length;\n\n _ensureMaxLoops(ordersCount / 2);\n\n for (uint256 i; i < ordersCount; ++i) {\n if (!markets[address(orders[i].vTokenBorrowed)].isListed) {\n revert MarketNotListed(address(orders[i].vTokenBorrowed));\n }\n if (!markets[address(orders[i].vTokenCollateral)].isListed) {\n revert MarketNotListed(address(orders[i].vTokenCollateral));\n }\n\n LiquidationOrder calldata order = orders[i];\n order.vTokenBorrowed.forceLiquidateBorrow(\n msg.sender,\n borrower,\n order.repayAmount,\n order.vTokenCollateral,\n true\n );\n }\n\n VToken[] memory borrowMarkets = accountAssets[borrower];\n uint256 marketsCount = borrowMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n (, uint256 borrowBalance, ) = _safeGetAccountSnapshot(borrowMarkets[i], borrower);\n require(borrowBalance == 0, \"Nonzero borrow balance after liquidation\");\n }\n }\n\n /**\n * @notice Sets the closeFactor to use when liquidating borrows\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @custom:event Emits NewCloseFactor on success\n * @custom:access Controlled by AccessControlManager\n */\n function setCloseFactor(uint256 newCloseFactorMantissa) external {\n _checkAccessAllowed(\"setCloseFactor(uint256)\");\n require(MAX_CLOSE_FACTOR_MANTISSA >= newCloseFactorMantissa, \"Close factor greater than maximum close factor\");\n require(MIN_CLOSE_FACTOR_MANTISSA <= newCloseFactorMantissa, \"Close factor smaller than minimum close factor\");\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, newCloseFactorMantissa);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev This function is restricted by the AccessControlManager\n * @param vToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @param newLiquidationThresholdMantissa The new liquidation threshold, scaled by 1e18\n * @custom:event Emits NewCollateralFactor when collateral factor is updated\n * and NewLiquidationThreshold when liquidation threshold is updated\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InvalidCollateralFactor error is thrown when collateral factor is too high\n * @custom:error InvalidLiquidationThreshold error is thrown when liquidation threshold is lower than collateral factor\n * @custom:error PriceError is thrown when the oracle returns an invalid price for the asset\n * @custom:access Controlled by AccessControlManager\n */\n function setCollateralFactor(\n VToken vToken,\n uint256 newCollateralFactorMantissa,\n uint256 newLiquidationThresholdMantissa\n ) external {\n _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n\n // Verify market is listed\n Market storage market = markets[address(vToken)];\n if (!market.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n // Check collateral factor <= 0.9\n if (newCollateralFactorMantissa > MAX_COLLATERAL_FACTOR_MANTISSA) {\n revert InvalidCollateralFactor();\n }\n\n // Ensure that liquidation threshold <= 1\n if (newLiquidationThresholdMantissa > MANTISSA_ONE) {\n revert InvalidLiquidationThreshold();\n }\n\n // Ensure that liquidation threshold >= CF\n if (newLiquidationThresholdMantissa < newCollateralFactorMantissa) {\n revert InvalidLiquidationThreshold();\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(address(vToken)) == 0) {\n revert PriceError(address(vToken));\n }\n\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n if (newCollateralFactorMantissa != oldCollateralFactorMantissa) {\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n emit NewCollateralFactor(vToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n }\n\n uint256 oldLiquidationThresholdMantissa = market.liquidationThresholdMantissa;\n if (newLiquidationThresholdMantissa != oldLiquidationThresholdMantissa) {\n market.liquidationThresholdMantissa = newLiquidationThresholdMantissa;\n emit NewLiquidationThreshold(vToken, oldLiquidationThresholdMantissa, newLiquidationThresholdMantissa);\n }\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev This function is restricted by the AccessControlManager\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @custom:event Emits NewLiquidationIncentive on success\n * @custom:access Controlled by AccessControlManager\n */\n function setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) external {\n require(newLiquidationIncentiveMantissa >= MANTISSA_ONE, \"liquidation incentive should be greater than 1e18\");\n\n _checkAccessAllowed(\"setLiquidationIncentive(uint256)\");\n\n // Save current value for use in log\n uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Only callable by the PoolRegistry\n * @param vToken The address of the market (token) to list\n * @custom:error MarketAlreadyListed is thrown if the market is already listed in this pool\n * @custom:access Only PoolRegistry\n */\n function supportMarket(VToken vToken) external {\n _checkSenderIs(poolRegistry);\n\n if (markets[address(vToken)].isListed) {\n revert MarketAlreadyListed(address(vToken));\n }\n\n require(vToken.isVToken(), \"Comptroller: Invalid vToken\"); // Sanity check to make sure its really a VToken\n\n Market storage newMarket = markets[address(vToken)];\n newMarket.isListed = true;\n newMarket.collateralFactorMantissa = 0;\n newMarket.liquidationThresholdMantissa = 0;\n\n _addMarket(address(vToken));\n\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n rewardsDistributors[i].initializeMarket(address(vToken));\n }\n\n emit MarketSupported(vToken);\n }\n\n /**\n * @notice Set the given borrow caps for the given vToken markets. Borrowing that brings total borrows to or above borrow cap will revert.\n * @dev This function is restricted by the AccessControlManager\n * @dev A borrow cap of type(uint256).max corresponds to unlimited borrowing.\n * @dev Borrow caps smaller than the current total borrows are accepted. This way, new borrows will not be allowed\n until the total borrows amount goes below the new borrow cap\n * @param vTokens The addresses of the markets (tokens) to change the borrow caps for\n * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited borrowing.\n * @custom:access Controlled by AccessControlManager\n */\n function setMarketBorrowCaps(VToken[] calldata vTokens, uint256[] calldata newBorrowCaps) external {\n _checkAccessAllowed(\"setMarketBorrowCaps(address[],uint256[])\");\n\n uint256 numMarkets = vTokens.length;\n uint256 numBorrowCaps = newBorrowCaps.length;\n\n require(numMarkets != 0 && numMarkets == numBorrowCaps, \"invalid input\");\n\n _ensureMaxLoops(numMarkets);\n\n for (uint256 i; i < numMarkets; ++i) {\n borrowCaps[address(vTokens[i])] = newBorrowCaps[i];\n emit NewBorrowCap(vTokens[i], newBorrowCaps[i]);\n }\n }\n\n /**\n * @notice Set the given supply caps for the given vToken markets. Supply that brings total Supply to or above supply cap will revert.\n * @dev This function is restricted by the AccessControlManager\n * @dev A supply cap of type(uint256).max corresponds to unlimited supply.\n * @dev Supply caps smaller than the current total supplies are accepted. This way, new supplies will not be allowed\n until the total supplies amount goes below the new supply cap\n * @param vTokens The addresses of the markets (tokens) to change the supply caps for\n * @param newSupplyCaps The new supply cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited supply.\n * @custom:access Controlled by AccessControlManager\n */\n function setMarketSupplyCaps(VToken[] calldata vTokens, uint256[] calldata newSupplyCaps) external {\n _checkAccessAllowed(\"setMarketSupplyCaps(address[],uint256[])\");\n uint256 vTokensCount = vTokens.length;\n\n require(vTokensCount != 0, \"invalid number of markets\");\n require(vTokensCount == newSupplyCaps.length, \"invalid number of markets\");\n\n _ensureMaxLoops(vTokensCount);\n\n for (uint256 i; i < vTokensCount; ++i) {\n supplyCaps[address(vTokens[i])] = newSupplyCaps[i];\n emit NewSupplyCap(vTokens[i], newSupplyCaps[i]);\n }\n }\n\n /**\n * @notice Pause/unpause specified actions\n * @dev This function is restricted by the AccessControlManager\n * @param marketsList Markets to pause/unpause the actions on\n * @param actionsList List of action ids to pause/unpause\n * @param paused The new paused state (true=paused, false=unpaused)\n * @custom:access Controlled by AccessControlManager\n */\n function setActionsPaused(\n VToken[] calldata marketsList,\n Action[] calldata actionsList,\n bool paused\n ) external {\n _checkAccessAllowed(\"setActionsPaused(address[],uint256[],bool)\");\n\n uint256 marketsCount = marketsList.length;\n uint256 actionsCount = actionsList.length;\n\n _ensureMaxLoops(marketsCount * actionsCount);\n\n for (uint256 marketIdx; marketIdx < marketsCount; ++marketIdx) {\n for (uint256 actionIdx; actionIdx < actionsCount; ++actionIdx) {\n _setActionPaused(address(marketsList[marketIdx]), actionsList[actionIdx], paused);\n }\n }\n }\n\n /**\n * @notice Set the given collateral threshold for non-batch liquidations. Regular liquidations\n * will fail if the collateral amount is less than this threshold. Liquidators should use batch\n * operations like liquidateAccount or healAccount.\n * @dev This function is restricted by the AccessControlManager\n * @param newMinLiquidatableCollateral The new min liquidatable collateral (in USD).\n * @custom:access Controlled by AccessControlManager\n */\n function setMinLiquidatableCollateral(uint256 newMinLiquidatableCollateral) external {\n _checkAccessAllowed(\"setMinLiquidatableCollateral(uint256)\");\n\n uint256 oldMinLiquidatableCollateral = minLiquidatableCollateral;\n minLiquidatableCollateral = newMinLiquidatableCollateral;\n emit NewMinLiquidatableCollateral(oldMinLiquidatableCollateral, newMinLiquidatableCollateral);\n }\n\n /**\n * @notice Add a new RewardsDistributor and initialize it with all markets\n * @dev Only callable by the admin\n * @param _rewardsDistributor Address of the RewardDistributor contract to add\n * @custom:access Only Governance\n * @custom:event Emits NewRewardsDistributor with distributor address\n */\n function addRewardsDistributor(RewardsDistributor _rewardsDistributor) external onlyOwner {\n require(!rewardsDistributorExists[address(_rewardsDistributor)], \"already exists\");\n\n uint256 rewardsDistributorsLen = rewardsDistributors.length;\n _ensureMaxLoops(rewardsDistributorsLen + 1);\n\n rewardsDistributors.push(_rewardsDistributor);\n rewardsDistributorExists[address(_rewardsDistributor)] = true;\n\n uint256 marketsCount = allMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n _rewardsDistributor.initializeMarket(address(allMarkets[i]));\n }\n\n emit NewRewardsDistributor(address(_rewardsDistributor));\n }\n\n /**\n * @notice Sets a new price oracle for the Comptroller\n * @dev Only callable by the admin\n * @param newOracle Address of the new price oracle to set\n * @custom:event Emits NewPriceOracle on success\n * @custom:error ZeroAddressNotAllowed is thrown when the new oracle address is zero\n */\n function setPriceOracle(ResilientOracleInterface newOracle) external onlyOwner {\n ensureNonzeroAddress(address(newOracle));\n\n ResilientOracleInterface oldOracle = oracle;\n oracle = newOracle;\n emit NewPriceOracle(oldOracle, newOracle);\n }\n\n /**\n * @notice Set the for loop iteration limit to avoid DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Determine the current account liquidity with respect to liquidation threshold requirements\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param account The account get liquidity for\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Account liquidity in excess of liquidation threshold requirements,\n * @return shortfall Account shortfall below liquidation threshold requirements\n */\n function getAccountLiquidity(address account)\n external\n view\n returns (\n uint256 error,\n uint256 liquidity,\n uint256 shortfall\n )\n {\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getLiquidationThreshold);\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity with respect to collateral requirements\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param account The account get liquidity for\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Account liquidity in excess of collateral requirements,\n * @return shortfall Account shortfall below collateral requirements\n */\n function getBorrowingPower(address account)\n external\n view\n returns (\n uint256 error,\n uint256 liquidity,\n uint256 shortfall\n )\n {\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getCollateralFactor);\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param vTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Hypothetical account liquidity in excess of collateral requirements,\n * @return shortfall Hypothetical account shortfall below collateral requirements\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address vTokenModify,\n uint256 redeemTokens,\n uint256 borrowAmount\n )\n external\n view\n returns (\n uint256 error,\n uint256 liquidity,\n uint256 shortfall\n )\n {\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n account,\n VToken(vTokenModify),\n redeemTokens,\n borrowAmount,\n _getCollateralFactor\n );\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return markets The list of market addresses\n */\n function getAllMarkets() external view override returns (VToken[] memory) {\n return allMarkets;\n }\n\n /**\n * @notice Check if a market is marked as listed (active)\n * @param vToken vToken Address for the market to check\n * @return listed True if listed otherwise false\n */\n function isMarketListed(VToken vToken) external view returns (bool) {\n return markets[address(vToken)].isListed;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (VToken[] memory) {\n VToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in a given market\n * @param account The address of the account to check\n * @param vToken The vToken to check\n * @return True if the account is in the market specified, otherwise false.\n */\n function checkMembership(address account, VToken vToken) external view returns (bool) {\n return markets[address(vToken)].accountMembership[account];\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in vToken.liquidateBorrowFresh)\n * @param vTokenBorrowed The address of the borrowed vToken\n * @param vTokenCollateral The address of the collateral vToken\n * @param actualRepayAmount The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return tokensToSeize Number of vTokenCollateral tokens to be seized in a liquidation\n * @custom:error PriceError if the oracle returns an invalid price\n */\n function liquidateCalculateSeizeTokens(\n address vTokenBorrowed,\n address vTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256 error, uint256 tokensToSeize) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = _safeGetUnderlyingPrice(VToken(vTokenBorrowed));\n uint256 priceCollateralMantissa = _safeGetUnderlyingPrice(VToken(vTokenCollateral));\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint256 exchangeRateMantissa = VToken(vTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n\n numerator = mul_(Exp({ mantissa: liquidationIncentiveMantissa }), Exp({ mantissa: priceBorrowedMantissa }));\n denominator = mul_(Exp({ mantissa: priceCollateralMantissa }), Exp({ mantissa: exchangeRateMantissa }));\n ratio = div_(numerator, denominator);\n\n seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n return (NO_ERROR, seizeTokens);\n }\n\n /**\n * @notice Returns reward speed given a vToken\n * @param vToken The vToken to get the reward speeds for\n * @return rewardSpeeds Array of total supply and borrow speeds and reward token for all reward distributors\n */\n function getRewardsByMarket(address vToken) external view returns (RewardSpeeds[] memory rewardSpeeds) {\n uint256 rewardsDistributorsLength = rewardsDistributors.length;\n rewardSpeeds = new RewardSpeeds[](rewardsDistributorsLength);\n for (uint256 i; i < rewardsDistributorsLength; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n address rewardToken = address(rewardsDistributor.rewardToken());\n rewardSpeeds[i] = RewardSpeeds({\n rewardToken: rewardToken,\n supplySpeed: rewardsDistributor.rewardTokenSupplySpeeds(vToken),\n borrowSpeed: rewardsDistributor.rewardTokenBorrowSpeeds(vToken)\n });\n }\n return rewardSpeeds;\n }\n\n /**\n * @notice Return all reward distributors for this pool\n * @return Array of RewardDistributor addresses\n */\n function getRewardDistributors() external view returns (RewardsDistributor[] memory) {\n return rewardsDistributors;\n }\n\n /**\n * @notice A marker method that returns true for a valid Comptroller contract\n * @return Always true\n */\n function isComptroller() external pure override returns (bool) {\n return true;\n }\n\n /**\n * @notice Update the prices of all the tokens associated with the provided account\n * @param account Address of the account to get associated tokens with\n */\n function updatePrices(address account) public {\n VToken[] memory vTokens = accountAssets[account];\n uint256 vTokensCount = vTokens.length;\n\n ResilientOracleInterface oracle_ = oracle;\n\n for (uint256 i; i < vTokensCount; ++i) {\n oracle_.updatePrice(address(vTokens[i]));\n }\n }\n\n /**\n * @notice Checks if a certain action is paused on a market\n * @param market vToken address\n * @param action Action to check\n * @return paused True if the action is paused otherwise false\n */\n function actionPaused(address market, Action action) public view returns (bool) {\n return _actionPaused[market][action];\n }\n\n /**\n * @notice Check if a vToken market has been deprecated\n * @dev All borrows in a deprecated vToken market can be immediately liquidated\n * @param vToken The market to check if deprecated\n * @return deprecated True if the given vToken market has been deprecated\n */\n function isDeprecated(VToken vToken) public view returns (bool) {\n return\n markets[address(vToken)].collateralFactorMantissa == 0 &&\n actionPaused(address(vToken), Action.BORROW) &&\n vToken.reserveFactorMantissa() == MANTISSA_ONE;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param vToken The market to enter\n * @param borrower The address of the account to modify\n */\n function _addToMarket(VToken vToken, address borrower) internal {\n _checkActionPauseState(address(vToken), Action.ENTER_MARKET);\n Market storage marketToJoin = markets[address(vToken)];\n\n if (!marketToJoin.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n if (marketToJoin.accountMembership[borrower]) {\n // already joined\n return;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(vToken);\n\n emit MarketEntered(vToken, borrower);\n }\n\n /**\n * @notice Internal function to validate that a market hasn't already been added\n * and if it hasn't adds it\n * @param vToken The market to support\n */\n function _addMarket(address vToken) internal {\n uint256 marketsCount = allMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n if (allMarkets[i] == VToken(vToken)) {\n revert MarketAlreadyListed(vToken);\n }\n }\n allMarkets.push(VToken(vToken));\n marketsCount = allMarkets.length;\n _ensureMaxLoops(marketsCount);\n }\n\n /**\n * @dev Pause/unpause an action on a market\n * @param market Market to pause/unpause the action on\n * @param action Action id to pause/unpause\n * @param paused The new paused state (true=paused, false=unpaused)\n */\n function _setActionPaused(\n address market,\n Action action,\n bool paused\n ) internal {\n require(markets[market].isListed, \"cannot pause a market that is not listed\");\n _actionPaused[market][action] = paused;\n emit ActionPausedMarket(VToken(market), action, paused);\n }\n\n /**\n * @dev Internal function to check that vTokens can be safely redeemed for the underlying asset.\n * @param vToken Address of the vTokens to redeem\n * @param redeemer Account redeeming the tokens\n * @param redeemTokens The number of tokens to redeem\n */\n function _checkRedeemAllowed(\n address vToken,\n address redeemer,\n uint256 redeemTokens\n ) internal {\n Market storage market = markets[vToken];\n\n if (!market.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!market.accountMembership[redeemer]) {\n return;\n }\n\n // Update the prices of tokens\n updatePrices(redeemer);\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n redeemer,\n VToken(vToken),\n redeemTokens,\n 0,\n _getCollateralFactor\n );\n if (snapshot.shortfall > 0) {\n revert InsufficientLiquidity();\n }\n }\n\n /**\n * @notice Get the total collateral, weighted collateral, borrow balance, liquidity, shortfall\n * @param account The account to get the snapshot for\n * @param weight The function to compute the weight of the collateral – either collateral factor or\n * liquidation threshold. Accepts the address of the vToken and returns the weight as Exp.\n * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n * without calculating accumulated interest.\n * @return snapshot Account liquidity snapshot\n */\n function _getCurrentLiquiditySnapshot(address account, function(VToken) internal view returns (Exp memory) weight)\n internal\n view\n returns (AccountLiquiditySnapshot memory snapshot)\n {\n return _getHypotheticalLiquiditySnapshot(account, VToken(address(0)), 0, 0, weight);\n }\n\n /**\n * @notice Determine what the supply/borrow balances would be if the given amounts were redeemed/borrowed\n * @param vTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @param weight The function to compute the weight of the collateral – either collateral factor or\n liquidation threshold. Accepts the address of the VToken and returns the weight\n * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n * without calculating accumulated interest.\n * @return snapshot Account liquidity snapshot\n */\n function _getHypotheticalLiquiditySnapshot(\n address account,\n VToken vTokenModify,\n uint256 redeemTokens,\n uint256 borrowAmount,\n function(VToken) internal view returns (Exp memory) weight\n ) internal view returns (AccountLiquiditySnapshot memory snapshot) {\n // For each asset the account is in\n VToken[] memory assets = accountAssets[account];\n uint256 assetsCount = assets.length;\n\n for (uint256 i; i < assetsCount; ++i) {\n VToken asset = assets[i];\n\n // Read the balances and exchange rate from the vToken\n (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) = _safeGetAccountSnapshot(\n asset,\n account\n );\n\n // Get the normalized price of the asset\n Exp memory oraclePrice = Exp({ mantissa: _safeGetUnderlyingPrice(asset) });\n\n // Pre-compute conversion factors from vTokens -> usd\n Exp memory vTokenPrice = mul_(Exp({ mantissa: exchangeRateMantissa }), oraclePrice);\n Exp memory weightedVTokenPrice = mul_(weight(asset), vTokenPrice);\n\n // weightedCollateral += weightedVTokenPrice * vTokenBalance\n snapshot.weightedCollateral = mul_ScalarTruncateAddUInt(\n weightedVTokenPrice,\n vTokenBalance,\n snapshot.weightedCollateral\n );\n\n // totalCollateral += vTokenPrice * vTokenBalance\n snapshot.totalCollateral = mul_ScalarTruncateAddUInt(vTokenPrice, vTokenBalance, snapshot.totalCollateral);\n\n // borrows += oraclePrice * borrowBalance\n snapshot.borrows = mul_ScalarTruncateAddUInt(oraclePrice, borrowBalance, snapshot.borrows);\n\n // Calculate effects of interacting with vTokenModify\n if (asset == vTokenModify) {\n // redeem effect\n // effects += tokensToDenom * redeemTokens\n snapshot.effects = mul_ScalarTruncateAddUInt(weightedVTokenPrice, redeemTokens, snapshot.effects);\n\n // borrow effect\n // effects += oraclePrice * borrowAmount\n snapshot.effects = mul_ScalarTruncateAddUInt(oraclePrice, borrowAmount, snapshot.effects);\n }\n }\n\n uint256 borrowPlusEffects = snapshot.borrows + snapshot.effects;\n // These are safe, as the underflow condition is checked first\n unchecked {\n if (snapshot.weightedCollateral > borrowPlusEffects) {\n snapshot.liquidity = snapshot.weightedCollateral - borrowPlusEffects;\n snapshot.shortfall = 0;\n } else {\n snapshot.liquidity = 0;\n snapshot.shortfall = borrowPlusEffects - snapshot.weightedCollateral;\n }\n }\n\n return snapshot;\n }\n\n /**\n * @dev Retrieves price from oracle for an asset and checks it is nonzero\n * @param asset Address for asset to query price\n * @return Underlying price\n */\n function _safeGetUnderlyingPrice(VToken asset) internal view returns (uint256) {\n uint256 oraclePriceMantissa = oracle.getUnderlyingPrice(address(asset));\n if (oraclePriceMantissa == 0) {\n revert PriceError(address(asset));\n }\n return oraclePriceMantissa;\n }\n\n /**\n * @dev Return collateral factor for a market\n * @param asset Address for asset\n * @return Collateral factor as exponential\n */\n function _getCollateralFactor(VToken asset) internal view returns (Exp memory) {\n return Exp({ mantissa: markets[address(asset)].collateralFactorMantissa });\n }\n\n /**\n * @dev Retrieves liquidation threshold for a market as an exponential\n * @param asset Address for asset to liquidation threshold\n * @return Liquidation threshold as exponential\n */\n function _getLiquidationThreshold(VToken asset) internal view returns (Exp memory) {\n return Exp({ mantissa: markets[address(asset)].liquidationThresholdMantissa });\n }\n\n /**\n * @dev Returns supply and borrow balances of user in vToken, reverts on failure\n * @param vToken Market to query\n * @param user Account address\n * @return vTokenBalance Balance of vTokens, the same as vToken.balanceOf(user)\n * @return borrowBalance Borrowed amount, including the interest\n * @return exchangeRateMantissa Stored exchange rate\n */\n function _safeGetAccountSnapshot(VToken vToken, address user)\n internal\n view\n returns (\n uint256 vTokenBalance,\n uint256 borrowBalance,\n uint256 exchangeRateMantissa\n )\n {\n uint256 err;\n (err, vTokenBalance, borrowBalance, exchangeRateMantissa) = vToken.getAccountSnapshot(user);\n if (err != 0) {\n revert SnapshotError(address(vToken), user);\n }\n return (vTokenBalance, borrowBalance, exchangeRateMantissa);\n }\n\n /// @notice Reverts if the call is not from expectedSender\n /// @param expectedSender Expected transaction sender\n function _checkSenderIs(address expectedSender) internal view {\n if (msg.sender != expectedSender) {\n revert UnexpectedSender(expectedSender, msg.sender);\n }\n }\n\n /// @notice Reverts if a certain action is paused on a market\n /// @param market Market to check\n /// @param action Action to check\n function _checkActionPauseState(address market, Action action) private view {\n if (actionPaused(market, action)) {\n revert ActionPaused(market, action);\n }\n }\n}\n" + }, + "contracts/ComptrollerInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\n/**\n * @title ComptrollerInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract.\n */\ninterface ComptrollerInterface {\n /*** Assets You Are In ***/\n\n function enterMarkets(address[] calldata vTokens) external returns (uint256[] memory);\n\n function exitMarket(address vToken) external returns (uint256);\n\n /*** Policy Hooks ***/\n\n function preMintHook(\n address vToken,\n address minter,\n uint256 mintAmount\n ) external;\n\n function preRedeemHook(\n address vToken,\n address redeemer,\n uint256 redeemTokens\n ) external;\n\n function preBorrowHook(\n address vToken,\n address borrower,\n uint256 borrowAmount\n ) external;\n\n function preRepayHook(address vToken, address borrower) external;\n\n function preLiquidateHook(\n address vTokenBorrowed,\n address vTokenCollateral,\n address borrower,\n uint256 repayAmount,\n bool skipLiquidityCheck\n ) external;\n\n function preSeizeHook(\n address vTokenCollateral,\n address vTokenBorrowed,\n address liquidator,\n address borrower\n ) external;\n\n function preTransferHook(\n address vToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external;\n\n function isComptroller() external view returns (bool);\n\n /*** Liquidity/Liquidation Calculations ***/\n\n function liquidateCalculateSeizeTokens(\n address vTokenBorrowed,\n address vTokenCollateral,\n uint256 repayAmount\n ) external view returns (uint256, uint256);\n\n function getAllMarkets() external view returns (VToken[] memory);\n}\n\n/**\n * @title ComptrollerViewInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract, including only some util view functions.\n */\ninterface ComptrollerViewInterface {\n function markets(address) external view returns (bool, uint256);\n\n function oracle() external view returns (ResilientOracleInterface);\n\n function getAssetsIn(address) external view returns (VToken[] memory);\n\n function closeFactorMantissa() external view returns (uint256);\n\n function liquidationIncentiveMantissa() external view returns (uint256);\n\n function minLiquidatableCollateral() external view returns (uint256);\n\n function getRewardDistributors() external view returns (RewardsDistributor[] memory);\n\n function getAllMarkets() external view returns (VToken[] memory);\n\n function borrowCaps(address) external view returns (uint256);\n\n function supplyCaps(address) external view returns (uint256);\n}\n" + }, + "contracts/ComptrollerStorage.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\n/**\n * @title ComptrollerStorage\n * @author Venus\n * @notice Storage layout for the `Comptroller` contract.\n */\ncontract ComptrollerStorage {\n struct LiquidationOrder {\n VToken vTokenCollateral;\n VToken vTokenBorrowed;\n uint256 repayAmount;\n }\n\n struct AccountLiquiditySnapshot {\n uint256 totalCollateral;\n uint256 weightedCollateral;\n uint256 borrows;\n uint256 effects;\n uint256 liquidity;\n uint256 shortfall;\n }\n\n struct RewardSpeeds {\n address rewardToken;\n uint256 supplySpeed;\n uint256 borrowSpeed;\n }\n\n struct Market {\n // Whether or not this market is listed\n bool isListed;\n // Multiplier representing the most one can borrow against their collateral in this market.\n // For instance, 0.9 to allow borrowing 90% of collateral value.\n // Must be between 0 and 1, and stored as a mantissa.\n uint256 collateralFactorMantissa;\n // Multiplier representing the collateralization after which the borrow is eligible\n // for liquidation. For instance, 0.8 liquidate when the borrow is 80% of collateral\n // value. Must be between 0 and collateral factor, stored as a mantissa.\n uint256 liquidationThresholdMantissa;\n // Per-market mapping of \"accounts in this asset\"\n mapping(address => bool) accountMembership;\n }\n\n enum Action {\n MINT,\n REDEEM,\n BORROW,\n REPAY,\n SEIZE,\n LIQUIDATE,\n TRANSFER,\n ENTER_MARKET,\n EXIT_MARKET\n }\n\n /**\n * @notice Oracle which gives the price of any given asset\n */\n ResilientOracleInterface public oracle;\n\n /**\n * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow\n */\n uint256 public closeFactorMantissa;\n\n /**\n * @notice Multiplier representing the discount on collateral that a liquidator receives\n */\n uint256 public liquidationIncentiveMantissa;\n\n /**\n * @notice Per-account mapping of \"assets you are in\"\n */\n mapping(address => VToken[]) public accountAssets;\n\n /**\n * @notice Official mapping of vTokens -> Market metadata\n * @dev Used e.g. to determine if a market is supported\n */\n mapping(address => Market) public markets;\n\n /// @notice A list of all markets\n VToken[] public allMarkets;\n\n /// @notice Borrow caps enforced by borrowAllowed for each vToken address. Defaults to zero which restricts borrowing.\n mapping(address => uint256) public borrowCaps;\n\n /// @notice Minimal collateral required for regular (non-batch) liquidations\n uint256 public minLiquidatableCollateral;\n\n /// @notice Supply caps enforced by mintAllowed for each vToken address. Defaults to zero which corresponds to minting not allowed\n mapping(address => uint256) public supplyCaps;\n\n /// @notice True if a certain action is paused on a certain market\n mapping(address => mapping(Action => bool)) internal _actionPaused;\n\n // List of Reward Distributors added\n RewardsDistributor[] internal rewardsDistributors;\n\n // Used to check if rewards distributor is added\n mapping(address => bool) internal rewardsDistributorExists;\n\n uint256 internal constant NO_ERROR = 0;\n\n // closeFactorMantissa must be strictly greater than this value\n uint256 internal constant MIN_CLOSE_FACTOR_MANTISSA = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant MAX_CLOSE_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant MAX_COLLATERAL_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "contracts/ErrorReporter.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title TokenErrorReporter\n * @author Venus\n * @notice Errors that can be thrown by the `VToken` contract.\n */\ncontract TokenErrorReporter {\n uint256 public constant NO_ERROR = 0; // support legacy return codes\n\n error TransferNotAllowed();\n\n error MintFreshnessCheck();\n\n error RedeemFreshnessCheck();\n error RedeemTransferOutNotPossible();\n\n error BorrowFreshnessCheck();\n error BorrowCashNotAvailable();\n\n error RepayBorrowFreshnessCheck();\n\n error HealBorrowUnauthorized();\n error ForceLiquidateBorrowUnauthorized();\n\n error LiquidateFreshnessCheck();\n error LiquidateCollateralFreshnessCheck();\n error LiquidateAccrueCollateralInterestFailed(uint256 errorCode);\n error LiquidateLiquidatorIsBorrower();\n error LiquidateCloseAmountIsZero();\n error LiquidateCloseAmountIsUintMax();\n\n error LiquidateSeizeLiquidatorIsBorrower();\n\n error ProtocolSeizeShareTooBig();\n\n error SetReserveFactorFreshCheck();\n error SetReserveFactorBoundsCheck();\n\n error AddReservesFactorFreshCheck(uint256 actualAddAmount);\n\n error ReduceReservesFreshCheck();\n error ReduceReservesCashNotAvailable();\n error ReduceReservesCashValidation();\n\n error SetInterestRateModelFreshCheck();\n}\n" + }, + "contracts/ExponentialNoError.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { EXP_SCALE as EXP_SCALE_, MANTISSA_ONE as MANTISSA_ONE_ } from \"./lib/constants.sol\";\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author Compound\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\n * `Exp({mantissa: 5100000000000000000})`.\n */\ncontract ExponentialNoError {\n struct Exp {\n uint256 mantissa;\n }\n\n struct Double {\n uint256 mantissa;\n }\n\n uint256 internal constant EXP_SCALE = EXP_SCALE_;\n uint256 internal constant DOUBLE_SCALE = 1e36;\n uint256 internal constant HALF_EXP_SCALE = EXP_SCALE / 2;\n uint256 internal constant MANTISSA_ONE = MANTISSA_ONE_;\n\n /**\n * @dev Truncates the given exp to a whole number value.\n * For example, truncate(Exp{mantissa: 15 * EXP_SCALE}) = 15\n */\n function truncate(Exp memory exp) internal pure returns (uint256) {\n // Note: We are not using careful math here as we're performing a division that cannot fail\n return exp.mantissa / EXP_SCALE;\n }\n\n /**\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\n */\n // solhint-disable-next-line func-name-mixedcase\n function mul_ScalarTruncate(Exp memory a, uint256 scalar) internal pure returns (uint256) {\n Exp memory product = mul_(a, scalar);\n return truncate(product);\n }\n\n /**\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\n */\n // solhint-disable-next-line func-name-mixedcase\n function mul_ScalarTruncateAddUInt(\n Exp memory a,\n uint256 scalar,\n uint256 addend\n ) internal pure returns (uint256) {\n Exp memory product = mul_(a, scalar);\n return add_(truncate(product), addend);\n }\n\n /**\n * @dev Checks if first Exp is less than second Exp.\n */\n function lessThanExp(Exp memory left, Exp memory right) internal pure returns (bool) {\n return left.mantissa < right.mantissa;\n }\n\n function safe224(uint256 n, string memory errorMessage) internal pure returns (uint224) {\n require(n <= type(uint224).max, errorMessage);\n return uint224(n);\n }\n\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n <= type(uint32).max, errorMessage);\n return uint32(n);\n }\n\n function add_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: add_(a.mantissa, b.mantissa) });\n }\n\n function add_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: add_(a.mantissa, b.mantissa) });\n }\n\n function add_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n function sub_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: sub_(a.mantissa, b.mantissa) });\n }\n\n function sub_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: sub_(a.mantissa, b.mantissa) });\n }\n\n function sub_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n function mul_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: mul_(a.mantissa, b.mantissa) / EXP_SCALE });\n }\n\n function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n return Exp({ mantissa: mul_(a.mantissa, b) });\n }\n\n function mul_(uint256 a, Exp memory b) internal pure returns (uint256) {\n return mul_(a, b.mantissa) / EXP_SCALE;\n }\n\n function mul_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: mul_(a.mantissa, b.mantissa) / DOUBLE_SCALE });\n }\n\n function mul_(Double memory a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: mul_(a.mantissa, b) });\n }\n\n function mul_(uint256 a, Double memory b) internal pure returns (uint256) {\n return mul_(a, b.mantissa) / DOUBLE_SCALE;\n }\n\n function mul_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n function div_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: div_(mul_(a.mantissa, EXP_SCALE), b.mantissa) });\n }\n\n function div_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n return Exp({ mantissa: div_(a.mantissa, b) });\n }\n\n function div_(uint256 a, Exp memory b) internal pure returns (uint256) {\n return div_(mul_(a, EXP_SCALE), b.mantissa);\n }\n\n function div_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(mul_(a.mantissa, DOUBLE_SCALE), b.mantissa) });\n }\n\n function div_(Double memory a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(a.mantissa, b) });\n }\n\n function div_(uint256 a, Double memory b) internal pure returns (uint256) {\n return div_(mul_(a, DOUBLE_SCALE), b.mantissa);\n }\n\n function div_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n function fraction(uint256 a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(mul_(a, DOUBLE_SCALE), b) });\n }\n}\n" + }, + "contracts/InterestRateModel.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title Compound's InterestRateModel Interface\n * @author Compound\n */\nabstract contract InterestRateModel {\n /**\n * @notice Calculates the current borrow interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) external view virtual returns (uint256);\n\n /**\n * @notice Calculates the current supply interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param reserveFactorMantissa The current reserve factor the market has\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate per block (as a percentage, and scaled by 1e18)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) external view virtual returns (uint256);\n\n /**\n * @notice Indicator that this is an InterestRateModel contract (for inspection)\n * @return Always true\n */\n function isInterestRateModel() external pure virtual returns (bool) {\n return true;\n }\n}\n" + }, + "contracts/IPancakeswapV2Router.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface IPancakeswapV2Router {\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n}\n" + }, + "contracts/JumpRateModelV2.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\n\nimport { BaseJumpRateModelV2 } from \"./BaseJumpRateModelV2.sol\";\n\n/**\n * @title Compound's JumpRateModel Contract V2 for V2 vTokens\n * @author Arr00\n * @notice Supports only for V2 vTokens\n */\ncontract JumpRateModelV2 is BaseJumpRateModelV2 {\n constructor(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n IAccessControlManagerV8 accessControlManager_\n )\n BaseJumpRateModelV2(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_, accessControlManager_)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n /**\n * @notice Calculates the current borrow rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) external view override returns (uint256) {\n return _getBorrowRate(cash, borrows, reserves, badDebt);\n }\n}\n" + }, + "contracts/Lens/PoolLens.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { RewardsDistributor } from \"../Rewards/RewardsDistributor.sol\";\n\n/**\n * @title PoolLens\n * @author Venus\n * @notice The `PoolLens` contract is designed to retrieve important information for each registered pool. A list of essential information\n * for all pools within the lending protocol can be acquired through the function `getAllPools()`. Additionally, the following records can be\n * looked up for specific pools and markets:\n- the vToken balance of a given user;\n- the pool data (oracle address, associated vToken, liquidation incentive, etc) of a pool via its associated comptroller address;\n- the vToken address in a pool for a given asset;\n- a list of all pools that support an asset;\n- the underlying asset price of a vToken;\n- the metadata (exchange/borrow/supply rate, total supply, collateral factor, etc) of any vToken.\n */\ncontract PoolLens is ExponentialNoError {\n /**\n * @dev Struct for PoolDetails.\n */\n struct PoolData {\n string name;\n address creator;\n address comptroller;\n uint256 blockPosted;\n uint256 timestampPosted;\n string category;\n string logoURL;\n string description;\n address priceOracle;\n uint256 closeFactor;\n uint256 liquidationIncentive;\n uint256 minLiquidatableCollateral;\n VTokenMetadata[] vTokens;\n }\n\n /**\n * @dev Struct for VToken.\n */\n struct VTokenMetadata {\n address vToken;\n uint256 exchangeRateCurrent;\n uint256 supplyRatePerBlock;\n uint256 borrowRatePerBlock;\n uint256 reserveFactorMantissa;\n uint256 supplyCaps;\n uint256 borrowCaps;\n uint256 totalBorrows;\n uint256 totalReserves;\n uint256 totalSupply;\n uint256 totalCash;\n bool isListed;\n uint256 collateralFactorMantissa;\n address underlyingAssetAddress;\n uint256 vTokenDecimals;\n uint256 underlyingDecimals;\n }\n\n /**\n * @dev Struct for VTokenBalance.\n */\n struct VTokenBalances {\n address vToken;\n uint256 balanceOf;\n uint256 borrowBalanceCurrent;\n uint256 balanceOfUnderlying;\n uint256 tokenBalance;\n uint256 tokenAllowance;\n }\n\n /**\n * @dev Struct for underlyingPrice of VToken.\n */\n struct VTokenUnderlyingPrice {\n address vToken;\n uint256 underlyingPrice;\n }\n\n /**\n * @dev Struct with pending reward info for a market.\n */\n struct PendingReward {\n address vTokenAddress;\n uint256 amount;\n }\n\n /**\n * @dev Struct with reward distribution totals for a single reward token and distributor.\n */\n struct RewardSummary {\n address distributorAddress;\n address rewardTokenAddress;\n uint256 totalRewards;\n PendingReward[] pendingRewards;\n }\n\n /**\n * @dev Struct used in RewardDistributor to save last updated market state.\n */\n struct RewardTokenState {\n // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n uint224 index;\n // The block number the index was last updated at\n uint32 block;\n // The block number at which to stop rewards\n uint32 lastRewardingBlock;\n }\n\n /**\n * @dev Struct with bad debt of a market denominated\n */\n struct BadDebt {\n address vTokenAddress;\n uint256 badDebtUsd;\n }\n\n /**\n * @dev Struct with bad debt total denominated in usd for a pool and an array of BadDebt structs for each market\n */\n struct BadDebtSummary {\n address comptroller;\n uint256 totalBadDebtUsd;\n BadDebt[] badDebts;\n }\n\n /**\n * @notice Queries the user's supply/borrow balances in vTokens\n * @param vTokens The list of vToken addresses\n * @param account The user Account\n * @return A list of structs containing balances data\n */\n function vTokenBalancesAll(VToken[] calldata vTokens, address account) external returns (VTokenBalances[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenBalances[] memory res = new VTokenBalances[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenBalances(vTokens[i], account);\n }\n return res;\n }\n\n /**\n * @notice Queries all pools with addtional details for each of them\n * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @return Arrays of all Venus pools' data\n */\n function getAllPools(address poolRegistryAddress) external view returns (PoolData[] memory) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n PoolRegistry.VenusPool[] memory venusPools = poolRegistryInterface.getAllPools();\n uint256 poolLength = venusPools.length;\n\n PoolData[] memory poolDataItems = new PoolData[](poolLength);\n\n for (uint256 i; i < poolLength; ++i) {\n PoolRegistry.VenusPool memory venusPool = venusPools[i];\n PoolData memory poolData = getPoolDataFromVenusPool(poolRegistryAddress, venusPool);\n poolDataItems[i] = poolData;\n }\n\n return poolDataItems;\n }\n\n /**\n * @notice Queries the details of a pool identified by Comptroller address\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param comptroller The Comptroller implementation address\n * @return PoolData structure containing the details of the pool\n */\n function getPoolByComptroller(address poolRegistryAddress, address comptroller)\n external\n view\n returns (PoolData memory)\n {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return getPoolDataFromVenusPool(poolRegistryAddress, poolRegistryInterface.getPoolByComptroller(comptroller));\n }\n\n /**\n * @notice Returns vToken holding the specified underlying asset in the specified pool\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param comptroller The pool comptroller\n * @param asset The underlyingAsset of VToken\n * @return Address of the vToken\n */\n function getVTokenForAsset(\n address poolRegistryAddress,\n address comptroller,\n address asset\n ) external view returns (address) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return poolRegistryInterface.getVTokenForAsset(comptroller, asset);\n }\n\n /**\n * @notice Returns all pools that support the specified underlying asset\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param asset The underlying asset of vToken\n * @return A list of Comptroller contracts\n */\n function getPoolsSupportedByAsset(address poolRegistryAddress, address asset)\n external\n view\n returns (address[] memory)\n {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return poolRegistryInterface.getPoolsSupportedByAsset(asset);\n }\n\n /**\n * @notice Returns the price data for the underlying assets of the specified vTokens\n * @param vTokens The list of vToken addresses\n * @return An array containing the price data for each asset\n */\n function vTokenUnderlyingPriceAll(VToken[] calldata vTokens)\n external\n view\n returns (VTokenUnderlyingPrice[] memory)\n {\n uint256 vTokenCount = vTokens.length;\n VTokenUnderlyingPrice[] memory res = new VTokenUnderlyingPrice[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenUnderlyingPrice(vTokens[i]);\n }\n return res;\n }\n\n /**\n * @notice Returns the pending rewards for a user for a given pool.\n * @param account The user account.\n * @param comptrollerAddress address\n * @return Pending rewards array\n */\n function getPendingRewards(address account, address comptrollerAddress)\n external\n view\n returns (RewardSummary[] memory)\n {\n VToken[] memory markets = ComptrollerInterface(comptrollerAddress).getAllMarkets();\n RewardsDistributor[] memory rewardsDistributors = ComptrollerViewInterface(comptrollerAddress)\n .getRewardDistributors();\n RewardSummary[] memory rewardSummary = new RewardSummary[](rewardsDistributors.length);\n for (uint256 i; i < rewardsDistributors.length; ++i) {\n RewardSummary memory reward;\n reward.distributorAddress = address(rewardsDistributors[i]);\n reward.rewardTokenAddress = address(rewardsDistributors[i].rewardToken());\n reward.totalRewards = rewardsDistributors[i].rewardTokenAccrued(account);\n reward.pendingRewards = _calculateNotDistributedAwards(account, markets, rewardsDistributors[i]);\n rewardSummary[i] = reward;\n }\n return rewardSummary;\n }\n\n /**\n * @notice Returns a summary of a pool's bad debt broken down by market\n *\n * @param comptrollerAddress Address of the comptroller\n *\n * @return badDebtSummary A struct with comptroller address, total bad debut denominated in usd, and\n * a break down of bad debt by market\n */\n function getPoolBadDebt(address comptrollerAddress) external view returns (BadDebtSummary memory) {\n uint256 totalBadDebtUsd;\n\n // Get every market in the pool\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n VToken[] memory markets = comptroller.getAllMarkets();\n ResilientOracleInterface priceOracle = comptroller.oracle();\n\n BadDebt[] memory badDebts = new BadDebt[](markets.length);\n\n BadDebtSummary memory badDebtSummary;\n badDebtSummary.comptroller = comptrollerAddress;\n badDebtSummary.badDebts = badDebts;\n\n // // Calculate the bad debt is USD per market\n for (uint256 i; i < markets.length; ++i) {\n BadDebt memory badDebt;\n badDebt.vTokenAddress = address(markets[i]);\n badDebt.badDebtUsd =\n (VToken(address(markets[i])).badDebt() * priceOracle.getUnderlyingPrice(address(markets[i]))) /\n EXP_SCALE;\n badDebtSummary.badDebts[i] = badDebt;\n totalBadDebtUsd = totalBadDebtUsd + badDebt.badDebtUsd;\n }\n\n badDebtSummary.totalBadDebtUsd = totalBadDebtUsd;\n\n return badDebtSummary;\n }\n\n /**\n * @notice Queries the user's supply/borrow balances in the specified vToken\n * @param vToken vToken address\n * @param account The user Account\n * @return A struct containing the balances data\n */\n function vTokenBalances(VToken vToken, address account) public returns (VTokenBalances memory) {\n uint256 balanceOf = vToken.balanceOf(account);\n uint256 borrowBalanceCurrent = vToken.borrowBalanceCurrent(account);\n uint256 balanceOfUnderlying = vToken.balanceOfUnderlying(account);\n uint256 tokenBalance;\n uint256 tokenAllowance;\n\n IERC20 underlying = IERC20(vToken.underlying());\n tokenBalance = underlying.balanceOf(account);\n tokenAllowance = underlying.allowance(account, address(vToken));\n\n return\n VTokenBalances({\n vToken: address(vToken),\n balanceOf: balanceOf,\n borrowBalanceCurrent: borrowBalanceCurrent,\n balanceOfUnderlying: balanceOfUnderlying,\n tokenBalance: tokenBalance,\n tokenAllowance: tokenAllowance\n });\n }\n\n /**\n * @notice Queries additional information for the pool\n * @param poolRegistryAddress Address of the PoolRegistry\n * @param venusPool The VenusPool Object from PoolRegistry\n * @return Enriched PoolData\n */\n function getPoolDataFromVenusPool(address poolRegistryAddress, PoolRegistry.VenusPool memory venusPool)\n public\n view\n returns (PoolData memory)\n {\n // Get tokens in the Pool\n ComptrollerInterface comptrollerInstance = ComptrollerInterface(venusPool.comptroller);\n\n VToken[] memory vTokens = comptrollerInstance.getAllMarkets();\n\n VTokenMetadata[] memory vTokenMetadataItems = vTokenMetadataAll(vTokens);\n\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n\n PoolRegistry.VenusPoolMetaData memory venusPoolMetaData = poolRegistryInterface.getVenusPoolMetadata(\n venusPool.comptroller\n );\n\n ComptrollerViewInterface comptrollerViewInstance = ComptrollerViewInterface(venusPool.comptroller);\n\n PoolData memory poolData = PoolData({\n name: venusPool.name,\n creator: venusPool.creator,\n comptroller: venusPool.comptroller,\n blockPosted: venusPool.blockPosted,\n timestampPosted: venusPool.timestampPosted,\n category: venusPoolMetaData.category,\n logoURL: venusPoolMetaData.logoURL,\n description: venusPoolMetaData.description,\n vTokens: vTokenMetadataItems,\n priceOracle: address(comptrollerViewInstance.oracle()),\n closeFactor: comptrollerViewInstance.closeFactorMantissa(),\n liquidationIncentive: comptrollerViewInstance.liquidationIncentiveMantissa(),\n minLiquidatableCollateral: comptrollerViewInstance.minLiquidatableCollateral()\n });\n\n return poolData;\n }\n\n /**\n * @notice Returns the metadata of VToken\n * @param vToken The address of vToken\n * @return VTokenMetadata struct\n */\n function vTokenMetadata(VToken vToken) public view returns (VTokenMetadata memory) {\n uint256 exchangeRateCurrent = vToken.exchangeRateStored();\n address comptrollerAddress = address(vToken.comptroller());\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n (bool isListed, uint256 collateralFactorMantissa) = comptroller.markets(address(vToken));\n\n address underlyingAssetAddress = vToken.underlying();\n uint256 underlyingDecimals = IERC20Metadata(underlyingAssetAddress).decimals();\n\n return\n VTokenMetadata({\n vToken: address(vToken),\n exchangeRateCurrent: exchangeRateCurrent,\n supplyRatePerBlock: vToken.supplyRatePerBlock(),\n borrowRatePerBlock: vToken.borrowRatePerBlock(),\n reserveFactorMantissa: vToken.reserveFactorMantissa(),\n supplyCaps: comptroller.supplyCaps(address(vToken)),\n borrowCaps: comptroller.borrowCaps(address(vToken)),\n totalBorrows: vToken.totalBorrows(),\n totalReserves: vToken.totalReserves(),\n totalSupply: vToken.totalSupply(),\n totalCash: vToken.getCash(),\n isListed: isListed,\n collateralFactorMantissa: collateralFactorMantissa,\n underlyingAssetAddress: underlyingAssetAddress,\n vTokenDecimals: vToken.decimals(),\n underlyingDecimals: underlyingDecimals\n });\n }\n\n /**\n * @notice Returns the metadata of all VTokens\n * @param vTokens The list of vToken addresses\n * @return An array of VTokenMetadata structs\n */\n function vTokenMetadataAll(VToken[] memory vTokens) public view returns (VTokenMetadata[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenMetadata[] memory res = new VTokenMetadata[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenMetadata(vTokens[i]);\n }\n return res;\n }\n\n /**\n * @notice Returns the price data for the underlying asset of the specified vToken\n * @param vToken vToken address\n * @return The price data for each asset\n */\n function vTokenUnderlyingPrice(VToken vToken) public view returns (VTokenUnderlyingPrice memory) {\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(address(vToken.comptroller()));\n ResilientOracleInterface priceOracle = comptroller.oracle();\n\n return\n VTokenUnderlyingPrice({\n vToken: address(vToken),\n underlyingPrice: priceOracle.getUnderlyingPrice(address(vToken))\n });\n }\n\n function _calculateNotDistributedAwards(\n address account,\n VToken[] memory markets,\n RewardsDistributor rewardsDistributor\n ) internal view returns (PendingReward[] memory) {\n PendingReward[] memory pendingRewards = new PendingReward[](markets.length);\n for (uint256 i; i < markets.length; ++i) {\n // Market borrow and supply state we will modify update in-memory, in order to not modify storage\n RewardTokenState memory borrowState;\n (borrowState.index, borrowState.block, borrowState.lastRewardingBlock) = rewardsDistributor\n .rewardTokenBorrowState(address(markets[i]));\n RewardTokenState memory supplyState;\n (supplyState.index, supplyState.block, supplyState.lastRewardingBlock) = rewardsDistributor\n .rewardTokenSupplyState(address(markets[i]));\n Exp memory marketBorrowIndex = Exp({ mantissa: markets[i].borrowIndex() });\n\n // Update market supply and borrow index in-memory\n updateMarketBorrowIndex(address(markets[i]), rewardsDistributor, borrowState, marketBorrowIndex);\n updateMarketSupplyIndex(address(markets[i]), rewardsDistributor, supplyState);\n\n // Calculate pending rewards\n uint256 borrowReward = calculateBorrowerReward(\n address(markets[i]),\n rewardsDistributor,\n account,\n borrowState,\n marketBorrowIndex\n );\n uint256 supplyReward = calculateSupplierReward(\n address(markets[i]),\n rewardsDistributor,\n account,\n supplyState\n );\n\n PendingReward memory pendingReward;\n pendingReward.vTokenAddress = address(markets[i]);\n pendingReward.amount = borrowReward + supplyReward;\n pendingRewards[i] = pendingReward;\n }\n return pendingRewards;\n }\n\n function updateMarketBorrowIndex(\n address vToken,\n RewardsDistributor rewardsDistributor,\n RewardTokenState memory borrowState,\n Exp memory marketBorrowIndex\n ) internal view {\n uint256 borrowSpeed = rewardsDistributor.rewardTokenBorrowSpeeds(vToken);\n uint256 blockNumber = block.number;\n\n if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n blockNumber = borrowState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n // Remove the total earned interest rate since the opening of the market from total borrows\n uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n uint256 tokensAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0 ? fraction(tokensAccrued, borrowAmount) : Double({ mantissa: 0 });\n Double memory index = add_(Double({ mantissa: borrowState.index }), ratio);\n borrowState.index = safe224(index.mantissa, \"new index overflows\");\n borrowState.block = safe32(blockNumber, \"block number overflows\");\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block number overflows\");\n }\n }\n\n function updateMarketSupplyIndex(\n address vToken,\n RewardsDistributor rewardsDistributor,\n RewardTokenState memory supplyState\n ) internal view {\n uint256 supplySpeed = rewardsDistributor.rewardTokenSupplySpeeds(vToken);\n uint256 blockNumber = block.number;\n\n if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n blockNumber = supplyState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = VToken(vToken).totalSupply();\n uint256 tokensAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(tokensAccrued, supplyTokens) : Double({ mantissa: 0 });\n Double memory index = add_(Double({ mantissa: supplyState.index }), ratio);\n supplyState.index = safe224(index.mantissa, \"new index overflows\");\n supplyState.block = safe32(blockNumber, \"block number overflows\");\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number overflows\");\n }\n }\n\n function calculateBorrowerReward(\n address vToken,\n RewardsDistributor rewardsDistributor,\n address borrower,\n RewardTokenState memory borrowState,\n Exp memory marketBorrowIndex\n ) internal view returns (uint256) {\n Double memory borrowIndex = Double({ mantissa: borrowState.index });\n Double memory borrowerIndex = Double({\n mantissa: rewardsDistributor.rewardTokenBorrowerIndex(vToken, borrower)\n });\n if (borrowerIndex.mantissa == 0 && borrowIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n // Covers the case where users borrowed tokens before the market's borrow state index was set\n borrowerIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n }\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n return borrowerDelta;\n }\n\n function calculateSupplierReward(\n address vToken,\n RewardsDistributor rewardsDistributor,\n address supplier,\n RewardTokenState memory supplyState\n ) internal view returns (uint256) {\n Double memory supplyIndex = Double({ mantissa: supplyState.index });\n Double memory supplierIndex = Double({\n mantissa: rewardsDistributor.rewardTokenSupplierIndex(vToken, supplier)\n });\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n // Covers the case where users supplied tokens before the market's supply state index was set\n supplierIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n }\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n return supplierDelta;\n }\n}\n" + }, + "contracts/lib/ApproveOrRevert.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nlibrary ApproveOrRevert {\n /// @notice Thrown if a contract is unable to approve a transfer\n error ApproveFailed();\n\n /// @notice Approves a transfer, ensuring that it is successful. This function supports non-compliant\n /// tokens like the ones that don't return a boolean value on success. Thus, such approve call supports\n /// three different kinds of tokens:\n /// * Compliant tokens that revert on failure\n /// * Compliant tokens that return false on failure\n /// * Non-compliant tokens that don't return a value\n /// @param token The contract address of the token which will be transferred\n /// @param spender The spender contract address\n /// @param amount The value of the transfer\n function approveOrRevert(\n IERC20Upgradeable token,\n address spender,\n uint256 amount\n ) internal {\n bytes memory callData = abi.encodeCall(token.approve, (spender, amount));\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory result) = address(token).call(callData);\n\n if (!success || (result.length != 0 && !abi.decode(result, (bool)))) {\n revert ApproveFailed();\n }\n }\n}\n" + }, + "contracts/lib/constants.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/// @dev The approximate number of blocks per year that is assumed by the interest rate model\nuint256 constant BLOCKS_PER_YEAR = 10_512_000;\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" + }, + "contracts/lib/imports.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n// This file is needed to make hardhat and typechain generate artifacts for\n// contracts we depend on (e.g. in tests or deployments) but not use directly.\n// Another way to do this would be to use hardhat-dependency-compiler, but\n// since we only have a couple of dependencies, installing a separate package\n// seems an overhead.\n\nimport { UpgradeableBeacon } from \"@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol\";\nimport { BeaconProxy } from \"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\";\n" + }, + "contracts/lib/TokenDebtTracker.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n/**\n * @title TokenDebtTracker\n * @author Venus\n * @notice TokenDebtTracker is an abstract contract that handles transfers _out_ of the inheriting contract.\n * If there is an error transferring out (due to any reason, e.g. the token contract restricted the user from\n * receiving incoming transfers), the amount is recorded as a debt that can be claimed later.\n * @dev Note that the inheriting contract keeps some amount of users' tokens on its balance, so be careful when\n * using balanceOf(address(this))!\n */\nabstract contract TokenDebtTracker is Initializable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /**\n * @notice Mapping (IERC20Upgradeable token => (address user => uint256 amount)).\n * Tracks failed transfers: when a token transfer fails, we record the\n * amount of the transfer, so that the user can redeem this debt later.\n */\n mapping(IERC20Upgradeable => mapping(address => uint256)) public tokenDebt;\n\n /**\n * @notice Mapping (IERC20Upgradeable token => uint256 amount) shows how many\n * tokens the contract owes to all users. This is useful for accounting to\n * understand how much of balanceOf(address(this)) is already owed to users.\n */\n mapping(IERC20Upgradeable => uint256) public totalTokenDebt;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[48] private __gap;\n\n /**\n * @notice Emitted when the contract's debt to the user is increased due to a failed transfer\n * @param token Token address\n * @param user User address\n * @param amount The amount of debt added\n */\n event TokenDebtAdded(address indexed token, address indexed user, uint256 amount);\n\n /**\n * @notice Emitted when a user claims tokens that the contract owes them\n * @param token Token address\n * @param user User address\n * @param amount The amount transferred\n */\n event TokenDebtClaimed(address indexed token, address indexed user, uint256 amount);\n\n /**\n * @notice Thrown if the user tries to claim more tokens than they are owed\n * @param token The token the user is trying to claim\n * @param owedAmount The amount of tokens the contract owes to the user\n * @param amount The amount of tokens the user is trying to claim\n */\n error InsufficientDebt(address token, address user, uint256 owedAmount, uint256 amount);\n\n /**\n * @notice Thrown if trying to transfer more tokens than the contract currently has\n * @param token The token the contract is trying to transfer\n * @param recipient The recipient of the transfer\n * @param amount The amount of tokens the contract is trying to transfer\n * @param availableBalance The amount of tokens the contract currently has\n */\n error InsufficientBalance(address token, address recipient, uint256 amount, uint256 availableBalance);\n\n /**\n * @notice Transfers the tokens we owe to msg.sender, if any\n * @param token The token to claim\n * @param amount_ The amount of tokens to claim (or max uint256 to claim all)\n * @custom:error InsufficientDebt The contract doesn't have enough debt to the user\n */\n function claimTokenDebt(IERC20Upgradeable token, uint256 amount_) external {\n uint256 owedAmount = tokenDebt[token][msg.sender];\n uint256 amount = (amount_ == type(uint256).max ? owedAmount : amount_);\n if (amount > owedAmount) {\n revert InsufficientDebt(address(token), msg.sender, owedAmount, amount);\n }\n unchecked {\n // Safe because we revert if amount > owedAmount above\n tokenDebt[token][msg.sender] = owedAmount - amount;\n }\n totalTokenDebt[token] -= amount;\n emit TokenDebtClaimed(address(token), msg.sender, amount);\n token.safeTransfer(msg.sender, amount);\n }\n\n // solhint-disable-next-line func-name-mixedcase\n function __TokenDebtTracker_init() internal onlyInitializing {\n __TokenDebtTracker_init_unchained();\n }\n\n // solhint-disable-next-line func-name-mixedcase, no-empty-blocks\n function __TokenDebtTracker_init_unchained() internal onlyInitializing {}\n\n /**\n * @dev Transfers tokens to the recipient if the contract has enough balance, or\n * records the debt if the transfer fails due to reasons unrelated to the contract's\n * balance (e.g. if the token forbids transfers to the recipient).\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n * @custom:error InsufficientBalance The contract doesn't have enough balance to transfer\n */\n function _transferOutOrTrackDebt(\n IERC20Upgradeable token,\n address to,\n uint256 amount\n ) internal {\n uint256 balance = token.balanceOf(address(this));\n if (balance < amount) {\n revert InsufficientBalance(address(token), address(this), amount, balance);\n }\n _transferOutOrTrackDebtSkippingBalanceCheck(token, to, amount);\n }\n\n /**\n * @dev Transfers tokens to the recipient, or records the debt if the transfer fails\n * due to any reason, including insufficient balance.\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n */\n function _transferOutOrTrackDebtSkippingBalanceCheck(\n IERC20Upgradeable token,\n address to,\n uint256 amount\n ) internal {\n // We can't use safeTransfer here because we can't try-catch internal calls\n bool success = _tryTransferOut(token, to, amount);\n if (!success) {\n tokenDebt[token][to] += amount;\n totalTokenDebt[token] += amount;\n emit TokenDebtAdded(address(token), to, amount);\n }\n }\n\n /**\n * @dev Either transfers tokens to the recepient or returns false. Supports tokens\n * thet revert or return false to indicate failure, and the non-compliant ones\n * that do not return any value.\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n * @return true if the transfer succeeded, false otherwise\n */\n function _tryTransferOut(\n IERC20Upgradeable token,\n address to,\n uint256 amount\n ) private returns (bool) {\n bytes memory callData = abi.encodeCall(token.transfer, (to, amount));\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(callData);\n return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n }\n}\n" + }, + "contracts/lib/validators.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n}\n" + }, + "contracts/MaxLoopsLimitHelper.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title MaxLoopsLimitHelper\n * @author Venus\n * @notice Abstract contract used to avoid collection with too many items that would generate gas errors and DoS.\n */\nabstract contract MaxLoopsLimitHelper {\n // Limit for the loops to avoid the DOS\n uint256 public maxLoopsLimit;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when max loops limit is set\n event MaxLoopsLimitUpdated(uint256 oldMaxLoopsLimit, uint256 newmaxLoopsLimit);\n\n /// @notice Thrown an error on maxLoopsLimit exceeds for any loop\n error MaxLoopsLimitExceeded(uint256 loopsLimit, uint256 requiredLoops);\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function _setMaxLoopsLimit(uint256 limit) internal {\n require(limit > maxLoopsLimit, \"Comptroller: Invalid maxLoopsLimit\");\n\n uint256 oldMaxLoopsLimit = maxLoopsLimit;\n maxLoopsLimit = limit;\n\n emit MaxLoopsLimitUpdated(oldMaxLoopsLimit, limit);\n }\n\n /**\n * @notice Compare the maxLoopsLimit with number of the times loop iterate\n * @param len Length of the loops iterate\n * @custom:error MaxLoopsLimitExceeded error is thrown when loops length exceeds maxLoopsLimit\n */\n function _ensureMaxLoops(uint256 len) internal view {\n if (len > maxLoopsLimit) {\n revert MaxLoopsLimitExceeded(maxLoopsLimit, len);\n }\n }\n}\n" + }, + "contracts/Pool/PoolRegistry.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { PoolRegistryInterface } from \"./PoolRegistryInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\n/**\n * @title PoolRegistry\n * @author Venus\n * @notice The Isolated Pools architecture centers around the `PoolRegistry` contract. The `PoolRegistry` maintains a directory of isolated lending\n * pools and can perform actions like creating and registering new pools, adding new markets to existing pools, setting and updating the pool's required\n * metadata, and providing the getter methods to get information on the pools.\n *\n * Isolated lending has three main components: PoolRegistry, pools, and markets. The PoolRegistry is responsible for managing pools.\n * It can create new pools, update pool metadata and manage markets within pools. PoolRegistry contains getter methods to get the details of\n * any existing pool like `getVTokenForAsset` and `getPoolsSupportedByAsset`. It also contains methods for updating pool metadata (`updatePoolMetadata`)\n * and setting pool name (`setPoolName`).\n *\n * The directory of pools is managed through two mappings: `_poolByComptroller` which is a hashmap with the comptroller address as the key and `VenusPool` as\n * the value and `_poolsByID` which is an array of comptroller addresses. Individual pools can be accessed by calling `getPoolByComptroller` with the pool's\n * comptroller address. `_poolsByID` is used to iterate through all of the pools.\n *\n * PoolRegistry also contains a map of asset addresses called `_supportedPools` that maps to an array of assets suppored by each pool. This array of pools by\n * asset is retrieved by calling `getPoolsSupportedByAsset`.\n *\n * PoolRegistry registers new isolated pools in the directory with the `createRegistryPool` method. Isolated pools are composed of independent markets with\n * specific assets and custom risk management configurations according to their markets.\n */\ncontract PoolRegistry is Ownable2StepUpgradeable, AccessControlledV8, PoolRegistryInterface {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n struct AddMarketInput {\n VToken vToken;\n uint256 collateralFactor;\n uint256 liquidationThreshold;\n uint256 initialSupply;\n address vTokenReceiver;\n uint256 supplyCap;\n uint256 borrowCap;\n }\n\n uint256 internal constant MAX_POOL_NAME_LENGTH = 100;\n\n /**\n * @notice Maps pool's comptroller address to metadata.\n */\n mapping(address => VenusPoolMetaData) public metadata;\n\n /**\n * @dev Maps pool ID to pool's comptroller address\n */\n mapping(uint256 => address) private _poolsByID;\n\n /**\n * @dev Total number of pools created.\n */\n uint256 private _numberOfPools;\n\n /**\n * @dev Maps comptroller address to Venus pool Index.\n */\n mapping(address => VenusPool) private _poolByComptroller;\n\n /**\n * @dev Maps pool's comptroller address to asset to vToken.\n */\n mapping(address => mapping(address => address)) private _vTokens;\n\n /**\n * @dev Maps asset to list of supported pools.\n */\n mapping(address => address[]) private _supportedPools;\n\n /**\n * @notice Emitted when a new Venus pool is added to the directory.\n */\n event PoolRegistered(address indexed comptroller, VenusPool pool);\n\n /**\n * @notice Emitted when a pool name is set.\n */\n event PoolNameSet(address indexed comptroller, string oldName, string newName);\n\n /**\n * @notice Emitted when a pool metadata is updated.\n */\n event PoolMetadataUpdated(\n address indexed comptroller,\n VenusPoolMetaData oldMetadata,\n VenusPoolMetaData newMetadata\n );\n\n /**\n * @notice Emitted when a Market is added to the pool.\n */\n event MarketAdded(address indexed comptroller, address indexed vTokenAddress);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner\n * @param accessControlManager_ AccessControlManager contract address\n */\n function initialize(address accessControlManager_) external initializer {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n /**\n * @notice Adds a new Venus pool to the directory\n * @dev Price oracle must be configured before adding a pool\n * @param name The name of the pool\n * @param comptroller Pool's Comptroller contract\n * @param closeFactor The pool's close factor (scaled by 1e18)\n * @param liquidationIncentive The pool's liquidation incentive (scaled by 1e18)\n * @param minLiquidatableCollateral Minimal collateral for regular (non-batch) liquidations flow\n * @return index The index of the registered Venus pool\n * @custom:error ZeroAddressNotAllowed is thrown when Comptroller address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when price oracle address is zero\n */\n function addPool(\n string calldata name,\n Comptroller comptroller,\n uint256 closeFactor,\n uint256 liquidationIncentive,\n uint256 minLiquidatableCollateral\n ) external virtual returns (uint256 index) {\n _checkAccessAllowed(\"addPool(string,address,uint256,uint256,uint256)\");\n // Input validation\n ensureNonzeroAddress(address(comptroller));\n ensureNonzeroAddress(address(comptroller.oracle()));\n\n uint256 poolId = _registerPool(name, address(comptroller));\n\n // Set Venus pool parameters\n comptroller.setCloseFactor(closeFactor);\n comptroller.setLiquidationIncentive(liquidationIncentive);\n comptroller.setMinLiquidatableCollateral(minLiquidatableCollateral);\n\n return poolId;\n }\n\n /**\n * @notice Add a market to an existing pool and then mint to provide initial supply\n * @param input The structure describing the parameters for adding a market to a pool\n * @custom:error ZeroAddressNotAllowed is thrown when vToken address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when vTokenReceiver address is zero\n */\n function addMarket(AddMarketInput memory input) external {\n _checkAccessAllowed(\"addMarket(AddMarketInput)\");\n ensureNonzeroAddress(address(input.vToken));\n ensureNonzeroAddress(input.vTokenReceiver);\n require(input.initialSupply > 0, \"PoolRegistry: initialSupply is zero\");\n\n VToken vToken = input.vToken;\n address vTokenAddress = address(vToken);\n address comptrollerAddress = address(vToken.comptroller());\n Comptroller comptroller = Comptroller(comptrollerAddress);\n address underlyingAddress = vToken.underlying();\n IERC20Upgradeable underlying = IERC20Upgradeable(underlyingAddress);\n\n require(_poolByComptroller[comptrollerAddress].creator != address(0), \"PoolRegistry: Pool not registered\");\n // solhint-disable-next-line reason-string\n require(\n _vTokens[comptrollerAddress][underlyingAddress] == address(0),\n \"PoolRegistry: Market already added for asset comptroller combination\"\n );\n\n comptroller.supportMarket(vToken);\n comptroller.setCollateralFactor(vToken, input.collateralFactor, input.liquidationThreshold);\n\n uint256[] memory newSupplyCaps = new uint256[](1);\n uint256[] memory newBorrowCaps = new uint256[](1);\n VToken[] memory vTokens = new VToken[](1);\n\n newSupplyCaps[0] = input.supplyCap;\n newBorrowCaps[0] = input.borrowCap;\n vTokens[0] = vToken;\n\n comptroller.setMarketSupplyCaps(vTokens, newSupplyCaps);\n comptroller.setMarketBorrowCaps(vTokens, newBorrowCaps);\n\n _vTokens[comptrollerAddress][underlyingAddress] = vTokenAddress;\n _supportedPools[underlyingAddress].push(comptrollerAddress);\n\n uint256 amountToSupply = _transferIn(underlying, msg.sender, input.initialSupply);\n underlying.approve(vTokenAddress, 0);\n underlying.approve(vTokenAddress, amountToSupply);\n vToken.mintBehalf(input.vTokenReceiver, amountToSupply);\n\n emit MarketAdded(comptrollerAddress, vTokenAddress);\n }\n\n /**\n * @notice Modify existing Venus pool name\n * @param comptroller Pool's Comptroller\n * @param name New pool name\n */\n function setPoolName(address comptroller, string calldata name) external {\n _checkAccessAllowed(\"setPoolName(address,string)\");\n _ensureValidName(name);\n VenusPool storage pool = _poolByComptroller[comptroller];\n string memory oldName = pool.name;\n pool.name = name;\n emit PoolNameSet(comptroller, oldName, name);\n }\n\n /**\n * @notice Update metadata of an existing pool\n * @param comptroller Pool's Comptroller\n * @param metadata_ New pool metadata\n */\n function updatePoolMetadata(address comptroller, VenusPoolMetaData calldata metadata_) external {\n _checkAccessAllowed(\"updatePoolMetadata(address,VenusPoolMetaData)\");\n VenusPoolMetaData memory oldMetadata = metadata[comptroller];\n metadata[comptroller] = metadata_;\n emit PoolMetadataUpdated(comptroller, oldMetadata, metadata_);\n }\n\n /**\n * @notice Returns arrays of all Venus pools' data\n * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n * @return A list of all pools within PoolRegistry, with details for each pool\n */\n function getAllPools() external view override returns (VenusPool[] memory) {\n uint256 numberOfPools_ = _numberOfPools; // storage load to save gas\n VenusPool[] memory _pools = new VenusPool[](numberOfPools_);\n for (uint256 i = 1; i <= numberOfPools_; ++i) {\n address comptroller = _poolsByID[i];\n _pools[i - 1] = (_poolByComptroller[comptroller]);\n }\n return _pools;\n }\n\n /**\n * @param comptroller The comptroller proxy address associated to the pool\n * @return Returns Venus pool\n */\n function getPoolByComptroller(address comptroller) external view override returns (VenusPool memory) {\n return _poolByComptroller[comptroller];\n }\n\n /**\n * @param comptroller comptroller of Venus pool\n * @return Returns Metadata of Venus pool\n */\n function getVenusPoolMetadata(address comptroller) external view override returns (VenusPoolMetaData memory) {\n return metadata[comptroller];\n }\n\n function getVTokenForAsset(address comptroller, address asset) external view override returns (address) {\n return _vTokens[comptroller][asset];\n }\n\n function getPoolsSupportedByAsset(address asset) external view override returns (address[] memory) {\n return _supportedPools[asset];\n }\n\n /**\n * @dev Adds a new Venus pool to the directory (without checking msg.sender).\n * @param name The name of the pool\n * @param comptroller The pool's Comptroller proxy contract address\n * @return The index of the registered Venus pool\n */\n function _registerPool(string calldata name, address comptroller) internal returns (uint256) {\n VenusPool storage storedPool = _poolByComptroller[comptroller];\n\n require(storedPool.creator == address(0), \"PoolRegistry: Pool already exists in the directory.\");\n _ensureValidName(name);\n\n ++_numberOfPools;\n uint256 numberOfPools_ = _numberOfPools; // cache on stack to save storage read gas\n\n VenusPool memory pool = VenusPool(name, msg.sender, comptroller, block.number, block.timestamp);\n\n _poolsByID[numberOfPools_] = comptroller;\n _poolByComptroller[comptroller] = pool;\n\n emit PoolRegistered(comptroller, pool);\n return numberOfPools_;\n }\n\n function _transferIn(\n IERC20Upgradeable token,\n address from,\n uint256 amount\n ) internal returns (uint256) {\n uint256 balanceBefore = token.balanceOf(address(this));\n token.safeTransferFrom(from, address(this), amount);\n uint256 balanceAfter = token.balanceOf(address(this));\n return balanceAfter - balanceBefore;\n }\n\n function _ensureValidName(string calldata name) internal pure {\n require(bytes(name).length <= MAX_POOL_NAME_LENGTH, \"Pool's name is too large\");\n }\n}\n" + }, + "contracts/Pool/PoolRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title PoolRegistryInterface\n * @author Venus\n * @notice Interface implemented by `PoolRegistry`.\n */\ninterface PoolRegistryInterface {\n /**\n * @notice Struct for a Venus interest rate pool.\n */\n struct VenusPool {\n string name;\n address creator;\n address comptroller;\n uint256 blockPosted;\n uint256 timestampPosted;\n }\n\n /**\n * @notice Struct for a Venus interest rate pool metadata.\n */\n struct VenusPoolMetaData {\n string category;\n string logoURL;\n string description;\n }\n\n /// @notice Get all pools in PoolRegistry\n function getAllPools() external view returns (VenusPool[] memory);\n\n /// @notice Get a pool by comptroller address\n function getPoolByComptroller(address comptroller) external view returns (VenusPool memory);\n\n /// @notice Get the address of the VToken contract in the Pool where the underlying token is the provided 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 /// @notice Get the metadata of a Pool by comptroller address\n function getVenusPoolMetadata(address comptroller) external view returns (VenusPoolMetaData memory);\n}\n" + }, + "contracts/Rewards/RewardsDistributor.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\n\n/**\n * @title `RewardsDistributor`\n * @author Venus\n * @notice Contract used to configure, track and distribute rewards to users based on their actions (borrows and supplies) in the protocol.\n * Users can receive additional rewards through a `RewardsDistributor`. Each `RewardsDistributor` proxy is initialized with a specific reward\n * token and `Comptroller`, which can then distribute the reward token to users that supply or borrow in the associated pool.\n * Authorized users can set the reward token borrow and supply speeds for each market in the pool. This sets a fixed amount of reward\n * token to be released each block for borrowers and suppliers, which is distributed based on a user’s percentage of the borrows or supplies\n * respectively. The owner can also set up reward distributions to contributor addresses (distinct from suppliers and borrowers) by setting\n * their contributor reward token speed, which similarly allocates a fixed amount of reward token per block.\n *\n * The owner has the ability to transfer any amount of reward tokens held by the contract to any other address. Rewards are not distributed\n * automatically and must be claimed by a user calling `claimRewardToken()`. Users should be aware that it is up to the owner and other centralized\n * entities to ensure that the `RewardsDistributor` holds enough tokens to distribute the accumulated rewards of users and contributors.\n */\ncontract RewardsDistributor is ExponentialNoError, Ownable2StepUpgradeable, AccessControlledV8, MaxLoopsLimitHelper {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n struct RewardToken {\n // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n uint224 index;\n // The block number the index was last updated at\n uint32 block;\n // The block number at which to stop rewards\n uint32 lastRewardingBlock;\n }\n\n /// @notice The initial REWARD TOKEN index for a market\n uint224 public constant INITIAL_INDEX = 1e36;\n\n /// @notice The REWARD TOKEN market supply state for each market\n mapping(address => RewardToken) public rewardTokenSupplyState;\n\n /// @notice The REWARD TOKEN borrow index for each market for each supplier as of the last time they accrued REWARD TOKEN\n mapping(address => mapping(address => uint256)) public rewardTokenSupplierIndex;\n\n /// @notice The REWARD TOKEN accrued but not yet transferred to each user\n mapping(address => uint256) public rewardTokenAccrued;\n\n /// @notice The rate at which rewardToken is distributed to the corresponding borrow market (per block)\n mapping(address => uint256) public rewardTokenBorrowSpeeds;\n\n /// @notice The rate at which rewardToken is distributed to the corresponding supply market (per block)\n mapping(address => uint256) public rewardTokenSupplySpeeds;\n\n /// @notice The REWARD TOKEN market borrow state for each market\n mapping(address => RewardToken) public rewardTokenBorrowState;\n\n /// @notice The portion of REWARD TOKEN that each contributor receives per block\n mapping(address => uint256) public rewardTokenContributorSpeeds;\n\n /// @notice Last block at which a contributor's REWARD TOKEN rewards have been allocated\n mapping(address => uint256) public lastContributorBlock;\n\n /// @notice The REWARD TOKEN borrow index for each market for each borrower as of the last time they accrued REWARD TOKEN\n mapping(address => mapping(address => uint256)) public rewardTokenBorrowerIndex;\n\n Comptroller private comptroller;\n\n IERC20Upgradeable public rewardToken;\n\n /// @notice Emitted when REWARD TOKEN is distributed to a supplier\n event DistributedSupplierRewardToken(\n VToken indexed vToken,\n address indexed supplier,\n uint256 rewardTokenDelta,\n uint256 rewardTokenTotal,\n uint256 rewardTokenSupplyIndex\n );\n\n /// @notice Emitted when REWARD TOKEN is distributed to a borrower\n event DistributedBorrowerRewardToken(\n VToken indexed vToken,\n address indexed borrower,\n uint256 rewardTokenDelta,\n uint256 rewardTokenTotal,\n uint256 rewardTokenBorrowIndex\n );\n\n /// @notice Emitted when a new supply-side REWARD TOKEN speed is calculated for a market\n event RewardTokenSupplySpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n /// @notice Emitted when a new borrow-side REWARD TOKEN speed is calculated for a market\n event RewardTokenBorrowSpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n /// @notice Emitted when REWARD TOKEN is granted by admin\n event RewardTokenGranted(address indexed recipient, uint256 amount);\n\n /// @notice Emitted when a new REWARD TOKEN speed is set for a contributor\n event ContributorRewardTokenSpeedUpdated(address indexed contributor, uint256 newSpeed);\n\n /// @notice Emitted when a market is initialized\n event MarketInitialized(address indexed vToken);\n\n /// @notice Emitted when a reward token supply index is updated\n event RewardTokenSupplyIndexUpdated(address indexed vToken);\n\n /// @notice Emitted when a reward token borrow index is updated\n event RewardTokenBorrowIndexUpdated(address indexed vToken, Exp marketBorrowIndex);\n\n /// @notice Emitted when a reward for contributor is updated\n event ContributorRewardsUpdated(address indexed contributor, uint256 rewardAccrued);\n\n /// @notice Emitted when a reward token last rewarding block for supply is updated\n event SupplyLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n /// @notice Emitted when a reward token last rewarding block for borrow is updated\n event BorrowLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n modifier onlyComptroller() {\n require(address(comptroller) == msg.sender, \"Only comptroller can call this function\");\n _;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice RewardsDistributor initializer\n * @dev Initializes the deployer to owner\n * @param comptroller_ Comptroller to attach the reward distributor to\n * @param rewardToken_ Reward token to distribute\n * @param loopsLimit_ Maximum number of iterations for the loops in this contract\n * @param accessControlManager_ AccessControlManager contract address\n */\n function initialize(\n Comptroller comptroller_,\n IERC20Upgradeable rewardToken_,\n uint256 loopsLimit_,\n address accessControlManager_\n ) external initializer {\n comptroller = comptroller_;\n rewardToken = rewardToken_;\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n\n _setMaxLoopsLimit(loopsLimit_);\n }\n\n function initializeMarket(address vToken) external onlyComptroller {\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n\n /*\n * Update market state indices\n */\n if (supplyState.index == 0) {\n // Initialize supply state index with default value\n supplyState.index = INITIAL_INDEX;\n }\n\n if (borrowState.index == 0) {\n // Initialize borrow state index with default value\n borrowState.index = INITIAL_INDEX;\n }\n\n /*\n * Update market state block numbers\n */\n supplyState.block = borrowState.block = blockNumber;\n\n emit MarketInitialized(vToken);\n }\n\n /*** Reward Token Distribution ***/\n\n /**\n * @notice Calculate reward token accrued by a borrower and possibly transfer it to them\n * Borrowers will begin to accrue after the first interaction with the protocol.\n * @dev This function should only be called when the user has a borrow position in the market\n * (e.g. Comptroller.preBorrowHook, and Comptroller.preRepayHook)\n * We avoid an external call to check if they are in the market to save gas because this function is called in many places\n * @param vToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute REWARD TOKEN to\n * @param marketBorrowIndex The current global borrow index of vToken\n */\n function distributeBorrowerRewardToken(\n address vToken,\n address borrower,\n Exp memory marketBorrowIndex\n ) external onlyComptroller {\n _distributeBorrowerRewardToken(vToken, borrower, marketBorrowIndex);\n }\n\n function updateRewardTokenSupplyIndex(address vToken) external onlyComptroller {\n _updateRewardTokenSupplyIndex(vToken);\n }\n\n /**\n * @notice Transfer REWARD TOKEN to the recipient\n * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all\n * @param recipient The address of the recipient to transfer REWARD TOKEN to\n * @param amount The amount of REWARD TOKEN to (possibly) transfer\n */\n function grantRewardToken(address recipient, uint256 amount) external onlyOwner {\n uint256 amountLeft = _grantRewardToken(recipient, amount);\n require(amountLeft == 0, \"insufficient rewardToken for grant\");\n emit RewardTokenGranted(recipient, amount);\n }\n\n function updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) external onlyComptroller {\n _updateRewardTokenBorrowIndex(vToken, marketBorrowIndex);\n }\n\n /**\n * @notice Set REWARD TOKEN borrow and supply speeds for the specified markets\n * @param vTokens The markets whose REWARD TOKEN speed to update\n * @param supplySpeeds New supply-side REWARD TOKEN speed for the corresponding market\n * @param borrowSpeeds New borrow-side REWARD TOKEN speed for the corresponding market\n */\n function setRewardTokenSpeeds(\n VToken[] memory vTokens,\n uint256[] memory supplySpeeds,\n uint256[] memory borrowSpeeds\n ) external {\n _checkAccessAllowed(\"setRewardTokenSpeeds(address[],uint256[],uint256[])\");\n uint256 numTokens = vTokens.length;\n require(numTokens == supplySpeeds.length && numTokens == borrowSpeeds.length, \"invalid setRewardTokenSpeeds\");\n\n for (uint256 i; i < numTokens; ++i) {\n _setRewardTokenSpeed(vTokens[i], supplySpeeds[i], borrowSpeeds[i]);\n }\n }\n\n /**\n * @notice Set REWARD TOKEN last rewarding block for the specified markets\n * @param vTokens The markets whose REWARD TOKEN last rewarding block to update\n * @param supplyLastRewardingBlocks New supply-side REWARD TOKEN last rewarding block for the corresponding market\n * @param borrowLastRewardingBlocks New borrow-side REWARD TOKEN last rewarding block for the corresponding market\n */\n function setLastRewardingBlocks(\n VToken[] calldata vTokens,\n uint32[] calldata supplyLastRewardingBlocks,\n uint32[] calldata borrowLastRewardingBlocks\n ) external {\n _checkAccessAllowed(\"setLastRewardingBlock(address[],uint32[],uint32[])\");\n uint256 numTokens = vTokens.length;\n require(\n numTokens == supplyLastRewardingBlocks.length && numTokens == borrowLastRewardingBlocks.length,\n \"RewardsDistributor::setLastRewardingBlocks invalid input\"\n );\n\n for (uint256 i; i < numTokens; ) {\n _setLastRewardingBlock(vTokens[i], supplyLastRewardingBlocks[i], borrowLastRewardingBlocks[i]);\n unchecked {\n ++i;\n }\n }\n }\n\n /**\n * @notice Set REWARD TOKEN speed for a single contributor\n * @param contributor The contributor whose REWARD TOKEN speed to update\n * @param rewardTokenSpeed New REWARD TOKEN speed for contributor\n */\n function setContributorRewardTokenSpeed(address contributor, uint256 rewardTokenSpeed) external onlyOwner {\n // note that REWARD TOKEN speed could be set to 0 to halt liquidity rewards for a contributor\n updateContributorRewards(contributor);\n if (rewardTokenSpeed == 0) {\n // release storage\n delete lastContributorBlock[contributor];\n } else {\n lastContributorBlock[contributor] = getBlockNumber();\n }\n rewardTokenContributorSpeeds[contributor] = rewardTokenSpeed;\n\n emit ContributorRewardTokenSpeedUpdated(contributor, rewardTokenSpeed);\n }\n\n function distributeSupplierRewardToken(address vToken, address supplier) external onlyComptroller {\n _distributeSupplierRewardToken(vToken, supplier);\n }\n\n /**\n * @notice Claim all the rewardToken accrued by holder in all markets\n * @param holder The address to claim REWARD TOKEN for\n */\n function claimRewardToken(address holder) external {\n return claimRewardToken(holder, comptroller.getAllMarkets());\n }\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Calculate additional accrued REWARD TOKEN for a contributor since last accrual\n * @param contributor The address to calculate contributor rewards for\n */\n function updateContributorRewards(address contributor) public {\n uint256 rewardTokenSpeed = rewardTokenContributorSpeeds[contributor];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, lastContributorBlock[contributor]);\n if (deltaBlocks > 0 && rewardTokenSpeed > 0) {\n uint256 newAccrued = mul_(deltaBlocks, rewardTokenSpeed);\n uint256 contributorAccrued = add_(rewardTokenAccrued[contributor], newAccrued);\n\n rewardTokenAccrued[contributor] = contributorAccrued;\n lastContributorBlock[contributor] = blockNumber;\n\n emit ContributorRewardsUpdated(contributor, rewardTokenAccrued[contributor]);\n }\n }\n\n /**\n * @notice Claim all the rewardToken accrued by holder in the specified markets\n * @param holder The address to claim REWARD TOKEN for\n * @param vTokens The list of markets to claim REWARD TOKEN in\n */\n function claimRewardToken(address holder, VToken[] memory vTokens) public {\n uint256 vTokensCount = vTokens.length;\n\n _ensureMaxLoops(vTokensCount);\n\n for (uint256 i; i < vTokensCount; ++i) {\n VToken vToken = vTokens[i];\n require(comptroller.isMarketListed(vToken), \"market must be listed\");\n Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n _distributeBorrowerRewardToken(address(vToken), holder, borrowIndex);\n _updateRewardTokenSupplyIndex(address(vToken));\n _distributeSupplierRewardToken(address(vToken), holder);\n }\n rewardTokenAccrued[holder] = _grantRewardToken(holder, rewardTokenAccrued[holder]);\n }\n\n function getBlockNumber() public view virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Set REWARD TOKEN last rewarding block for a single market.\n * @param vToken market's whose reward token last rewarding block to be updated\n * @param supplyLastRewardingBlock New supply-side REWARD TOKEN last rewarding block for market\n * @param borrowLastRewardingBlock New borrow-side REWARD TOKEN last rewarding block for market\n */\n function _setLastRewardingBlock(\n VToken vToken,\n uint32 supplyLastRewardingBlock,\n uint32 borrowLastRewardingBlock\n ) internal {\n require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n uint256 blockNumber = getBlockNumber();\n\n require(supplyLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n require(borrowLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n\n uint32 currentSupplyLastRewardingBlock = rewardTokenSupplyState[address(vToken)].lastRewardingBlock;\n uint32 currentBorrowLastRewardingBlock = rewardTokenBorrowState[address(vToken)].lastRewardingBlock;\n\n require(\n currentSupplyLastRewardingBlock == 0 || currentSupplyLastRewardingBlock > blockNumber,\n \"this RewardsDistributor is already locked\"\n );\n require(\n currentBorrowLastRewardingBlock == 0 || currentBorrowLastRewardingBlock > blockNumber,\n \"this RewardsDistributor is already locked\"\n );\n\n if (currentSupplyLastRewardingBlock != supplyLastRewardingBlock) {\n rewardTokenSupplyState[address(vToken)].lastRewardingBlock = supplyLastRewardingBlock;\n emit SupplyLastRewardingBlockUpdated(address(vToken), supplyLastRewardingBlock);\n }\n\n if (currentBorrowLastRewardingBlock != borrowLastRewardingBlock) {\n rewardTokenBorrowState[address(vToken)].lastRewardingBlock = borrowLastRewardingBlock;\n emit BorrowLastRewardingBlockUpdated(address(vToken), borrowLastRewardingBlock);\n }\n }\n\n /**\n * @notice Set REWARD TOKEN speed for a single market.\n * @param vToken market's whose reward token rate to be updated\n * @param supplySpeed New supply-side REWARD TOKEN speed for market\n * @param borrowSpeed New borrow-side REWARD TOKEN speed for market\n */\n function _setRewardTokenSpeed(\n VToken vToken,\n uint256 supplySpeed,\n uint256 borrowSpeed\n ) internal {\n require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n if (rewardTokenSupplySpeeds[address(vToken)] != supplySpeed) {\n // Supply speed updated so let's update supply state to ensure that\n // 1. REWARD TOKEN accrued properly for the old speed, and\n // 2. REWARD TOKEN accrued at the new speed starts after this block.\n _updateRewardTokenSupplyIndex(address(vToken));\n\n // Update speed and emit event\n rewardTokenSupplySpeeds[address(vToken)] = supplySpeed;\n emit RewardTokenSupplySpeedUpdated(vToken, supplySpeed);\n }\n\n if (rewardTokenBorrowSpeeds[address(vToken)] != borrowSpeed) {\n // Borrow speed updated so let's update borrow state to ensure that\n // 1. REWARD TOKEN accrued properly for the old speed, and\n // 2. REWARD TOKEN accrued at the new speed starts after this block.\n Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n\n // Update speed and emit event\n rewardTokenBorrowSpeeds[address(vToken)] = borrowSpeed;\n emit RewardTokenBorrowSpeedUpdated(vToken, borrowSpeed);\n }\n }\n\n /**\n * @notice Calculate REWARD TOKEN accrued by a supplier and possibly transfer it to them.\n * @param vToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute REWARD TOKEN to\n */\n function _distributeSupplierRewardToken(address vToken, address supplier) internal {\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n uint256 supplyIndex = supplyState.index;\n uint256 supplierIndex = rewardTokenSupplierIndex[vToken][supplier];\n\n // Update supplier's index to the current index since we are distributing accrued REWARD TOKEN\n rewardTokenSupplierIndex[vToken][supplier] = supplyIndex;\n\n if (supplierIndex == 0 && supplyIndex >= INITIAL_INDEX) {\n // Covers the case where users supplied tokens before the market's supply state index was set.\n // Rewards the user with REWARD TOKEN accrued from the start of when supplier rewards were first\n // set for the market.\n supplierIndex = INITIAL_INDEX;\n }\n\n // Calculate change in the cumulative sum of the REWARD TOKEN per vToken accrued\n Double memory deltaIndex = Double({ mantissa: sub_(supplyIndex, supplierIndex) });\n\n uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n\n // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerVToken\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n\n uint256 supplierAccrued = add_(rewardTokenAccrued[supplier], supplierDelta);\n rewardTokenAccrued[supplier] = supplierAccrued;\n\n emit DistributedSupplierRewardToken(VToken(vToken), supplier, supplierDelta, supplierAccrued, supplyIndex);\n }\n\n /**\n * @notice Calculate reward token accrued by a borrower and possibly transfer it to them.\n * @param vToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute REWARD TOKEN to\n * @param marketBorrowIndex The current global borrow index of vToken\n */\n function _distributeBorrowerRewardToken(\n address vToken,\n address borrower,\n Exp memory marketBorrowIndex\n ) internal {\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n uint256 borrowIndex = borrowState.index;\n uint256 borrowerIndex = rewardTokenBorrowerIndex[vToken][borrower];\n\n // Update borrowers's index to the current index since we are distributing accrued REWARD TOKEN\n rewardTokenBorrowerIndex[vToken][borrower] = borrowIndex;\n\n if (borrowerIndex == 0 && borrowIndex >= INITIAL_INDEX) {\n // Covers the case where users borrowed tokens before the market's borrow state index was set.\n // Rewards the user with REWARD TOKEN accrued from the start of when borrower rewards were first\n // set for the market.\n borrowerIndex = INITIAL_INDEX;\n }\n\n // Calculate change in the cumulative sum of the REWARD TOKEN per borrowed unit accrued\n Double memory deltaIndex = Double({ mantissa: sub_(borrowIndex, borrowerIndex) });\n\n uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n\n // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerBorrowedUnit\n if (borrowerAmount != 0) {\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n\n uint256 borrowerAccrued = add_(rewardTokenAccrued[borrower], borrowerDelta);\n rewardTokenAccrued[borrower] = borrowerAccrued;\n\n emit DistributedBorrowerRewardToken(VToken(vToken), borrower, borrowerDelta, borrowerAccrued, borrowIndex);\n }\n }\n\n /**\n * @notice Transfer REWARD TOKEN to the user.\n * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all.\n * @param user The address of the user to transfer REWARD TOKEN to\n * @param amount The amount of REWARD TOKEN to (possibly) transfer\n * @return The amount of REWARD TOKEN which was NOT transferred to the user\n */\n function _grantRewardToken(address user, uint256 amount) internal returns (uint256) {\n uint256 rewardTokenRemaining = rewardToken.balanceOf(address(this));\n if (amount > 0 && amount <= rewardTokenRemaining) {\n rewardToken.safeTransfer(user, amount);\n return 0;\n }\n return amount;\n }\n\n /**\n * @notice Accrue REWARD TOKEN to the market by updating the supply index\n * @param vToken The market whose supply index to update\n * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n */\n function _updateRewardTokenSupplyIndex(address vToken) internal {\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n uint256 supplySpeed = rewardTokenSupplySpeeds[vToken];\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n blockNumber = supplyState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(uint256(blockNumber), uint256(supplyState.block));\n\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = VToken(vToken).totalSupply();\n uint256 accruedSinceUpdate = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(accruedSinceUpdate, supplyTokens)\n : Double({ mantissa: 0 });\n supplyState.index = safe224(\n add_(Double({ mantissa: supplyState.index }), ratio).mantissa,\n \"new index exceeds 224 bits\"\n );\n supplyState.block = blockNumber;\n } else if (deltaBlocks > 0) {\n supplyState.block = blockNumber;\n }\n\n emit RewardTokenSupplyIndexUpdated(vToken);\n }\n\n /**\n * @notice Accrue REWARD TOKEN to the market by updating the borrow index\n * @param vToken The market whose borrow index to update\n * @param marketBorrowIndex The current global borrow index of vToken\n * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n */\n function _updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) internal {\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n uint256 borrowSpeed = rewardTokenBorrowSpeeds[vToken];\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n blockNumber = borrowState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(uint256(blockNumber), uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n uint256 accruedSinceUpdate = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(accruedSinceUpdate, borrowAmount)\n : Double({ mantissa: 0 });\n borrowState.index = safe224(\n add_(Double({ mantissa: borrowState.index }), ratio).mantissa,\n \"new index exceeds 224 bits\"\n );\n borrowState.block = blockNumber;\n } else if (deltaBlocks > 0) {\n borrowState.block = blockNumber;\n }\n\n emit RewardTokenBorrowIndexUpdated(vToken, marketBorrowIndex);\n }\n}\n" + }, + "contracts/RiskFund/IProtocolShareReserve.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IProtocolShareReserve\n * @author Venus\n * @notice Interface implemented by `ProtocolShareReserve`.\n */\ninterface IProtocolShareReserve {\n function updateAssetsState(address comptroller, address asset) external;\n}\n" + }, + "contracts/RiskFund/IRiskFund.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IRiskFund\n * @author Venus\n * @notice Interface implemented by `RiskFund`.\n */\ninterface IRiskFund {\n function swapPoolsAssets(\n address[] calldata markets,\n uint256[] calldata amountsOutMin,\n address[][] calldata paths,\n uint256 deadline\n ) external returns (uint256);\n\n function transferReserveForAuction(address comptroller, uint256 amount) external returns (uint256);\n\n function updateAssetsState(address comptroller, address asset) external;\n\n function convertibleBaseAsset() external view returns (address);\n\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256);\n}\n" + }, + "contracts/RiskFund/ProtocolShareReserve.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { IProtocolShareReserve } from \"./IProtocolShareReserve.sol\";\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\ncontract ProtocolShareReserve is ExponentialNoError, ReserveHelpers, IProtocolShareReserve {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n address public protocolIncome;\n address public riskFund;\n // Percentage of funds not sent to the RiskFund contract when the funds are released, following the project Tokenomics\n uint256 private constant PROTOCOL_SHARE_PERCENTAGE = 50;\n uint256 private constant BASE_UNIT = 100;\n\n /// @notice Emitted when funds are released\n event FundsReleased(address indexed comptroller, address indexed asset, uint256 amount);\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner.\n * @param protocolIncome_ The address protocol income will be sent to\n * @param riskFund_ Risk fund address\n * @custom:error ZeroAddressNotAllowed is thrown when protocol income address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n */\n function initialize(address protocolIncome_, address riskFund_) external initializer {\n ensureNonzeroAddress(protocolIncome_);\n ensureNonzeroAddress(riskFund_);\n\n __Ownable2Step_init();\n\n protocolIncome = protocolIncome_;\n riskFund = riskFund_;\n }\n\n /**\n * @notice Pool registry setter.\n * @param poolRegistry_ Address of the pool registry\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function setPoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Release funds\n * @param comptroller Pool's Comptroller\n * @param asset Asset to be released\n * @param amount Amount to release\n * @return Number of total released tokens\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function releaseFunds(\n address comptroller,\n address asset,\n uint256 amount\n ) external nonReentrant returns (uint256) {\n ensureNonzeroAddress(asset);\n require(amount <= _poolsAssetsReserves[comptroller][asset], \"ProtocolShareReserve: Insufficient pool balance\");\n\n assetsReserves[asset] -= amount;\n _poolsAssetsReserves[comptroller][asset] -= amount;\n uint256 protocolIncomeAmount = mul_(\n Exp({ mantissa: amount }),\n div_(Exp({ mantissa: PROTOCOL_SHARE_PERCENTAGE * EXP_SCALE }), BASE_UNIT)\n ).mantissa;\n\n address riskFund_ = riskFund;\n\n emit FundsReleased(comptroller, asset, amount);\n\n IERC20Upgradeable(asset).safeTransfer(protocolIncome, protocolIncomeAmount);\n IERC20Upgradeable(asset).safeTransfer(riskFund_, amount - protocolIncomeAmount);\n\n // Update the pool asset's state in the risk fund for the above transfer.\n IRiskFund(riskFund_).updateAssetsState(comptroller, asset);\n\n return amount;\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to the protocol share reserve.\n * @param comptroller Comptroller address(pool)\n * @param asset Asset address.\n */\n function updateAssetsState(address comptroller, address asset)\n public\n override(IProtocolShareReserve, ReserveHelpers)\n {\n super.updateAssetsState(comptroller, asset);\n }\n}\n" + }, + "contracts/RiskFund/ReserveHelpers.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\n\ncontract ReserveHelpers is Ownable2StepUpgradeable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n uint256 private constant NOT_ENTERED = 1;\n\n uint256 private constant ENTERED = 2;\n\n // Store the previous state for the asset transferred to ProtocolShareReserve combined(for all pools).\n mapping(address => uint256) public assetsReserves;\n\n // Store the asset's reserve per pool in the ProtocolShareReserve.\n // Comptroller(pool) -> Asset -> amount\n mapping(address => mapping(address => uint256)) internal _poolsAssetsReserves;\n\n // Address of pool registry contract\n address public poolRegistry;\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n uint256 internal status;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n */\n uint256[46] private __gap;\n\n /// @notice Event emitted after the update of the assets reserves.\n /// @param comptroller Pool's Comptroller address\n /// @param asset Token address\n /// @param amount An amount by which the reserves have increased\n event AssetsReservesUpdated(address indexed comptroller, address indexed asset, uint256 amount);\n\n /// @notice event emitted on sweep token success\n event SweepToken(address indexed token, address indexed to, uint256 amount);\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(status != ENTERED, \"re-entered\");\n status = ENTERED;\n _;\n status = NOT_ENTERED;\n }\n\n /**\n * @notice A public function to sweep accidental BEP-20 transfers to this contract. Tokens are sent to the address `to`, provided in input\n * @param _token The address of the BEP-20 token to sweep\n * @param _to Recipient of the output tokens.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n * @custom:access Only Owner\n */\n function sweepToken(address _token, address _to) external onlyOwner nonReentrant {\n ensureNonzeroAddress(_to);\n uint256 balanceDfference_;\n uint256 balance_ = IERC20Upgradeable(_token).balanceOf(address(this));\n\n require(balance_ > assetsReserves[_token], \"ReserveHelpers: Zero surplus tokens\");\n unchecked {\n balanceDfference_ = balance_ - assetsReserves[_token];\n }\n\n emit SweepToken(_token, _to, balanceDfference_);\n IERC20Upgradeable(_token).safeTransfer(_to, balanceDfference_);\n }\n\n /**\n * @notice Get the Amount of the asset in the risk fund for the specific pool.\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n * @return Asset's reserve in risk fund.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function getPoolAssetReserve(address comptroller, address asset) external view returns (uint256) {\n ensureNonzeroAddress(asset);\n require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n return _poolsAssetsReserves[comptroller][asset];\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to risk fund\n * and transferring funds to the protocol share reserve\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function updateAssetsState(address comptroller, address asset) public virtual {\n ensureNonzeroAddress(asset);\n require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n address poolRegistry_ = poolRegistry;\n require(poolRegistry_ != address(0), \"ReserveHelpers: Pool Registry address is not set\");\n require(\n PoolRegistryInterface(poolRegistry_).getVTokenForAsset(comptroller, asset) != address(0),\n \"ReserveHelpers: The pool doesn't support the asset\"\n );\n\n uint256 currentBalance = IERC20Upgradeable(asset).balanceOf(address(this));\n uint256 assetReserve = assetsReserves[asset];\n if (currentBalance > assetReserve) {\n uint256 balanceDifference;\n unchecked {\n balanceDifference = currentBalance - assetReserve;\n }\n assetsReserves[asset] += balanceDifference;\n _poolsAssetsReserves[comptroller][asset] += balanceDifference;\n emit AssetsReservesUpdated(comptroller, asset, balanceDifference);\n }\n }\n}\n" + }, + "contracts/RiskFund/RiskFund.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { IPancakeswapV2Router } from \"../IPancakeswapV2Router.sol\";\nimport { IShortfall } from \"../Shortfall/IShortfall.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { ApproveOrRevert } from \"../lib/ApproveOrRevert.sol\";\n\n/**\n * @title RiskFund\n * @author Venus\n * @notice Contract with basic features to track/hold different assets for different Comptrollers.\n * @dev This contract does not support BNB.\n */\ncontract RiskFund is AccessControlledV8, ExponentialNoError, ReserveHelpers, MaxLoopsLimitHelper, IRiskFund {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using ApproveOrRevert for IERC20Upgradeable;\n\n address public convertibleBaseAsset;\n address public shortfall;\n address public pancakeSwapRouter;\n uint256 public minAmountToConvert;\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @notice Emitted when shortfall contract address is updated\n event ShortfallContractUpdated(address indexed oldShortfallContract, address indexed newShortfallContract);\n\n /// @notice Emitted when PancakeSwap router contract address is updated\n event PancakeSwapRouterUpdated(address indexed oldPancakeSwapRouter, address indexed newPancakeSwapRouter);\n\n /// @notice Emitted when minimum amount to convert is updated\n event MinAmountToConvertUpdated(uint256 oldMinAmountToConvert, uint256 newMinAmountToConvert);\n\n /// @notice Emitted when pools assets are swapped\n event SwappedPoolsAssets(address[] markets, uint256[] amountsOutMin, uint256 totalAmount);\n\n /// @notice Emitted when reserves are transferred for auction\n event TransferredReserveForAuction(address indexed comptroller, uint256 amount);\n\n /// @dev Note that the contract is upgradeable. Use initialize() or reinitializers\n /// to set the state variables.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner.\n * @param pancakeSwapRouter_ Address of the PancakeSwap router\n * @param minAmountToConvert_ Minimum amount assets must be worth to convert into base asset\n * @param convertibleBaseAsset_ Address of the base asset\n * @param accessControlManager_ Address of the access control contract\n * @param loopsLimit_ Limit for the loops in the contract to avoid DOS\n * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n */\n function initialize(\n address pancakeSwapRouter_,\n uint256 minAmountToConvert_,\n address convertibleBaseAsset_,\n address accessControlManager_,\n uint256 loopsLimit_\n ) external initializer {\n ensureNonzeroAddress(pancakeSwapRouter_);\n ensureNonzeroAddress(convertibleBaseAsset_);\n require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n require(loopsLimit_ > 0, \"Risk Fund: Loops limit can not be zero\");\n\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n\n pancakeSwapRouter = pancakeSwapRouter_;\n minAmountToConvert = minAmountToConvert_;\n convertibleBaseAsset = convertibleBaseAsset_;\n\n _setMaxLoopsLimit(loopsLimit_);\n }\n\n /**\n * @notice Pool registry setter\n * @param poolRegistry_ Address of the pool registry\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function setPoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Shortfall contract address setter\n * @param shortfallContractAddress_ Address of the auction contract\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n */\n function setShortfallContractAddress(address shortfallContractAddress_) external onlyOwner {\n ensureNonzeroAddress(shortfallContractAddress_);\n require(\n IShortfall(shortfallContractAddress_).convertibleBaseAsset() == convertibleBaseAsset,\n \"Risk Fund: Base asset doesn't match\"\n );\n\n address oldShortfallContractAddress = shortfall;\n shortfall = shortfallContractAddress_;\n emit ShortfallContractUpdated(oldShortfallContractAddress, shortfallContractAddress_);\n }\n\n /**\n * @notice PancakeSwap router address setter\n * @param pancakeSwapRouter_ Address of the PancakeSwap router\n * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n */\n function setPancakeSwapRouter(address pancakeSwapRouter_) external onlyOwner {\n ensureNonzeroAddress(pancakeSwapRouter_);\n address oldPancakeSwapRouter = pancakeSwapRouter;\n pancakeSwapRouter = pancakeSwapRouter_;\n emit PancakeSwapRouterUpdated(oldPancakeSwapRouter, pancakeSwapRouter_);\n }\n\n /**\n * @notice Min amount to convert setter\n * @param minAmountToConvert_ Min amount to convert.\n */\n function setMinAmountToConvert(uint256 minAmountToConvert_) external {\n _checkAccessAllowed(\"setMinAmountToConvert(uint256)\");\n require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n uint256 oldMinAmountToConvert = minAmountToConvert;\n minAmountToConvert = minAmountToConvert_;\n emit MinAmountToConvertUpdated(oldMinAmountToConvert, minAmountToConvert_);\n }\n\n /**\n * @notice Swap array of pool assets into base asset's tokens of at least a minimum amount\n * @param markets Array of vTokens whose assets to swap for base asset\n * @param amountsOutMin Minimum amount to receive for swap\n * @param paths A path consisting of PCS token pairs for each swap\n * @param deadline Deadline for the swap\n * @return Number of swapped tokens\n * @custom:error ZeroAddressNotAllowed is thrown if PoolRegistry contract address is not configured\n */\n function swapPoolsAssets(\n address[] calldata markets,\n uint256[] calldata amountsOutMin,\n address[][] calldata paths,\n uint256 deadline\n ) external override nonReentrant returns (uint256) {\n _checkAccessAllowed(\"swapPoolsAssets(address[],uint256[],address[][],uint256)\");\n require(deadline >= block.timestamp, \"Risk fund: deadline passed\");\n address poolRegistry_ = poolRegistry;\n ensureNonzeroAddress(poolRegistry_);\n require(markets.length == amountsOutMin.length, \"Risk fund: markets and amountsOutMin are unequal lengths\");\n require(markets.length == paths.length, \"Risk fund: markets and paths are unequal lengths\");\n\n uint256 totalAmount;\n uint256 marketsCount = markets.length;\n\n _ensureMaxLoops(marketsCount);\n\n for (uint256 i; i < marketsCount; ++i) {\n address comptroller = address(VToken(markets[i]).comptroller());\n\n PoolRegistry.VenusPool memory pool = PoolRegistry(poolRegistry_).getPoolByComptroller(comptroller);\n require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n require(Comptroller(comptroller).isMarketListed(VToken(markets[i])), \"market is not listed\");\n\n uint256 swappedTokens = _swapAsset(VToken(markets[i]), comptroller, amountsOutMin[i], paths[i]);\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] += swappedTokens;\n assetsReserves[convertibleBaseAsset] += swappedTokens;\n totalAmount = totalAmount + swappedTokens;\n }\n\n emit SwappedPoolsAssets(markets, amountsOutMin, totalAmount);\n\n return totalAmount;\n }\n\n /**\n * @notice Transfer tokens for auction.\n * @param comptroller Comptroller of the pool.\n * @param amount Amount to be transferred to auction contract.\n * @return Number reserved tokens.\n */\n function transferReserveForAuction(address comptroller, uint256 amount)\n external\n override\n nonReentrant\n returns (uint256)\n {\n address shortfall_ = shortfall;\n require(msg.sender == shortfall_, \"Risk fund: Only callable by Shortfall contract\");\n require(\n amount <= _poolsAssetsReserves[comptroller][convertibleBaseAsset],\n \"Risk Fund: Insufficient pool reserve.\"\n );\n unchecked {\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] =\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] -\n amount;\n }\n unchecked {\n assetsReserves[convertibleBaseAsset] = assetsReserves[convertibleBaseAsset] - amount;\n }\n\n emit TransferredReserveForAuction(comptroller, amount);\n IERC20Upgradeable(convertibleBaseAsset).safeTransfer(shortfall_, amount);\n\n return amount;\n }\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Get the Amount of the Base asset in the risk fund for the specific pool.\n * @param comptroller Comptroller address(pool).\n * @return Base Asset's reserve in risk fund.\n */\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256) {\n require(ComptrollerInterface(comptroller).isComptroller(), \"Risk Fund: Comptroller address invalid\");\n return _poolsAssetsReserves[comptroller][convertibleBaseAsset];\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to risk fund.\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n */\n function updateAssetsState(address comptroller, address asset) public override(IRiskFund, ReserveHelpers) {\n super.updateAssetsState(comptroller, asset);\n }\n\n /**\n * @dev Swap single asset to base asset.\n * @param vToken VToken\n * @param comptroller Comptroller address\n * @param amountOutMin Minimum amount to receive for swap\n * @param path A path for the swap consisting of PCS token pairs\n * @return Number of swapped tokens.\n */\n function _swapAsset(\n VToken vToken,\n address comptroller,\n uint256 amountOutMin,\n address[] calldata path\n ) internal returns (uint256) {\n require(amountOutMin != 0, \"RiskFund: amountOutMin must be greater than 0 to swap vToken\");\n uint256 totalAmount;\n\n address underlyingAsset = vToken.underlying();\n address convertibleBaseAsset_ = convertibleBaseAsset;\n uint256 balanceOfUnderlyingAsset = _poolsAssetsReserves[comptroller][underlyingAsset];\n\n if (balanceOfUnderlyingAsset == 0) {\n return 0;\n }\n\n ResilientOracleInterface oracle = ComptrollerViewInterface(comptroller).oracle();\n oracle.updateAssetPrice(convertibleBaseAsset_);\n Exp memory baseAssetPrice = Exp({ mantissa: oracle.getPrice(convertibleBaseAsset_) });\n uint256 amountOutMinInUsd = mul_ScalarTruncate(baseAssetPrice, amountOutMin);\n\n require(amountOutMinInUsd >= minAmountToConvert, \"RiskFund: minAmountToConvert violated\");\n\n assetsReserves[underlyingAsset] -= balanceOfUnderlyingAsset;\n _poolsAssetsReserves[comptroller][underlyingAsset] -= balanceOfUnderlyingAsset;\n\n if (underlyingAsset != convertibleBaseAsset_) {\n require(path[0] == underlyingAsset, \"RiskFund: swap path must start with the underlying asset\");\n require(\n path[path.length - 1] == convertibleBaseAsset_,\n \"RiskFund: finally path must be convertible base asset\"\n );\n address pancakeSwapRouter_ = pancakeSwapRouter;\n IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, 0);\n IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, balanceOfUnderlyingAsset);\n uint256[] memory amounts = IPancakeswapV2Router(pancakeSwapRouter_).swapExactTokensForTokens(\n balanceOfUnderlyingAsset,\n amountOutMin,\n path,\n address(this),\n block.timestamp\n );\n totalAmount = amounts[path.length - 1];\n } else {\n totalAmount = balanceOfUnderlyingAsset;\n }\n\n return totalAmount;\n }\n}\n" + }, + "contracts/Shortfall/IShortfall.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IShortfall\n * @author Venus\n * @notice Interface implemented by `Shortfall`.\n */\ninterface IShortfall {\n function convertibleBaseAsset() external returns (address);\n}\n" + }, + "contracts/Shortfall/Shortfall.sol": { + "content": "/// @notice SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"../RiskFund/IRiskFund.sol\";\nimport { IShortfall } from \"./IShortfall.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { TokenDebtTracker } from \"../lib/TokenDebtTracker.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { EXP_SCALE } from \"../lib/constants.sol\";\n\n/**\n * @title Shortfall\n * @author Venus\n * @notice Shortfall is an auction contract designed to auction off the `convertibleBaseAsset` accumulated in `RiskFund`. The `convertibleBaseAsset`\n * is auctioned in exchange for users paying off the pool's bad debt. An auction can be started by anyone once a pool's bad debt has reached a minimum value.\n * This value is set and can be changed by the authorized accounts. If the pool’s bad debt exceeds the risk fund plus a 10% incentive, then the auction winner\n * is determined by who will pay off the largest percentage of the pool's bad debt. The auction winner then exchanges for the entire risk fund. Otherwise,\n * if the risk fund covers the pool's bad debt plus the 10% incentive, then the auction winner is determined by who will take the smallest percentage of the\n * risk fund in exchange for paying off all the pool's bad debt.\n */\ncontract Shortfall is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n ReentrancyGuardUpgradeable,\n TokenDebtTracker,\n IShortfall\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /// @notice Type of auction\n enum AuctionType {\n LARGE_POOL_DEBT,\n LARGE_RISK_FUND\n }\n\n /// @notice Status of auction\n enum AuctionStatus {\n NOT_STARTED,\n STARTED,\n ENDED\n }\n\n /// @notice Auction metadata\n struct Auction {\n uint256 startBlock;\n AuctionType auctionType;\n AuctionStatus status;\n VToken[] markets;\n uint256 seizedRiskFund;\n address highestBidder;\n uint256 highestBidBps;\n uint256 highestBidBlock;\n uint256 startBidBps;\n mapping(VToken => uint256) marketDebt;\n mapping(VToken => uint256) bidAmount;\n }\n\n /// @dev Max basis points i.e., 100%\n uint256 private constant MAX_BPS = 10000;\n\n uint256 private constant DEFAULT_NEXT_BIDDER_BLOCK_LIMIT = 100;\n\n uint256 private constant DEFAULT_WAIT_FOR_FIRST_BIDDER = 100;\n\n uint256 private constant DEFAULT_INCENTIVE_BPS = 1000; // 10%\n\n /// @notice Pool registry address\n address public poolRegistry;\n\n /// @notice Risk fund address\n IRiskFund public riskFund;\n\n /// @notice Minimum USD debt in pool for shortfall to trigger\n uint256 public minimumPoolBadDebt;\n\n /// @notice Incentive to auction participants, initial value set to 1000 or 10%\n uint256 public incentiveBps;\n\n /// @notice Time to wait for next bidder. Initially waits for 100 blocks\n uint256 public nextBidderBlockLimit;\n\n /// @notice Boolean of if auctions are paused\n bool public auctionsPaused;\n\n /// @notice Time to wait for first bidder. Initially waits for 100 blocks\n uint256 public waitForFirstBidder;\n\n /// @notice base asset contract address\n address public convertibleBaseAsset;\n\n /// @notice Auctions for each pool\n mapping(address => Auction) public auctions;\n\n /// @notice Emitted when a auction starts\n event AuctionStarted(\n address indexed comptroller,\n uint256 auctionStartBlock,\n AuctionType auctionType,\n VToken[] markets,\n uint256[] marketsDebt,\n uint256 seizedRiskFund,\n uint256 startBidBps\n );\n\n /// @notice Emitted when a bid is placed\n event BidPlaced(address indexed comptroller, uint256 auctionStartBlock, uint256 bidBps, address indexed bidder);\n\n /// @notice Emitted when a auction is completed\n event AuctionClosed(\n address indexed comptroller,\n uint256 auctionStartBlock,\n address indexed highestBidder,\n uint256 highestBidBps,\n uint256 seizedRiskFind,\n VToken[] markets,\n uint256[] marketDebt\n );\n\n /// @notice Emitted when a auction is restarted\n event AuctionRestarted(address indexed comptroller, uint256 auctionStartBlock);\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @notice Emitted when minimum pool bad debt is updated\n event MinimumPoolBadDebtUpdated(uint256 oldMinimumPoolBadDebt, uint256 newMinimumPoolBadDebt);\n\n /// @notice Emitted when wait for first bidder block count is updated\n event WaitForFirstBidderUpdated(uint256 oldWaitForFirstBidder, uint256 newWaitForFirstBidder);\n\n /// @notice Emitted when next bidder block limit is updated\n event NextBidderBlockLimitUpdated(uint256 oldNextBidderBlockLimit, uint256 newNextBidderBlockLimit);\n\n /// @notice Emitted when incentiveBps is updated\n event IncentiveBpsUpdated(uint256 oldIncentiveBps, uint256 newIncentiveBps);\n\n /// @notice Emitted when auctions are paused\n event AuctionsPaused(address sender);\n\n /// @notice Emitted when auctions are unpaused\n event AuctionsResumed(address sender);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initialize the shortfall contract\n * @param convertibleBaseAsset_ Asset to swap the funds to\n * @param riskFund_ RiskFund contract address\n * @param minimumPoolBadDebt_ Minimum bad debt in base asset for a pool to start auction\n * @param accessControlManager_ AccessControlManager contract address\n * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n */\n function initialize(\n address convertibleBaseAsset_,\n IRiskFund riskFund_,\n uint256 minimumPoolBadDebt_,\n address accessControlManager_\n ) external initializer {\n ensureNonzeroAddress(convertibleBaseAsset_);\n ensureNonzeroAddress(address(riskFund_));\n require(minimumPoolBadDebt_ != 0, \"invalid minimum pool bad debt\");\n\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n __ReentrancyGuard_init();\n __TokenDebtTracker_init();\n minimumPoolBadDebt = minimumPoolBadDebt_;\n convertibleBaseAsset = convertibleBaseAsset_;\n riskFund = riskFund_;\n waitForFirstBidder = DEFAULT_WAIT_FOR_FIRST_BIDDER;\n nextBidderBlockLimit = DEFAULT_NEXT_BIDDER_BLOCK_LIMIT;\n incentiveBps = DEFAULT_INCENTIVE_BPS;\n auctionsPaused = false;\n }\n\n /**\n * @notice Place a bid greater than the previous in an ongoing auction\n * @param comptroller Comptroller address of the pool\n * @param bidBps The bid percent of the risk fund or bad debt depending on auction type\n * @param auctionStartBlock The block number when auction started\n * @custom:event Emits BidPlaced event on success\n */\n function placeBid(\n address comptroller,\n uint256 bidBps,\n uint256 auctionStartBlock\n ) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(auction.startBlock == auctionStartBlock, \"auction has been restarted\");\n require(_isStarted(auction), \"no on-going auction\");\n require(!_isStale(auction), \"auction is stale, restart it\");\n require(bidBps > 0, \"basis points cannot be zero\");\n require(bidBps <= MAX_BPS, \"basis points cannot be more than 10000\");\n require(\n (auction.auctionType == AuctionType.LARGE_POOL_DEBT &&\n ((auction.highestBidder != address(0) && bidBps > auction.highestBidBps) ||\n (auction.highestBidder == address(0) && bidBps >= auction.startBidBps))) ||\n (auction.auctionType == AuctionType.LARGE_RISK_FUND &&\n ((auction.highestBidder != address(0) && bidBps < auction.highestBidBps) ||\n (auction.highestBidder == address(0) && bidBps <= auction.startBidBps))),\n \"your bid is not the highest\"\n );\n\n uint256 marketsCount = auction.markets.length;\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = VToken(address(auction.markets[i]));\n IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n if (auction.highestBidder != address(0)) {\n _transferOutOrTrackDebt(erc20, auction.highestBidder, auction.bidAmount[auction.markets[i]]);\n }\n uint256 balanceBefore = erc20.balanceOf(address(this));\n\n if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n uint256 currentBidAmount = ((auction.marketDebt[auction.markets[i]] * bidBps) / MAX_BPS);\n erc20.safeTransferFrom(msg.sender, address(this), currentBidAmount);\n } else {\n erc20.safeTransferFrom(msg.sender, address(this), auction.marketDebt[auction.markets[i]]);\n }\n\n uint256 balanceAfter = erc20.balanceOf(address(this));\n auction.bidAmount[auction.markets[i]] = balanceAfter - balanceBefore;\n }\n\n auction.highestBidder = msg.sender;\n auction.highestBidBps = bidBps;\n auction.highestBidBlock = block.number;\n\n emit BidPlaced(comptroller, auction.startBlock, bidBps, msg.sender);\n }\n\n /**\n * @notice Close an auction\n * @param comptroller Comptroller address of the pool\n * @custom:event Emits AuctionClosed event on successful close\n */\n function closeAuction(address comptroller) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(_isStarted(auction), \"no on-going auction\");\n require(\n block.number > auction.highestBidBlock + nextBidderBlockLimit && auction.highestBidder != address(0),\n \"waiting for next bidder. cannot close auction\"\n );\n\n uint256 marketsCount = auction.markets.length;\n uint256[] memory marketsDebt = new uint256[](marketsCount);\n\n auction.status = AuctionStatus.ENDED;\n\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = VToken(address(auction.markets[i]));\n IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n uint256 balanceBefore = erc20.balanceOf(address(auction.markets[i]));\n erc20.safeTransfer(address(auction.markets[i]), auction.bidAmount[auction.markets[i]]);\n uint256 balanceAfter = erc20.balanceOf(address(auction.markets[i]));\n marketsDebt[i] = balanceAfter - balanceBefore;\n\n auction.markets[i].badDebtRecovered(marketsDebt[i]);\n }\n\n uint256 riskFundBidAmount;\n\n if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n riskFundBidAmount = auction.seizedRiskFund;\n } else {\n riskFundBidAmount = (auction.seizedRiskFund * auction.highestBidBps) / MAX_BPS;\n }\n\n uint256 transferredAmount = riskFund.transferReserveForAuction(comptroller, riskFundBidAmount);\n _transferOutOrTrackDebt(IERC20Upgradeable(convertibleBaseAsset), auction.highestBidder, riskFundBidAmount);\n\n emit AuctionClosed(\n comptroller,\n auction.startBlock,\n auction.highestBidder,\n auction.highestBidBps,\n transferredAmount,\n auction.markets,\n marketsDebt\n );\n }\n\n /**\n * @notice Start a auction when there is not currently one active\n * @param comptroller Comptroller address of the pool\n * @custom:event Emits AuctionStarted event on success\n * @custom:event Errors if auctions are paused\n */\n function startAuction(address comptroller) external nonReentrant {\n require(!auctionsPaused, \"Auctions are paused\");\n _startAuction(comptroller);\n }\n\n /**\n * @notice Restart an auction\n * @param comptroller Address of the pool\n * @custom:event Emits AuctionRestarted event on successful restart\n */\n function restartAuction(address comptroller) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(!auctionsPaused, \"auctions are paused\");\n require(_isStarted(auction), \"no on-going auction\");\n require(_isStale(auction), \"you need to wait for more time for first bidder\");\n\n auction.status = AuctionStatus.ENDED;\n\n emit AuctionRestarted(comptroller, auction.startBlock);\n _startAuction(comptroller);\n }\n\n /**\n * @notice Update next bidder block limit which is used determine when an auction can be closed\n * @param _nextBidderBlockLimit New next bidder block limit\n * @custom:event Emits NextBidderBlockLimitUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateNextBidderBlockLimit(uint256 _nextBidderBlockLimit) external {\n _checkAccessAllowed(\"updateNextBidderBlockLimit(uint256)\");\n require(_nextBidderBlockLimit != 0, \"_nextBidderBlockLimit must not be 0\");\n uint256 oldNextBidderBlockLimit = nextBidderBlockLimit;\n nextBidderBlockLimit = _nextBidderBlockLimit;\n emit NextBidderBlockLimitUpdated(oldNextBidderBlockLimit, _nextBidderBlockLimit);\n }\n\n /**\n * @notice Updates the incentive BPS\n * @param _incentiveBps New incentive BPS\n * @custom:event Emits IncentiveBpsUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateIncentiveBps(uint256 _incentiveBps) external {\n _checkAccessAllowed(\"updateIncentiveBps(uint256)\");\n require(_incentiveBps != 0, \"incentiveBps must not be 0\");\n uint256 oldIncentiveBps = incentiveBps;\n incentiveBps = _incentiveBps;\n emit IncentiveBpsUpdated(oldIncentiveBps, _incentiveBps);\n }\n\n /**\n * @notice Update minimum pool bad debt to start auction\n * @param _minimumPoolBadDebt Minimum bad debt in BUSD for a pool to start auction\n * @custom:event Emits MinimumPoolBadDebtUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateMinimumPoolBadDebt(uint256 _minimumPoolBadDebt) external {\n _checkAccessAllowed(\"updateMinimumPoolBadDebt(uint256)\");\n uint256 oldMinimumPoolBadDebt = minimumPoolBadDebt;\n minimumPoolBadDebt = _minimumPoolBadDebt;\n emit MinimumPoolBadDebtUpdated(oldMinimumPoolBadDebt, _minimumPoolBadDebt);\n }\n\n /**\n * @notice Update wait for first bidder block count. If the first bid is not made within this limit, the auction is closed and needs to be restarted\n * @param _waitForFirstBidder New wait for first bidder block count\n * @custom:event Emits WaitForFirstBidderUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateWaitForFirstBidder(uint256 _waitForFirstBidder) external {\n _checkAccessAllowed(\"updateWaitForFirstBidder(uint256)\");\n uint256 oldWaitForFirstBidder = waitForFirstBidder;\n waitForFirstBidder = _waitForFirstBidder;\n emit WaitForFirstBidderUpdated(oldWaitForFirstBidder, _waitForFirstBidder);\n }\n\n /**\n * @notice Update the pool registry this shortfall supports\n * @dev After Pool Registry is deployed we need to set the pool registry address\n * @param poolRegistry_ Address of pool registry contract\n * @custom:event Emits PoolRegistryUpdated on success\n * @custom:access Restricted to owner\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function updatePoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Pause auctions. This disables starting new auctions but lets the current auction finishes\n * @custom:event Emits AuctionsPaused on success\n * @custom:error Errors is auctions are paused\n * @custom:access Restricted by ACM\n */\n function pauseAuctions() external {\n _checkAccessAllowed(\"pauseAuctions()\");\n require(!auctionsPaused, \"Auctions are already paused\");\n auctionsPaused = true;\n emit AuctionsPaused(msg.sender);\n }\n\n /**\n * @notice Resume paused auctions.\n * @custom:event Emits AuctionsResumed on success\n * @custom:error Errors is auctions are active\n * @custom:access Restricted by ACM\n */\n function resumeAuctions() external {\n _checkAccessAllowed(\"resumeAuctions()\");\n require(auctionsPaused, \"Auctions are not paused\");\n auctionsPaused = false;\n emit AuctionsResumed(msg.sender);\n }\n\n /**\n * @notice Start a auction when there is not currently one active\n * @param comptroller Comptroller address of the pool\n */\n function _startAuction(address comptroller) internal {\n PoolRegistryInterface.VenusPool memory pool = PoolRegistry(poolRegistry).getPoolByComptroller(comptroller);\n require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n\n Auction storage auction = auctions[comptroller];\n require(\n auction.status == AuctionStatus.NOT_STARTED || auction.status == AuctionStatus.ENDED,\n \"auction is on-going\"\n );\n\n auction.highestBidBps = 0;\n auction.highestBidBlock = 0;\n\n uint256 marketsCount = auction.markets.length;\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = auction.markets[i];\n auction.marketDebt[vToken] = 0;\n }\n\n delete auction.markets;\n\n VToken[] memory vTokens = _getAllMarkets(comptroller);\n marketsCount = vTokens.length;\n ResilientOracleInterface priceOracle = _getPriceOracle(comptroller);\n uint256 poolBadDebt;\n\n uint256[] memory marketsDebt = new uint256[](marketsCount);\n auction.markets = new VToken[](marketsCount);\n\n for (uint256 i; i < marketsCount; ++i) {\n uint256 marketBadDebt = vTokens[i].badDebt();\n\n priceOracle.updatePrice(address(vTokens[i]));\n uint256 usdValue = (priceOracle.getUnderlyingPrice(address(vTokens[i])) * marketBadDebt) / EXP_SCALE;\n\n poolBadDebt = poolBadDebt + usdValue;\n auction.markets[i] = vTokens[i];\n auction.marketDebt[vTokens[i]] = marketBadDebt;\n marketsDebt[i] = marketBadDebt;\n }\n\n require(poolBadDebt >= minimumPoolBadDebt, \"pool bad debt is too low\");\n\n priceOracle.updateAssetPrice(riskFund.convertibleBaseAsset());\n uint256 riskFundBalance = (priceOracle.getPrice(riskFund.convertibleBaseAsset()) *\n riskFund.getPoolsBaseAssetReserves(comptroller)) / EXP_SCALE;\n uint256 remainingRiskFundBalance = riskFundBalance;\n uint256 badDebtPlusIncentive = poolBadDebt + ((poolBadDebt * incentiveBps) / MAX_BPS);\n if (badDebtPlusIncentive >= riskFundBalance) {\n auction.startBidBps =\n (MAX_BPS * MAX_BPS * remainingRiskFundBalance) /\n (poolBadDebt * (MAX_BPS + incentiveBps));\n remainingRiskFundBalance = 0;\n auction.auctionType = AuctionType.LARGE_POOL_DEBT;\n } else {\n uint256 maxSeizeableRiskFundBalance = badDebtPlusIncentive;\n\n remainingRiskFundBalance = remainingRiskFundBalance - maxSeizeableRiskFundBalance;\n auction.auctionType = AuctionType.LARGE_RISK_FUND;\n auction.startBidBps = MAX_BPS;\n }\n\n auction.seizedRiskFund = riskFundBalance - remainingRiskFundBalance;\n auction.startBlock = block.number;\n auction.status = AuctionStatus.STARTED;\n auction.highestBidder = address(0);\n\n emit AuctionStarted(\n comptroller,\n auction.startBlock,\n auction.auctionType,\n auction.markets,\n marketsDebt,\n auction.seizedRiskFund,\n auction.startBidBps\n );\n }\n\n /**\n * @dev Returns the price oracle of the pool\n * @param comptroller Address of the pool's comptroller\n * @return oracle The pool's price oracle\n */\n function _getPriceOracle(address comptroller) internal view returns (ResilientOracleInterface) {\n return ResilientOracleInterface(ComptrollerViewInterface(comptroller).oracle());\n }\n\n /**\n * @dev Returns all markets of the pool\n * @param comptroller Address of the pool's comptroller\n * @return markets The pool's markets as VToken array\n */\n function _getAllMarkets(address comptroller) internal view returns (VToken[] memory) {\n return ComptrollerInterface(comptroller).getAllMarkets();\n }\n\n /**\n * @dev Checks if the auction has started\n * @param auction The auction to query the status for\n * @return True if the auction has started\n */\n function _isStarted(Auction storage auction) internal view returns (bool) {\n return auction.status == AuctionStatus.STARTED;\n }\n\n /**\n * @dev Checks if the auction is stale, i.e. there's no bidder and the auction\n * was started more than waitForFirstBidder blocks ago.\n * @param auction The auction to query the status for\n * @return True if the auction is stale\n */\n function _isStale(Auction storage auction) internal view returns (bool) {\n bool noBidder = auction.highestBidder == address(0);\n return noBidder && (block.number > auction.startBlock + waitForFirstBidder);\n }\n}\n" + }, + "contracts/test/ComptrollerHarness.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { Comptroller } from \"../Comptroller.sol\";\n\ncontract ComptrollerHarness is Comptroller {\n uint256 public blockNumber;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n function harnessFastForward(uint256 blocks) public returns (uint256) {\n blockNumber += blocks;\n return blockNumber;\n }\n\n function setBlockNumber(uint256 number) public {\n blockNumber = number;\n }\n}\n\ncontract EchoTypesComptroller {\n function stringy(string memory s) public pure returns (string memory) {\n return s;\n }\n\n function addresses(address a) public pure returns (address) {\n return a;\n }\n\n function booly(bool b) public pure returns (bool) {\n return b;\n }\n\n function listOInts(uint256[] memory u) public pure returns (uint256[] memory) {\n return u;\n }\n\n function reverty() public pure {\n require(false, \"gotcha sucka\");\n }\n}\n" + }, + "contracts/test/ComptrollerScenario.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\n\ncontract ComptrollerScenario is Comptroller {\n uint256 public blockNumber;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n function fastForward(uint256 blocks) public returns (uint256) {\n blockNumber += blocks;\n return blockNumber;\n }\n\n function setBlockNumber(uint256 number) public {\n blockNumber = number;\n }\n\n function unlist(VToken vToken) public {\n markets[address(vToken)].isListed = false;\n }\n\n function membershipLength(VToken vToken) public view returns (uint256) {\n return accountAssets[address(vToken)].length;\n }\n}\n" + }, + "contracts/test/ERC20.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { SafeMath } from \"./SafeMath.sol\";\n\ninterface ERC20Base {\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function totalSupply() external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function balanceOf(address who) external view returns (uint256);\n}\n\nabstract contract ERC20 is ERC20Base {\n function transfer(address to, uint256 value) external virtual returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external virtual returns (bool);\n}\n\nabstract contract ERC20NS is ERC20Base {\n function transfer(address to, uint256 value) external virtual;\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external virtual;\n}\n\n/**\n * @title Standard ERC20 token\n * @dev Implementation of the basic standard token.\n * See https://github.com/ethereum/EIPs/issues/20\n */\ncontract StandardToken is ERC20 {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external virtual override returns (bool) {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external virtual override returns (bool) {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function approve(address _spender, uint256 amount) external virtual override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\n/**\n * @title Non-Standard ERC20 token\n * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`\n * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\ncontract NonStandardToken is ERC20NS {\n using SafeMath for uint256;\n\n string public name;\n uint8 public decimals;\n string public symbol;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external override {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n }\n\n function approve(address _spender, uint256 amount) external override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\ncontract ERC20Harness is StandardToken {\n using SafeMath for uint256;\n // To support testing, we can specify addresses for which transferFrom should fail and return false\n mapping(address => bool) public failTransferFromAddresses;\n\n // To support testing, we allow the contract to always fail `transfer`.\n mapping(address => bool) public failTransferToAddresses;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferToAddresses[dst]) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferFromAddresses[src]) {\n return false;\n }\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\n failTransferFromAddresses[src] = _fail;\n }\n\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\n failTransferToAddresses[dst] = _fail;\n }\n\n function harnessSetBalance(address _account, uint256 _amount) public {\n balanceOf[_account] = _amount;\n }\n}\n" + }, + "contracts/test/EvilToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { FaucetToken } from \"./FaucetToken.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title The Compound Evil Test Token\n * @author Compound\n * @notice A simple test token that fails certain operations\n */\ncontract EvilToken is FaucetToken {\n using SafeMath for uint256;\n\n bool public fail;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) FaucetToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {\n fail = true;\n }\n\n function setFail(bool _fail) external {\n fail = _fail;\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool) {\n if (fail) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(amount);\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override returns (bool) {\n if (fail) {\n return false;\n }\n balanceOf[src] = balanceOf[src].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(amount);\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" + }, + "contracts/test/FaucetToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { StandardToken, NonStandardToken } from \"./ERC20.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title The Compound Faucet Test Token\n * @author Compound\n * @notice A simple test token that lets anyone get more of it.\n */\ncontract FaucetToken is StandardToken {\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf[_owner] += value;\n totalSupply += value;\n emit Transfer(address(this), _owner, value);\n }\n}\n\n/**\n * @title The Compound Faucet Test Token (non-standard)\n * @author Compound\n * @notice A simple test token that lets anyone get more of it.\n */\ncontract FaucetNonStandardToken is NonStandardToken {\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n NonStandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf[_owner] += value;\n totalSupply += value;\n emit Transfer(address(this), _owner, value);\n }\n}\n\n/**\n * @title The Compound Faucet Re-Entrant Test Token\n * @author Compound\n * @notice A test token that is malicious and tries to re-enter callers\n */\ncontract FaucetTokenReEntrantHarness {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 private totalSupply_;\n mapping(address => mapping(address => uint256)) private allowance_;\n mapping(address => uint256) private balanceOf_;\n\n bytes public reEntryCallData;\n string public reEntryFun;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n modifier reEnter(string memory funName) {\n string memory _reEntryFun = reEntryFun;\n if (compareStrings(_reEntryFun, funName)) {\n reEntryFun = \"\"; // Clear re-entry fun\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = msg.sender.call(reEntryCallData);\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 0) {\n revert(add(returndata, 0x20), returndatasize())\n }\n }\n }\n\n _;\n }\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol,\n bytes memory _reEntryCallData,\n string memory _reEntryFun\n ) {\n totalSupply_ = _initialAmount;\n balanceOf_[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n reEntryCallData = _reEntryCallData;\n reEntryFun = _reEntryFun;\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf_[_owner] += value;\n totalSupply_ += value;\n emit Transfer(address(this), _owner, value);\n }\n\n function totalSupply() public reEnter(\"totalSupply\") returns (uint256) {\n return totalSupply_;\n }\n\n function allowance(address owner, address spender) public reEnter(\"allowance\") returns (uint256 remaining) {\n return allowance_[owner][spender];\n }\n\n function approve(address spender, uint256 amount) public reEnter(\"approve\") returns (bool success) {\n _approve(msg.sender, spender, amount);\n return true;\n }\n\n function balanceOf(address owner) public reEnter(\"balanceOf\") returns (uint256 balance) {\n return balanceOf_[owner];\n }\n\n function transfer(address dst, uint256 amount) public reEnter(\"transfer\") returns (bool success) {\n _transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) public reEnter(\"transferFrom\") returns (bool success) {\n _transfer(src, dst, amount);\n _approve(src, msg.sender, allowance_[src][msg.sender].sub(amount));\n return true;\n }\n\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(spender != address(0), \"FaucetToken: approve to the zero address\");\n require(owner != address(0), \"FaucetToken: approve from the zero address\");\n allowance_[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n function _transfer(\n address src,\n address dst,\n uint256 amount\n ) internal {\n require(dst != address(0), \"FaucetToken: transfer to the zero address\");\n balanceOf_[src] = balanceOf_[src].sub(amount);\n balanceOf_[dst] = balanceOf_[dst].add(amount);\n emit Transfer(src, dst, amount);\n }\n\n function compareStrings(string memory a, string memory b) internal pure returns (bool) {\n return keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)));\n }\n}\n" + }, + "contracts/test/FeeToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { FaucetToken } from \"./FaucetToken.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title Fee Token\n * @author Compound\n * @notice A simple test token that charges fees on transfer. Used to mock USDT.\n */\ncontract FeeToken is FaucetToken {\n using SafeMath for uint256;\n\n uint256 public basisPointFee;\n address public owner;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol,\n uint256 _basisPointFee,\n address _owner\n ) FaucetToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {\n basisPointFee = _basisPointFee;\n owner = _owner;\n }\n\n function transfer(address dst, uint256 amount) public override returns (bool) {\n uint256 fee = amount.mul(basisPointFee).div(10000);\n uint256 net = amount.sub(fee);\n balanceOf[owner] = balanceOf[owner].add(fee);\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(net);\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) public override returns (bool) {\n uint256 fee = amount.mul(basisPointFee).div(10000);\n uint256 net = amount.sub(fee);\n balanceOf[owner] = balanceOf[owner].add(fee);\n balanceOf[src] = balanceOf[src].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(net);\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" + }, + "contracts/test/HarnessMaxLoopsLimitHelper.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\n\ncontract HarnessMaxLoopsLimitHelper is MaxLoopsLimitHelper {\n function setMaxLoopsLimit(uint256 limit) external {\n _setMaxLoopsLimit(limit);\n }\n\n function ensureMaxLoops(uint256 limit) external view {\n _ensureMaxLoops(limit);\n }\n}\n" + }, + "contracts/test/lib/ApproveOrRevertHarness.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ApproveOrRevert } from \"../../lib/ApproveOrRevert.sol\";\n\ncontract ApproveOrRevertHarness {\n using ApproveOrRevert for IERC20Upgradeable;\n\n function approve(\n IERC20Upgradeable token,\n address spender,\n uint256 amount\n ) external {\n token.approveOrRevert(spender, amount);\n }\n}\n" + }, + "contracts/test/lib/TokenDebtTrackerHarness.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { TokenDebtTracker } from \"../../lib/TokenDebtTracker.sol\";\n\ncontract TokenDebtTrackerHarness is TokenDebtTracker {\n function initialize() external initializer {\n __TokenDebtTracker_init();\n }\n\n function addTokenDebt(\n IERC20Upgradeable token,\n address user,\n uint256 amount\n ) external {\n tokenDebt[token][user] += amount;\n totalTokenDebt[token] += amount;\n }\n\n function transferOutOrTrackDebt(\n IERC20Upgradeable token,\n address user,\n uint256 amount\n ) external {\n _transferOutOrTrackDebt(token, user, amount);\n }\n\n function transferOutOrTrackDebtSkippingBalanceCheck(\n IERC20Upgradeable token,\n address user,\n uint256 amount\n ) external {\n _transferOutOrTrackDebtSkippingBalanceCheck(token, user, amount);\n }\n}\n" + }, + "contracts/test/MockDeflationaryToken.sol": { + "content": "pragma solidity 0.8.13;\n\ncontract MockDeflatingToken {\n string public constant NAME = \"Deflating Test Token\";\n string public constant SYMBOL = \"DTT\";\n uint8 public constant DECIMALS = 18;\n uint256 public totalSupply;\n mapping(address => uint256) public balanceOf;\n mapping(address => mapping(address => uint256)) public allowance;\n\n bytes32 public DOMAIN_SEPARATOR;\n // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n mapping(address => uint256) public nonces;\n\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n constructor(uint256 _totalSupply) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n DOMAIN_SEPARATOR = keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string NAME,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(NAME)),\n keccak256(bytes(\"1\")),\n chainId,\n address(this)\n )\n );\n _mint(msg.sender, _totalSupply);\n }\n\n function approve(address spender, uint256 value) external returns (bool) {\n _approve(msg.sender, spender, value);\n return true;\n }\n\n function transfer(address to, uint256 value) external returns (bool) {\n _transfer(msg.sender, to, value);\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool) {\n if (allowance[from][msg.sender] != type(uint256).max) {\n allowance[from][msg.sender] = allowance[from][msg.sender] - value;\n }\n _transfer(from, to, value);\n return true;\n }\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n require(deadline >= block.timestamp, \"EXPIRED\");\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR,\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))\n )\n );\n address recoveredAddress = ecrecover(digest, v, r, s);\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNATURE\");\n _approve(owner, spender, value);\n }\n\n function _mint(address to, uint256 value) internal {\n totalSupply = totalSupply + value;\n balanceOf[to] = balanceOf[to] + value;\n emit Transfer(address(0), to, value);\n }\n\n function _burn(address from, uint256 value) internal {\n balanceOf[from] = balanceOf[from] - value;\n totalSupply = totalSupply - value;\n emit Transfer(from, address(0), value);\n }\n\n function _approve(\n address owner,\n address spender,\n uint256 value\n ) private {\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n function _transfer(\n address from,\n address to,\n uint256 value\n ) private {\n uint256 burnAmount = value / 100;\n _burn(from, burnAmount);\n uint256 transferAmount = value - burnAmount;\n balanceOf[from] = balanceOf[from] - transferAmount;\n balanceOf[to] = balanceOf[to] + transferAmount;\n emit Transfer(from, to, transferAmount);\n }\n}\n" + }, + "contracts/test/Mocks/MockPriceOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { BinanceOracle } from \"@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol\";\nimport { ChainlinkOracle } from \"@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol\";\n\nimport { VToken } from \"../../VToken.sol\";\n\ncontract MockPriceOracle is ResilientOracleInterface {\n mapping(address => uint256) public assetPrices;\n\n //set price in 6 decimal precision\n // solhint-disable-next-line no-empty-blocks\n constructor() {}\n\n function setPrice(address asset, uint256 price) external {\n assetPrices[asset] = price;\n }\n\n // solhint-disable-next-line no-empty-blocks\n function updatePrice(address vToken) external override {}\n\n // solhint-disable-next-line no-empty-blocks\n function updateAssetPrice(address asset) external override {}\n\n function getPrice(address asset) external view returns (uint256) {\n return assetPrices[asset];\n }\n\n //https://compound.finance/docs/prices\n function getUnderlyingPrice(address vToken) public view override returns (uint256) {\n return assetPrices[VToken(vToken).underlying()];\n }\n}\n" + }, + "contracts/test/Mocks/MockToken.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockToken is ERC20 {\n uint8 private immutable _decimals;\n\n constructor(\n string memory name_,\n string memory symbol_,\n uint8 decimals_\n ) ERC20(name_, symbol_) {\n _decimals = decimals_;\n }\n\n function faucet(uint256 amount) external {\n _mint(msg.sender, amount);\n }\n\n function decimals() public view virtual override returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/test/SafeMath.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol\n// Subject to the MIT license.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction underflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts with custom message on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n" + }, + "contracts/test/UpgradedVToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\n/**\n * @title Venus's VToken Contract\n * @notice VTokens which wrap an EIP-20 underlying and are immutable\n * @author Venus\n */\ncontract UpgradedVToken is VToken {\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param riskManagement Addresses of risk fund contracts\n */\n\n /// @notice We added this new function to test contract upgrade\n function version() external pure returns (uint256) {\n return 2;\n }\n\n function initializeV2(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) public reinitializer(2) {\n super._initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_,\n admin_,\n accessControlManager_,\n riskManagement,\n reserveFactorMantissa_\n );\n }\n\n function getTokenUnderlying() public view returns (address) {\n return underlying;\n }\n}\n" + }, + "contracts/test/VTokenHarness.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\ncontract VTokenHarness is VToken {\n uint256 public blockNumber;\n uint256 public harnessExchangeRate;\n bool public harnessExchangeRateStored;\n\n mapping(address => bool) public failTransferToAddresses;\n\n function harnessSetAccrualBlockNumber(uint256 accrualBlockNumber_) external {\n accrualBlockNumber = accrualBlockNumber_;\n }\n\n function harnessSetBlockNumber(uint256 newBlockNumber) external {\n blockNumber = newBlockNumber;\n }\n\n function harnessFastForward(uint256 blocks) external {\n blockNumber += blocks;\n }\n\n function harnessSetBalance(address account, uint256 amount) external {\n accountTokens[account] = amount;\n }\n\n function harnessSetTotalSupply(uint256 totalSupply_) external {\n totalSupply = totalSupply_;\n }\n\n function harnessSetTotalBorrows(uint256 totalBorrows_) external {\n totalBorrows = totalBorrows_;\n }\n\n function harnessSetTotalReserves(uint256 totalReserves_) external {\n totalReserves = totalReserves_;\n }\n\n function harnessExchangeRateDetails(\n uint256 totalSupply_,\n uint256 totalBorrows_,\n uint256 totalReserves_\n ) external {\n totalSupply = totalSupply_;\n totalBorrows = totalBorrows_;\n totalReserves = totalReserves_;\n }\n\n function harnessSetExchangeRate(uint256 exchangeRate) external {\n harnessExchangeRate = exchangeRate;\n harnessExchangeRateStored = true;\n }\n\n function harnessSetFailTransferToAddress(address to_, bool fail_) external {\n failTransferToAddresses[to_] = fail_;\n }\n\n function harnessMintFresh(address account, uint256 mintAmount) external {\n super._mintFresh(account, account, mintAmount);\n }\n\n function harnessRedeemFresh(\n address payable account,\n uint256 vTokenAmount,\n uint256 underlyingAmount\n ) external {\n super._redeemFresh(account, vTokenAmount, underlyingAmount);\n }\n\n function harnessSetAccountBorrows(\n address account,\n uint256 principal,\n uint256 interestIndex\n ) external {\n accountBorrows[account] = BorrowSnapshot({ principal: principal, interestIndex: interestIndex });\n }\n\n function harnessSetBorrowIndex(uint256 borrowIndex_) external {\n borrowIndex = borrowIndex_;\n }\n\n function harnessBorrowFresh(address payable account, uint256 borrowAmount) external {\n _borrowFresh(account, borrowAmount);\n }\n\n function harnessRepayBorrowFresh(\n address payer,\n address account,\n uint256 repayAmount\n ) external {\n _repayBorrowFresh(payer, account, repayAmount);\n }\n\n function harnessLiquidateBorrowFresh(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VToken vTokenCollateral,\n bool skipLiquidityCheck\n ) external {\n _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n function harnessReduceReservesFresh(uint256 amount) external {\n return _reduceReservesFresh(amount);\n }\n\n function harnessSetReserveFactorFresh(uint256 newReserveFactorMantissa) external {\n _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n function harnessSetInterestRateModelFresh(InterestRateModel newInterestRateModel) external {\n _setInterestRateModelFresh(newInterestRateModel);\n }\n\n function harnessAccountBorrows(address account) external view returns (uint256 principal, uint256 interestIndex) {\n BorrowSnapshot memory snapshot = accountBorrows[account];\n return (snapshot.principal, snapshot.interestIndex);\n }\n\n function getBorrowRateMaxMantissa() external pure returns (uint256) {\n return MAX_BORROW_RATE_MANTISSA;\n }\n\n function harnessSetInterestRateModel(address newInterestRateModelAddress) public {\n interestRateModel = InterestRateModel(newInterestRateModelAddress);\n }\n\n function harnessCallPreBorrowHook(uint256 amount) public {\n comptroller.preBorrowHook(address(this), msg.sender, amount);\n }\n\n function _doTransferOut(address to, uint256 amount) internal override {\n require(failTransferToAddresses[to] == false, \"HARNESS_TOKEN_TRANSFER_OUT_FAILED\");\n return super._doTransferOut(to, amount);\n }\n\n function _exchangeRateStored() internal view override returns (uint256) {\n if (harnessExchangeRateStored) {\n return harnessExchangeRate;\n }\n return super._exchangeRateStored();\n }\n\n function _getBlockNumber() internal view override returns (uint256) {\n return blockNumber;\n }\n}\n" + }, + "contracts/VToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { VTokenInterface } from \"./VTokenInterfaces.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"./ComptrollerInterface.sol\";\nimport { TokenErrorReporter } from \"./ErrorReporter.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { IProtocolShareReserve } from \"./RiskFund/IProtocolShareReserve.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title VToken\n * @author Venus\n * @notice Each asset that is supported by a pool is integrated through an instance of the `VToken` contract. As outlined in the protocol overview,\n * each isolated pool creates its own `vToken` corresponding to an asset. Within a given pool, each included `vToken` is referred to as a market of\n * the pool. The main actions a user regularly interacts with in a market are:\n\n- mint/redeem of vTokens;\n- transfer of vTokens;\n- borrow/repay a loan on an underlying asset;\n- liquidate a borrow or liquidate/heal an account.\n\n * A user supplies the underlying asset to a pool by minting `vTokens`, where the corresponding `vToken` amount is determined by the `exchangeRate`.\n * The `exchangeRate` will change over time, dependent on a number of factors, some of which accrue interest. Additionally, once users have minted\n * `vToken` in a pool, they can borrow any asset in the isolated pool by using their `vToken` as collateral. In order to borrow an asset or use a `vToken`\n * as collateral, the user must be entered into each corresponding market (else, the `vToken` will not be considered collateral for a borrow). Note that\n * a user may borrow up to a portion of their collateral determined by the market’s collateral factor. However, if their borrowed amount exceeds an amount\n * calculated using the market’s corresponding liquidation threshold, the borrow is eligible for liquidation. When a user repays a borrow, they must also\n * pay off interest accrued on the borrow.\n * \n * The Venus protocol includes unique mechanisms for healing an account and liquidating an account. These actions are performed in the `Comptroller`\n * and consider all borrows and collateral for which a given account is entered within a market. These functions may only be called on an account with a\n * total collateral amount that is no larger than a universal `minLiquidatableCollateral` value, which is used for all markets within a `Comptroller`.\n * Both functions settle all of an account’s borrows, but `healAccount()` may add `badDebt` to a vToken. For more detail, see the description of\n * `healAccount()` and `liquidateAccount()` in the `Comptroller` summary section below.\n */\ncontract VToken is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n VTokenInterface,\n ExponentialNoError,\n TokenErrorReporter\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n uint256 internal constant DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA = 5e16; // 5%\n\n /*** Reentrancy Guard ***/\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(_notEntered, \"re-entered\");\n _notEntered = false;\n _;\n _notEntered = true; // get a gas-refund post-Istanbul\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param accessControlManager_ AccessControlManager contract address\n * @param riskManagement Addresses of risk & income related contracts\n * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n * @custom:error ZeroAddressNotAllowed is thrown when admin address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n */\n function initialize(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) external initializer {\n ensureNonzeroAddress(admin_);\n\n // Initialize the market\n _initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_,\n admin_,\n accessControlManager_,\n riskManagement,\n reserveFactorMantissa_\n );\n }\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return success True if the transfer succeeded, reverts otherwise\n * @custom:event Emits Transfer event on success\n * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n * @custom:access Not restricted\n */\n function transfer(address dst, uint256 amount) external override nonReentrant returns (bool) {\n _transferTokens(msg.sender, msg.sender, dst, amount);\n return true;\n }\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return success True if the transfer succeeded, reverts otherwise\n * @custom:event Emits Transfer event on success\n * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n * @custom:access Not restricted\n */\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override nonReentrant returns (bool) {\n _transferTokens(msg.sender, src, dst, amount);\n return true;\n }\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param amount The number of tokens that are approved (uint256.max means infinite)\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function approve(address spender, uint256 amount) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n transferAllowances[src][spender] = amount;\n emit Approval(src, spender, amount);\n return true;\n }\n\n /**\n * @notice Increase approval for `spender`\n * @param spender The address of the account which may transfer tokens\n * @param addedValue The number of additional tokens spender can transfer\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function increaseAllowance(address spender, uint256 addedValue) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n uint256 newAllowance = transferAllowances[src][spender];\n newAllowance += addedValue;\n transferAllowances[src][spender] = newAllowance;\n\n emit Approval(src, spender, newAllowance);\n return true;\n }\n\n /**\n * @notice Decreases approval for `spender`\n * @param spender The address of the account which may transfer tokens\n * @param subtractedValue The number of tokens to remove from total approval\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n uint256 currentAllowance = transferAllowances[src][spender];\n require(currentAllowance >= subtractedValue, \"decreased allowance below zero\");\n unchecked {\n currentAllowance -= subtractedValue;\n }\n\n transferAllowances[src][spender] = currentAllowance;\n\n emit Approval(src, spender, currentAllowance);\n return true;\n }\n\n /**\n * @notice Get the underlying balance of the `owner`\n * @dev This also accrues interest in a transaction\n * @param owner The address of the account to query\n * @return amount The amount of underlying owned by `owner`\n */\n function balanceOfUnderlying(address owner) external override returns (uint256) {\n Exp memory exchangeRate = Exp({ mantissa: exchangeRateCurrent() });\n return mul_ScalarTruncate(exchangeRate, accountTokens[owner]);\n }\n\n /**\n * @notice Returns the current total borrows plus accrued interest\n * @return totalBorrows The total borrows with interest\n */\n function totalBorrowsCurrent() external override nonReentrant returns (uint256) {\n accrueInterest();\n return totalBorrows;\n }\n\n /**\n * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex\n * @param account The address whose balance should be calculated after updating borrowIndex\n * @return borrowBalance The calculated balance\n */\n function borrowBalanceCurrent(address account) external override nonReentrant returns (uint256) {\n accrueInterest();\n return _borrowBalanceStored(account);\n }\n\n /**\n * @notice Sender supplies assets into the market and receives vTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param mintAmount The amount of the underlying asset to supply\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function mint(uint256 mintAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n _mintFresh(msg.sender, msg.sender, mintAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender calls on-behalf of minter. minter supplies assets into the market and receives vTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param minter User whom the supply will be attributed to\n * @param mintAmount The amount of the underlying asset to supply\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when minter address is zero\n */\n function mintBehalf(address minter, uint256 mintAmount) external override nonReentrant returns (uint256) {\n ensureNonzeroAddress(minter);\n\n accrueInterest();\n // _mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n _mintFresh(msg.sender, minter, mintAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender redeems vTokens in exchange for the underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemTokens The number of vTokens to redeem into underlying\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Redeem and Transfer events; may emit AccrueInterest\n * @custom:error RedeemTransferOutNotPossible is thrown when the protocol has insufficient cash\n * @custom:access Not restricted\n */\n function redeem(uint256 redeemTokens) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _redeemFresh emits redeem-specific logs on errors, so we don't need to\n _redeemFresh(msg.sender, redeemTokens, 0);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender redeems vTokens in exchange for a specified amount of underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemAmount The amount of underlying to receive from redeeming vTokens\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n */\n function redeemUnderlying(uint256 redeemAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _redeemFresh emits redeem-specific logs on errors, so we don't need to\n _redeemFresh(msg.sender, 0, redeemAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender borrows assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Borrow event; may emit AccrueInterest\n * @custom:error BorrowCashNotAvailable is thrown when the protocol has insufficient cash\n * @custom:access Not restricted\n */\n function borrow(uint256 borrowAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // borrowFresh emits borrow-specific logs on errors, so we don't need to\n _borrowFresh(msg.sender, borrowAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender repays their own borrow\n * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function repayBorrow(uint256 repayAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n _repayBorrowFresh(msg.sender, msg.sender, repayAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender repays a borrow belonging to borrower\n * @param borrower the account with the debt being payed off\n * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n _repayBorrowFresh(msg.sender, borrower, repayAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param borrower The borrower of this vToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n * @custom:access Not restricted\n */\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral\n ) external override returns (uint256) {\n _liquidateBorrow(msg.sender, borrower, repayAmount, vTokenCollateral, false);\n return NO_ERROR;\n }\n\n /**\n * @notice sets protocol share accumulated from liquidations\n * @dev must be equal or less than liquidation incentive - 1\n * @param newProtocolSeizeShareMantissa_ new protocol share mantissa\n * @custom:event Emits NewProtocolSeizeShare event on success\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:error ProtocolSeizeShareTooBig is thrown when the new seize share is too high\n * @custom:access Controlled by AccessControlManager\n */\n function setProtocolSeizeShare(uint256 newProtocolSeizeShareMantissa_) external {\n _checkAccessAllowed(\"setProtocolSeizeShare(uint256)\");\n uint256 liquidationIncentive = ComptrollerViewInterface(address(comptroller)).liquidationIncentiveMantissa();\n if (newProtocolSeizeShareMantissa_ + MANTISSA_ONE > liquidationIncentive) {\n revert ProtocolSeizeShareTooBig();\n }\n\n uint256 oldProtocolSeizeShareMantissa = protocolSeizeShareMantissa;\n protocolSeizeShareMantissa = newProtocolSeizeShareMantissa_;\n emit NewProtocolSeizeShare(oldProtocolSeizeShareMantissa, newProtocolSeizeShareMantissa_);\n }\n\n /**\n * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh\n * @dev Admin function to accrue interest and set a new reserve factor\n * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n * @custom:event Emits NewReserveFactor event; may emit AccrueInterest\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:error SetReserveFactorBoundsCheck is thrown when the new reserve factor is too high\n * @custom:access Controlled by AccessControlManager\n */\n function setReserveFactor(uint256 newReserveFactorMantissa) external override nonReentrant {\n _checkAccessAllowed(\"setReserveFactor(uint256)\");\n\n accrueInterest();\n _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n /**\n * @notice Accrues interest and reduces reserves by transferring to the protocol reserve contract\n * @param reduceAmount Amount of reduction to reserves\n * @custom:event Emits ReservesReduced event; may emit AccrueInterest\n * @custom:error ReduceReservesCashNotAvailable is thrown when the vToken does not have sufficient cash\n * @custom:error ReduceReservesCashValidation is thrown when trying to withdraw more cash than the reserves have\n * @custom:access Not restricted\n */\n function reduceReserves(uint256 reduceAmount) external override nonReentrant {\n accrueInterest();\n _reduceReservesFresh(reduceAmount);\n }\n\n /**\n * @notice The sender adds to reserves.\n * @param addAmount The amount of underlying token to add as reserves\n * @custom:event Emits ReservesAdded event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function addReserves(uint256 addAmount) external override nonReentrant {\n accrueInterest();\n _addReservesFresh(addAmount);\n }\n\n /**\n * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh\n * @dev Admin function to accrue interest and update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n * @custom:event Emits NewMarketInterestRateModel event; may emit AccrueInterest\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:access Controlled by AccessControlManager\n */\n function setInterestRateModel(InterestRateModel newInterestRateModel) external override {\n _checkAccessAllowed(\"setInterestRateModel(address)\");\n\n accrueInterest();\n _setInterestRateModelFresh(newInterestRateModel);\n }\n\n /**\n * @notice Repays a certain amount of debt, treats the rest of the borrow as bad debt, essentially\n * \"forgiving\" the borrower. Healing is a situation that should rarely happen. However, some pools\n * may list risky assets or be configured improperly – we want to still handle such cases gracefully.\n * We assume that Comptroller does the seizing, so this function is only available to Comptroller.\n * @dev This function does not call any Comptroller hooks (like \"healAllowed\"), because we assume\n * the Comptroller does all the necessary checks before calling this function.\n * @param payer account who repays the debt\n * @param borrower account to heal\n * @param repayAmount amount to repay\n * @custom:event Emits RepayBorrow, BadDebtIncreased events; may emit AccrueInterest\n * @custom:error HealBorrowUnauthorized is thrown when the request does not come from Comptroller\n * @custom:access Only Comptroller\n */\n function healBorrow(\n address payer,\n address borrower,\n uint256 repayAmount\n ) external override nonReentrant {\n if (repayAmount != 0) {\n comptroller.preRepayHook(address(this), borrower);\n }\n\n if (msg.sender != address(comptroller)) {\n revert HealBorrowUnauthorized();\n }\n\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n uint256 totalBorrowsNew = totalBorrows;\n\n uint256 actualRepayAmount;\n if (repayAmount != 0) {\n // _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n // We violate checks-effects-interactions here to account for tokens that take transfer fees\n actualRepayAmount = _doTransferIn(payer, repayAmount);\n totalBorrowsNew = totalBorrowsNew - actualRepayAmount;\n emit RepayBorrow(\n payer,\n borrower,\n actualRepayAmount,\n accountBorrowsPrev - actualRepayAmount,\n totalBorrowsNew\n );\n }\n\n // The transaction will fail if trying to repay too much\n uint256 badDebtDelta = accountBorrowsPrev - actualRepayAmount;\n if (badDebtDelta != 0) {\n uint256 badDebtOld = badDebt;\n uint256 badDebtNew = badDebtOld + badDebtDelta;\n totalBorrowsNew = totalBorrowsNew - badDebtDelta;\n badDebt = badDebtNew;\n\n // We treat healing as \"repayment\", where vToken is the payer\n emit RepayBorrow(address(this), borrower, badDebtDelta, 0, totalBorrowsNew);\n emit BadDebtIncreased(borrower, badDebtDelta, badDebtOld, badDebtNew);\n }\n\n accountBorrows[borrower].principal = 0;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n emit HealBorrow(payer, borrower, repayAmount);\n }\n\n /**\n * @notice The extended version of liquidations, callable only by Comptroller. May skip\n * the close factor check. The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n * @custom:error ForceLiquidateBorrowUnauthorized is thrown when the request does not come from Comptroller\n * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n * @custom:access Only Comptroller\n */\n function forceLiquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) external override {\n if (msg.sender != address(comptroller)) {\n revert ForceLiquidateBorrowUnauthorized();\n }\n _liquidateBorrow(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Will fail unless called by another vToken during the process of liquidation.\n * It's absolutely critical to use msg.sender as the borrowed vToken and not a parameter.\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of vTokens to seize\n * @custom:event Emits Transfer, ReservesAdded events\n * @custom:error LiquidateSeizeLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:access Not restricted\n */\n function seize(\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external override nonReentrant {\n _seize(msg.sender, liquidator, borrower, seizeTokens);\n }\n\n /**\n * @notice Updates bad debt\n * @dev Called only when bad debt is recovered from auction\n * @param recoveredAmount_ The amount of bad debt recovered\n * @custom:event Emits BadDebtRecovered event\n * @custom:access Only Shortfall contract\n */\n function badDebtRecovered(uint256 recoveredAmount_) external {\n require(msg.sender == shortfall, \"only shortfall contract can update bad debt\");\n require(recoveredAmount_ <= badDebt, \"more than bad debt recovered from auction\");\n\n uint256 badDebtOld = badDebt;\n uint256 badDebtNew = badDebtOld - recoveredAmount_;\n badDebt = badDebtNew;\n\n emit BadDebtRecovered(badDebtOld, badDebtNew);\n }\n\n /**\n * @notice Sets protocol share reserve contract address\n * @param protocolShareReserve_ The address of the protocol share reserve contract\n * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n * @custom:access Only Governance\n */\n function setProtocolShareReserve(address payable protocolShareReserve_) external onlyOwner {\n _setProtocolShareReserve(protocolShareReserve_);\n }\n\n /**\n * @notice Sets shortfall contract address\n * @param shortfall_ The address of the shortfall contract\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n * @custom:access Only Governance\n */\n function setShortfallContract(address shortfall_) external onlyOwner {\n _setShortfallContract(shortfall_);\n }\n\n /**\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\n * @param token The address of the ERC-20 token to sweep\n * @custom:access Only Governance\n */\n function sweepToken(IERC20Upgradeable token) external override {\n require(msg.sender == owner(), \"VToken::sweepToken: only admin can sweep tokens\");\n require(address(token) != underlying, \"VToken::sweepToken: can not sweep underlying token\");\n uint256 balance = token.balanceOf(address(this));\n token.safeTransfer(owner(), balance);\n\n emit SweepToken(address(token));\n }\n\n /**\n * @notice Get the current allowance from `owner` for `spender`\n * @param owner The address of the account which owns the tokens to be spent\n * @param spender The address of the account which may transfer tokens\n * @return amount The number of tokens allowed to be spent (type(uint256).max means infinite)\n */\n function allowance(address owner, address spender) external view override returns (uint256) {\n return transferAllowances[owner][spender];\n }\n\n /**\n * @notice Get the token balance of the `owner`\n * @param owner The address of the account to query\n * @return amount The number of tokens owned by `owner`\n */\n function balanceOf(address owner) external view override returns (uint256) {\n return accountTokens[owner];\n }\n\n /**\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\n * @param account Address of the account to snapshot\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return vTokenBalance User's balance of vTokens\n * @return borrowBalance Amount owed in terms of underlying\n * @return exchangeRate Stored exchange rate\n */\n function getAccountSnapshot(address account)\n external\n view\n override\n returns (\n uint256 error,\n uint256 vTokenBalance,\n uint256 borrowBalance,\n uint256 exchangeRate\n )\n {\n return (NO_ERROR, accountTokens[account], _borrowBalanceStored(account), _exchangeRateStored());\n }\n\n /**\n * @notice Get cash balance of this vToken in the underlying asset\n * @return cash The quantity of underlying asset owned by this contract\n */\n function getCash() external view override returns (uint256) {\n return _getCashPrior();\n }\n\n /**\n * @notice Returns the current per-block borrow interest rate for this vToken\n * @return rate The borrow interest rate per block, scaled by 1e18\n */\n function borrowRatePerBlock() external view override returns (uint256) {\n return interestRateModel.getBorrowRate(_getCashPrior(), totalBorrows, totalReserves, badDebt);\n }\n\n /**\n * @notice Returns the current per-block supply interest rate for this v\n * @return rate The supply interest rate per block, scaled by 1e18\n */\n function supplyRatePerBlock() external view override returns (uint256) {\n return\n interestRateModel.getSupplyRate(\n _getCashPrior(),\n totalBorrows,\n totalReserves,\n reserveFactorMantissa,\n badDebt\n );\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return borrowBalance The calculated balance\n */\n function borrowBalanceStored(address account) external view override returns (uint256) {\n return _borrowBalanceStored(account);\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the VToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() external view override returns (uint256) {\n return _exchangeRateStored();\n }\n\n /**\n * @notice Accrue interest then return the up-to-date exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function exchangeRateCurrent() public override nonReentrant returns (uint256) {\n accrueInterest();\n return _exchangeRateStored();\n }\n\n /**\n * @notice Applies accrued interest to total borrows and reserves\n * @dev This calculates interest accrued from the last checkpointed block\n * up to the current block and writes new checkpoint to storage.\n * @return Always NO_ERROR\n * @custom:event Emits AccrueInterest event on success\n * @custom:access Not restricted\n */\n function accrueInterest() public virtual override returns (uint256) {\n /* Remember the initial block number */\n uint256 currentBlockNumber = _getBlockNumber();\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\n\n /* Short-circuit accumulating 0 interest */\n if (accrualBlockNumberPrior == currentBlockNumber) {\n return NO_ERROR;\n }\n\n /* Read the previous values out of storage */\n uint256 cashPrior = _getCashPrior();\n uint256 borrowsPrior = totalBorrows;\n uint256 reservesPrior = totalReserves;\n uint256 borrowIndexPrior = borrowIndex;\n\n /* Calculate the current borrow interest rate */\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior, badDebt);\n require(borrowRateMantissa <= MAX_BORROW_RATE_MANTISSA, \"borrow rate is absurdly high\");\n\n /* Calculate the number of blocks elapsed since the last accrual */\n uint256 blockDelta = currentBlockNumber - accrualBlockNumberPrior;\n\n /*\n * Calculate the interest accumulated into borrows and reserves and the new index:\n * simpleInterestFactor = borrowRate * blockDelta\n * interestAccumulated = simpleInterestFactor * totalBorrows\n * totalBorrowsNew = interestAccumulated + totalBorrows\n * totalReservesNew = interestAccumulated * reserveFactor + totalReserves\n * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex\n */\n\n Exp memory simpleInterestFactor = mul_(Exp({ mantissa: borrowRateMantissa }), blockDelta);\n uint256 interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior);\n uint256 totalBorrowsNew = interestAccumulated + borrowsPrior;\n uint256 totalReservesNew = mul_ScalarTruncateAddUInt(\n Exp({ mantissa: reserveFactorMantissa }),\n interestAccumulated,\n reservesPrior\n );\n uint256 borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the previously calculated values into storage */\n accrualBlockNumber = currentBlockNumber;\n borrowIndex = borrowIndexNew;\n totalBorrows = totalBorrowsNew;\n totalReserves = totalReservesNew;\n\n /* We emit an AccrueInterest event */\n emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);\n\n return NO_ERROR;\n }\n\n /**\n * @notice User supplies assets into the market and receives vTokens in exchange\n * @dev Assumes interest has already been accrued up to the current block\n * @param payer The address of the account which is sending the assets for supply\n * @param minter The address of the account which is supplying the assets\n * @param mintAmount The amount of the underlying asset to supply\n */\n function _mintFresh(\n address payer,\n address minter,\n uint256 mintAmount\n ) internal {\n /* Fail if mint not allowed */\n comptroller.preMintHook(address(this), minter, mintAmount);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert MintFreshnessCheck();\n }\n\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call `_doTransferIn` for the minter and the mintAmount.\n * `_doTransferIn` reverts if anything goes wrong, since we can't be sure if\n * side-effects occurred. The function returns the amount actually transferred,\n * in case of a fee. On success, the vToken holds an additional `actualMintAmount`\n * of cash.\n */\n uint256 actualMintAmount = _doTransferIn(payer, mintAmount);\n\n /*\n * We get the current exchange rate and calculate the number of vTokens to be minted:\n * mintTokens = actualMintAmount / exchangeRate\n */\n\n uint256 mintTokens = div_(actualMintAmount, exchangeRate);\n\n /*\n * We calculate the new total supply of vTokens and minter token balance, checking for overflow:\n * totalSupplyNew = totalSupply + mintTokens\n * accountTokensNew = accountTokens[minter] + mintTokens\n * And write them into storage\n */\n totalSupply = totalSupply + mintTokens;\n uint256 balanceAfter = accountTokens[minter] + mintTokens;\n accountTokens[minter] = balanceAfter;\n\n /* We emit a Mint event, and a Transfer event */\n emit Mint(minter, actualMintAmount, mintTokens, balanceAfter);\n emit Transfer(address(0), minter, mintTokens);\n }\n\n /**\n * @notice User redeems vTokens in exchange for the underlying asset\n * @dev Assumes interest has already been accrued up to the current block\n * @param redeemer The address of the account which is redeeming the tokens\n * @param redeemTokensIn The number of vTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n * @param redeemAmountIn The number of underlying tokens to receive from redeeming vTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n */\n function _redeemFresh(\n address redeemer,\n uint256 redeemTokensIn,\n uint256 redeemAmountIn\n ) internal {\n require(redeemTokensIn == 0 || redeemAmountIn == 0, \"one of redeemTokensIn or redeemAmountIn must be zero\");\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert RedeemFreshnessCheck();\n }\n\n /* exchangeRate = invoke Exchange Rate Stored() */\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n uint256 redeemTokens;\n uint256 redeemAmount;\n\n /* If redeemTokensIn > 0: */\n if (redeemTokensIn > 0) {\n /*\n * We calculate the exchange rate and the amount of underlying to be redeemed:\n * redeemTokens = redeemTokensIn\n */\n redeemTokens = redeemTokensIn;\n } else {\n /*\n * We get the current exchange rate and calculate the amount to be redeemed:\n * redeemTokens = redeemAmountIn / exchangeRate\n */\n redeemTokens = div_(redeemAmountIn, exchangeRate);\n\n uint256 _redeemAmount = mul_(redeemTokens, exchangeRate);\n if (_redeemAmount != 0 && _redeemAmount != redeemAmountIn) redeemTokens++; // round up\n }\n\n // redeemAmount = exchangeRate * redeemTokens\n redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokens);\n\n // Revert if amount is zero\n if (redeemAmount == 0) {\n revert(\"redeemAmount is zero\");\n }\n\n /* Fail if redeem not allowed */\n comptroller.preRedeemHook(address(this), redeemer, redeemTokens);\n\n /* Fail gracefully if protocol has insufficient cash */\n if (_getCashPrior() - totalReserves < redeemAmount) {\n revert RedeemTransferOutNotPossible();\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We write the previously calculated values into storage.\n * Note: Avoid token reentrancy attacks by writing reduced supply before external transfer.\n */\n totalSupply = totalSupply - redeemTokens;\n uint256 balanceAfter = accountTokens[redeemer] - redeemTokens;\n accountTokens[redeemer] = balanceAfter;\n\n /*\n * We invoke _doTransferOut for the redeemer and the redeemAmount.\n * On success, the vToken has redeemAmount less of cash.\n * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n _doTransferOut(redeemer, redeemAmount);\n\n /* We emit a Transfer event, and a Redeem event */\n emit Transfer(redeemer, address(this), redeemTokens);\n emit Redeem(redeemer, redeemAmount, redeemTokens, balanceAfter);\n }\n\n /**\n * @notice Users borrow assets from the protocol to their own address\n * @param borrower User who borrows the assets\n * @param borrowAmount The amount of the underlying asset to borrow\n */\n function _borrowFresh(address borrower, uint256 borrowAmount) internal {\n /* Fail if borrow not allowed */\n comptroller.preBorrowHook(address(this), borrower, borrowAmount);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert BorrowFreshnessCheck();\n }\n\n /* Fail gracefully if protocol has insufficient underlying cash */\n if (_getCashPrior() - totalReserves < borrowAmount) {\n revert BorrowCashNotAvailable();\n }\n\n /*\n * We calculate the new borrower and total borrow balances, failing on overflow:\n * accountBorrowNew = accountBorrow + borrowAmount\n * totalBorrowsNew = totalBorrows + borrowAmount\n */\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n uint256 accountBorrowsNew = accountBorrowsPrev + borrowAmount;\n uint256 totalBorrowsNew = totalBorrows + borrowAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We write the previously calculated values into storage.\n * Note: Avoid token reentrancy attacks by writing increased borrow before external transfer.\n `*/\n accountBorrows[borrower].principal = accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n /*\n * We invoke _doTransferOut for the borrower and the borrowAmount.\n * On success, the vToken borrowAmount less of cash.\n * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n _doTransferOut(borrower, borrowAmount);\n\n /* We emit a Borrow event */\n emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);\n }\n\n /**\n * @notice Borrows are repaid by another user (possibly the borrower).\n * @param payer the account paying off the borrow\n * @param borrower the account with the debt being payed off\n * @param repayAmount the amount of underlying tokens being returned, or type(uint256).max for the full outstanding amount\n * @return (uint) the actual repayment amount.\n */\n function _repayBorrowFresh(\n address payer,\n address borrower,\n uint256 repayAmount\n ) internal returns (uint256) {\n /* Fail if repayBorrow not allowed */\n comptroller.preRepayHook(address(this), borrower);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert RepayBorrowFreshnessCheck();\n }\n\n /* We fetch the amount the borrower owes, with accumulated interest */\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n\n uint256 repayAmountFinal = repayAmount >= accountBorrowsPrev ? accountBorrowsPrev : repayAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call _doTransferIn for the payer and the repayAmount\n * On success, the vToken holds an additional repayAmount of cash.\n * _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n * it returns the amount actually transferred, in case of a fee.\n */\n uint256 actualRepayAmount = _doTransferIn(payer, repayAmountFinal);\n\n /*\n * We calculate the new borrower and total borrow balances, failing on underflow:\n * accountBorrowsNew = accountBorrows - actualRepayAmount\n * totalBorrowsNew = totalBorrows - actualRepayAmount\n */\n uint256 accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;\n uint256 totalBorrowsNew = totalBorrows - actualRepayAmount;\n\n /* We write the previously calculated values into storage */\n accountBorrows[borrower].principal = accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n /* We emit a RepayBorrow event */\n emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew);\n\n return actualRepayAmount;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n */\n function _liquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) internal nonReentrant {\n accrueInterest();\n\n uint256 error = vTokenCollateral.accrueInterest();\n if (error != NO_ERROR) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed\n revert LiquidateAccrueCollateralInterestFailed(error);\n }\n\n // _liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\n _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n /**\n * @notice The liquidator liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n */\n function _liquidateBorrowFresh(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) internal {\n /* Fail if liquidate not allowed */\n comptroller.preLiquidateHook(\n address(this),\n address(vTokenCollateral),\n borrower,\n repayAmount,\n skipLiquidityCheck\n );\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert LiquidateFreshnessCheck();\n }\n\n /* Verify vTokenCollateral market's block number equals current block number */\n if (vTokenCollateral.accrualBlockNumber() != _getBlockNumber()) {\n revert LiquidateCollateralFreshnessCheck();\n }\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n revert LiquidateLiquidatorIsBorrower();\n }\n\n /* Fail if repayAmount = 0 */\n if (repayAmount == 0) {\n revert LiquidateCloseAmountIsZero();\n }\n\n /* Fail if repayAmount = type(uint256).max */\n if (repayAmount == type(uint256).max) {\n revert LiquidateCloseAmountIsUintMax();\n }\n\n /* Fail if repayBorrow fails */\n uint256 actualRepayAmount = _repayBorrowFresh(liquidator, borrower, repayAmount);\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We calculate the number of collateral tokens that will be seized */\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller.liquidateCalculateSeizeTokens(\n address(this),\n address(vTokenCollateral),\n actualRepayAmount\n );\n require(amountSeizeError == NO_ERROR, \"LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED\");\n\n /* Revert if borrower collateral token balance < seizeTokens */\n require(vTokenCollateral.balanceOf(borrower) >= seizeTokens, \"LIQUIDATE_SEIZE_TOO_MUCH\");\n\n // If this is also the collateral, call _seize internally to avoid re-entrancy, otherwise make an external call\n if (address(vTokenCollateral) == address(this)) {\n _seize(address(this), liquidator, borrower, seizeTokens);\n } else {\n vTokenCollateral.seize(liquidator, borrower, seizeTokens);\n }\n\n /* We emit a LiquidateBorrow event */\n emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(vTokenCollateral), seizeTokens);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another VToken.\n * It's absolutely critical to use msg.sender as the seizer vToken and not a parameter.\n * @param seizerContract The contract seizing the collateral (either borrowed vToken or Comptroller)\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of vTokens to seize\n */\n function _seize(\n address seizerContract,\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) internal {\n /* Fail if seize not allowed */\n comptroller.preSeizeHook(address(this), seizerContract, liquidator, borrower);\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n revert LiquidateSeizeLiquidatorIsBorrower();\n }\n\n /*\n * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\n * borrowerTokensNew = accountTokens[borrower] - seizeTokens\n * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\n */\n uint256 liquidationIncentiveMantissa = ComptrollerViewInterface(address(comptroller))\n .liquidationIncentiveMantissa();\n uint256 numerator = mul_(seizeTokens, Exp({ mantissa: protocolSeizeShareMantissa }));\n uint256 protocolSeizeTokens = div_(numerator, Exp({ mantissa: liquidationIncentiveMantissa }));\n uint256 liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n uint256 protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens);\n uint256 totalReservesNew = totalReserves + protocolSeizeAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the calculated values into storage */\n totalReserves = totalReservesNew;\n totalSupply = totalSupply - protocolSeizeTokens;\n accountTokens[borrower] = accountTokens[borrower] - seizeTokens;\n accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens;\n\n /* Emit a Transfer event */\n emit Transfer(borrower, liquidator, liquidatorSeizeTokens);\n emit Transfer(borrower, address(this), protocolSeizeTokens);\n emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew);\n }\n\n function _setComptroller(ComptrollerInterface newComptroller) internal {\n ComptrollerInterface oldComptroller = comptroller;\n // Ensure invoke comptroller.isComptroller() returns true\n require(newComptroller.isComptroller(), \"marker method returned false\");\n\n // Set market's comptroller to newComptroller\n comptroller = newComptroller;\n\n // Emit NewComptroller(oldComptroller, newComptroller)\n emit NewComptroller(oldComptroller, newComptroller);\n }\n\n /**\n * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)\n * @dev Admin function to set a new reserve factor\n * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n */\n function _setReserveFactorFresh(uint256 newReserveFactorMantissa) internal {\n // Verify market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert SetReserveFactorFreshCheck();\n }\n\n // Check newReserveFactor ≤ maxReserveFactor\n if (newReserveFactorMantissa > MAX_RESERVE_FACTOR_MANTISSA) {\n revert SetReserveFactorBoundsCheck();\n }\n\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\n reserveFactorMantissa = newReserveFactorMantissa;\n\n emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);\n }\n\n /**\n * @notice Add reserves by transferring from caller\n * @dev Requires fresh interest accrual\n * @param addAmount Amount of addition to reserves\n * @return actualAddAmount The actual amount added, excluding the potential token fees\n */\n function _addReservesFresh(uint256 addAmount) internal returns (uint256) {\n // totalReserves + actualAddAmount\n uint256 totalReservesNew;\n uint256 actualAddAmount;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert AddReservesFactorFreshCheck(actualAddAmount);\n }\n\n actualAddAmount = _doTransferIn(msg.sender, addAmount);\n totalReservesNew = totalReserves + actualAddAmount;\n totalReserves = totalReservesNew;\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\n\n return actualAddAmount;\n }\n\n /**\n * @notice Reduces reserves by transferring to the protocol reserve contract\n * @dev Requires fresh interest accrual\n * @param reduceAmount Amount of reduction to reserves\n */\n function _reduceReservesFresh(uint256 reduceAmount) internal {\n // totalReserves - reduceAmount\n uint256 totalReservesNew;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert ReduceReservesFreshCheck();\n }\n\n // Fail gracefully if protocol has insufficient underlying cash\n if (_getCashPrior() < reduceAmount) {\n revert ReduceReservesCashNotAvailable();\n }\n\n // Check reduceAmount ≤ reserves[n] (totalReserves)\n if (reduceAmount > totalReserves) {\n revert ReduceReservesCashValidation();\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n totalReservesNew = totalReserves - reduceAmount;\n\n // Store reserves[n+1] = reserves[n] - reduceAmount\n totalReserves = totalReservesNew;\n\n // _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n // Transferring an underlying asset to the protocolShareReserve contract to channel the funds for different use.\n _doTransferOut(protocolShareReserve, reduceAmount);\n\n // Update the pool asset's state in the protocol share reserve for the above transfer.\n IProtocolShareReserve(protocolShareReserve).updateAssetsState(address(comptroller), underlying);\n\n emit ReservesReduced(protocolShareReserve, reduceAmount, totalReservesNew);\n }\n\n /**\n * @notice updates the interest rate model (*requires fresh interest accrual)\n * @dev Admin function to update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n */\n function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal {\n // Used to store old model for use in the event that is emitted on success\n InterestRateModel oldInterestRateModel;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert SetInterestRateModelFreshCheck();\n }\n\n // Track the market's current interest rate model\n oldInterestRateModel = interestRateModel;\n\n // Ensure invoke newInterestRateModel.isInterestRateModel() returns true\n require(newInterestRateModel.isInterestRateModel(), \"marker method returned false\");\n\n // Set the interest rate model to newInterestRateModel\n interestRateModel = newInterestRateModel;\n\n // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)\n emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);\n }\n\n /*** Safe Token ***/\n\n /**\n * @dev Similar to ERC-20 transfer, but handles tokens that have transfer fees.\n * This function returns the actual amount received,\n * which may be less than `amount` if there is a fee attached to the transfer.\n * @param from Sender of the underlying tokens\n * @param amount Amount of underlying to transfer\n * @return Actual amount received\n */\n function _doTransferIn(address from, uint256 amount) internal virtual returns (uint256) {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n uint256 balanceBefore = token.balanceOf(address(this));\n token.safeTransferFrom(from, address(this), amount);\n uint256 balanceAfter = token.balanceOf(address(this));\n // Return the amount that was *actually* transferred\n return balanceAfter - balanceBefore;\n }\n\n /**\n * @dev Just a regular ERC-20 transfer, reverts on failure\n * @param to Receiver of the underlying tokens\n * @param amount Amount of underlying to transfer\n */\n function _doTransferOut(address to, uint256 amount) internal virtual {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n token.safeTransfer(to, amount);\n }\n\n /**\n * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`\n * @dev Called by both `transfer` and `transferFrom` internally\n * @param spender The address of the account performing the transfer\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param tokens The number of tokens to transfer\n */\n function _transferTokens(\n address spender,\n address src,\n address dst,\n uint256 tokens\n ) internal {\n /* Fail if transfer not allowed */\n comptroller.preTransferHook(address(this), src, dst, tokens);\n\n /* Do not allow self-transfers */\n if (src == dst) {\n revert TransferNotAllowed();\n }\n\n /* Get the allowance, infinite for the account owner */\n uint256 startingAllowance;\n if (spender == src) {\n startingAllowance = type(uint256).max;\n } else {\n startingAllowance = transferAllowances[src][spender];\n }\n\n /* Do the calculations, checking for {under,over}flow */\n uint256 allowanceNew = startingAllowance - tokens;\n uint256 srcTokensNew = accountTokens[src] - tokens;\n uint256 dstTokensNew = accountTokens[dst] + tokens;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n\n accountTokens[src] = srcTokensNew;\n accountTokens[dst] = dstTokensNew;\n\n /* Eat some of the allowance (if necessary) */\n if (startingAllowance != type(uint256).max) {\n transferAllowances[src][spender] = allowanceNew;\n }\n\n /* We emit a Transfer event */\n emit Transfer(src, dst, tokens);\n }\n\n /**\n * @notice Initialize the money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param accessControlManager_ AccessControlManager contract address\n * @param riskManagement Addresses of risk & income related contracts\n * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n */\n function _initialize(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n require(accrualBlockNumber == 0 && borrowIndex == 0, \"market may only be initialized once\");\n\n // Set initial exchange rate\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\n require(initialExchangeRateMantissa > 0, \"initial exchange rate must be greater than zero.\");\n\n _setComptroller(comptroller_);\n\n // Initialize block number and borrow index (block number mocks depend on comptroller being set)\n accrualBlockNumber = _getBlockNumber();\n borrowIndex = MANTISSA_ONE;\n\n // Set the interest rate model (depends on block number / borrow index)\n _setInterestRateModelFresh(interestRateModel_);\n\n _setReserveFactorFresh(reserveFactorMantissa_);\n\n name = name_;\n symbol = symbol_;\n decimals = decimals_;\n _setShortfallContract(riskManagement.shortfall);\n _setProtocolShareReserve(riskManagement.protocolShareReserve);\n protocolSeizeShareMantissa = DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA;\n\n // Set underlying and sanity check it\n underlying = underlying_;\n IERC20Upgradeable(underlying).totalSupply();\n\n // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\n _notEntered = true;\n _transferOwnership(admin_);\n }\n\n function _setShortfallContract(address shortfall_) internal {\n ensureNonzeroAddress(shortfall_);\n address oldShortfall = shortfall;\n shortfall = shortfall_;\n emit NewShortfallContract(oldShortfall, shortfall_);\n }\n\n function _setProtocolShareReserve(address payable protocolShareReserve_) internal {\n ensureNonzeroAddress(protocolShareReserve_);\n address oldProtocolShareReserve = address(protocolShareReserve);\n protocolShareReserve = protocolShareReserve_;\n emit NewProtocolShareReserve(oldProtocolShareReserve, address(protocolShareReserve_));\n }\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying tokens owned by this contract\n */\n function _getCashPrior() internal view virtual returns (uint256) {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n return token.balanceOf(address(this));\n }\n\n /**\n * @dev Function to simply retrieve block number\n * This exists mainly for inheriting test contracts to stub this result.\n * @return Current block number\n */\n function _getBlockNumber() internal view virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return borrowBalance the calculated balance\n */\n function _borrowBalanceStored(address account) internal view returns (uint256) {\n /* Get borrowBalance and borrowIndex */\n BorrowSnapshot memory borrowSnapshot = accountBorrows[account];\n\n /* If borrowBalance = 0 then borrowIndex is likely also 0.\n * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.\n */\n if (borrowSnapshot.principal == 0) {\n return 0;\n }\n\n /* Calculate new borrow balance using the interest index:\n * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex\n */\n uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex;\n\n return principalTimesIndex / borrowSnapshot.interestIndex;\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the VToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function _exchangeRateStored() internal view virtual returns (uint256) {\n uint256 _totalSupply = totalSupply;\n if (_totalSupply == 0) {\n /*\n * If there are no tokens minted:\n * exchangeRate = initialExchangeRate\n */\n return initialExchangeRateMantissa;\n }\n /*\n * Otherwise:\n * exchangeRate = (totalCash + totalBorrows + badDebt - totalReserves) / totalSupply\n */\n uint256 totalCash = _getCashPrior();\n uint256 cashPlusBorrowsMinusReserves = totalCash + totalBorrows + badDebt - totalReserves;\n uint256 exchangeRate = (cashPlusBorrowsMinusReserves * EXP_SCALE) / _totalSupply;\n\n return exchangeRate;\n }\n}\n" + }, + "contracts/VTokenInterfaces.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\n\n/**\n * @title VTokenStorage\n * @author Venus\n * @notice Storage layout used by the `VToken` contract\n */\n// solhint-disable-next-line max-states-count\ncontract VTokenStorage {\n /**\n * @notice Container for borrow balance information\n * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action\n * @member interestIndex Global borrowIndex as of the most recent balance-changing action\n */\n struct BorrowSnapshot {\n uint256 principal;\n uint256 interestIndex;\n }\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n bool internal _notEntered;\n\n /**\n * @notice Underlying asset for this VToken\n */\n address public underlying;\n\n /**\n * @notice EIP-20 token name for this token\n */\n string public name;\n\n /**\n * @notice EIP-20 token symbol for this token\n */\n string public symbol;\n\n /**\n * @notice EIP-20 token decimals for this token\n */\n uint8 public decimals;\n\n /**\n * @notice Protocol share Reserve contract address\n */\n address payable public protocolShareReserve;\n\n // Maximum borrow rate that can ever be applied (.0005% / block)\n uint256 internal constant MAX_BORROW_RATE_MANTISSA = 0.0005e16;\n\n // Maximum fraction of interest that can be set aside for reserves\n uint256 internal constant MAX_RESERVE_FACTOR_MANTISSA = 1e18;\n\n /**\n * @notice Contract which oversees inter-vToken operations\n */\n ComptrollerInterface public comptroller;\n\n /**\n * @notice Model which tells what the current interest rate should be\n */\n InterestRateModel public interestRateModel;\n\n // Initial exchange rate used when minting the first VTokens (used when totalSupply = 0)\n uint256 internal initialExchangeRateMantissa;\n\n /**\n * @notice Fraction of interest currently set aside for reserves\n */\n uint256 public reserveFactorMantissa;\n\n /**\n * @notice Block number that interest was last accrued at\n */\n uint256 public accrualBlockNumber;\n\n /**\n * @notice Accumulator of the total earned interest rate since the opening of the market\n */\n uint256 public borrowIndex;\n\n /**\n * @notice Total amount of outstanding borrows of the underlying in this market\n */\n uint256 public totalBorrows;\n\n /**\n * @notice Total amount of reserves of the underlying held in this market\n */\n uint256 public totalReserves;\n\n /**\n * @notice Total number of tokens in circulation\n */\n uint256 public totalSupply;\n\n /**\n * @notice Total bad debt of the market\n */\n uint256 public badDebt;\n\n // Official record of token balances for each account\n mapping(address => uint256) internal accountTokens;\n\n // Approved token transfer amounts on behalf of others\n mapping(address => mapping(address => uint256)) internal transferAllowances;\n\n // Mapping of account addresses to outstanding borrow balances\n mapping(address => BorrowSnapshot) internal accountBorrows;\n\n /**\n * @notice Share of seized collateral that is added to reserves\n */\n uint256 public protocolSeizeShareMantissa;\n\n /**\n * @notice Storage of Shortfall contract address\n */\n address public shortfall;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n\n/**\n * @title VTokenInterface\n * @author Venus\n * @notice Interface implemented by the `VToken` contract\n */\nabstract contract VTokenInterface is VTokenStorage {\n struct RiskManagementInit {\n address shortfall;\n address payable protocolShareReserve;\n }\n\n /*** Market Events ***/\n\n /**\n * @notice Event emitted when interest is accrued\n */\n event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when tokens are minted\n */\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens, uint256 accountBalance);\n\n /**\n * @notice Event emitted when tokens are redeemed\n */\n event Redeem(address indexed redeemer, uint256 redeemAmount, uint256 redeemTokens, uint256 accountBalance);\n\n /**\n * @notice Event emitted when underlying is borrowed\n */\n event Borrow(address indexed borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when a borrow is repaid\n */\n event RepayBorrow(\n address indexed payer,\n address indexed borrower,\n uint256 repayAmount,\n uint256 accountBorrows,\n uint256 totalBorrows\n );\n\n /**\n * @notice Event emitted when bad debt is accumulated on a market\n * @param borrower borrower to \"forgive\"\n * @param badDebtDelta amount of new bad debt recorded\n * @param badDebtOld previous bad debt value\n * @param badDebtNew new bad debt value\n */\n event BadDebtIncreased(address indexed borrower, uint256 badDebtDelta, uint256 badDebtOld, uint256 badDebtNew);\n\n /**\n * @notice Event emitted when bad debt is recovered via an auction\n * @param badDebtOld previous bad debt value\n * @param badDebtNew new bad debt value\n */\n event BadDebtRecovered(uint256 badDebtOld, uint256 badDebtNew);\n\n /**\n * @notice Event emitted when a borrow is liquidated\n */\n event LiquidateBorrow(\n address indexed liquidator,\n address indexed borrower,\n uint256 repayAmount,\n address indexed vTokenCollateral,\n uint256 seizeTokens\n );\n\n /*** Admin Events ***/\n\n /**\n * @notice Event emitted when comptroller is changed\n */\n event NewComptroller(ComptrollerInterface indexed oldComptroller, ComptrollerInterface indexed newComptroller);\n\n /**\n * @notice Event emitted when shortfall contract address is changed\n */\n event NewShortfallContract(address indexed oldShortfall, address indexed newShortfall);\n\n /**\n * @notice Event emitted when protocol share reserve contract address is changed\n */\n event NewProtocolShareReserve(address indexed oldProtocolShareReserve, address indexed newProtocolShareReserve);\n\n /**\n * @notice Event emitted when interestRateModel is changed\n */\n event NewMarketInterestRateModel(\n InterestRateModel indexed oldInterestRateModel,\n InterestRateModel indexed newInterestRateModel\n );\n\n /**\n * @notice Event emitted when protocol seize share is changed\n */\n event NewProtocolSeizeShare(uint256 oldProtocolSeizeShareMantissa, uint256 newProtocolSeizeShareMantissa);\n\n /**\n * @notice Event emitted when the reserve factor is changed\n */\n event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa);\n\n /**\n * @notice Event emitted when the reserves are added\n */\n event ReservesAdded(address indexed benefactor, uint256 addAmount, uint256 newTotalReserves);\n\n /**\n * @notice Event emitted when the reserves are reduced\n */\n event ReservesReduced(address indexed admin, uint256 reduceAmount, uint256 newTotalReserves);\n\n /**\n * @notice EIP20 Transfer event\n */\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n /**\n * @notice EIP20 Approval event\n */\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /**\n * @notice Event emitted when healing the borrow\n */\n event HealBorrow(address indexed payer, address indexed borrower, uint256 repayAmount);\n\n /**\n * @notice Event emitted when tokens are swept\n */\n event SweepToken(address indexed token);\n\n /*** User Interface ***/\n\n function mint(uint256 mintAmount) external virtual returns (uint256);\n\n function mintBehalf(address minter, uint256 mintAllowed) external virtual returns (uint256);\n\n function redeem(uint256 redeemTokens) external virtual returns (uint256);\n\n function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256);\n\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\n\n function repayBorrow(uint256 repayAmount) external virtual returns (uint256);\n\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256);\n\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral\n ) external virtual returns (uint256);\n\n function healBorrow(\n address payer,\n address borrower,\n uint256 repayAmount\n ) external virtual;\n\n function forceLiquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipCloseFactorCheck\n ) external virtual;\n\n function seize(\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external virtual;\n\n function transfer(address dst, uint256 amount) external virtual returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external virtual returns (bool);\n\n function accrueInterest() external virtual returns (uint256);\n\n function sweepToken(IERC20Upgradeable token) external virtual;\n\n /*** Admin Functions ***/\n\n function setReserveFactor(uint256 newReserveFactorMantissa) external virtual;\n\n function reduceReserves(uint256 reduceAmount) external virtual;\n\n function exchangeRateCurrent() external virtual returns (uint256);\n\n function borrowBalanceCurrent(address account) external virtual returns (uint256);\n\n function setInterestRateModel(InterestRateModel newInterestRateModel) external virtual;\n\n function addReserves(uint256 addAmount) external virtual;\n\n function totalBorrowsCurrent() external virtual returns (uint256);\n\n function balanceOfUnderlying(address owner) external virtual returns (uint256);\n\n function approve(address spender, uint256 amount) external virtual returns (bool);\n\n function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool);\n\n function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool);\n\n function allowance(address owner, address spender) external view virtual returns (uint256);\n\n function balanceOf(address owner) external view virtual returns (uint256);\n\n function getAccountSnapshot(address account)\n external\n view\n virtual\n returns (\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function borrowRatePerBlock() external view virtual returns (uint256);\n\n function supplyRatePerBlock() external view virtual returns (uint256);\n\n function borrowBalanceStored(address account) external view virtual returns (uint256);\n\n function exchangeRateStored() external view virtual returns (uint256);\n\n function getCash() external view virtual returns (uint256);\n\n /**\n * @notice Indicator that this is a VToken contract (for inspection)\n * @return Always true\n */\n function isVToken() external pure virtual returns (bool) {\n return true;\n }\n}\n" + }, + "contracts/WhitePaperInterestRateModel.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { BLOCKS_PER_YEAR, EXP_SCALE, MANTISSA_ONE } from \"./lib/constants.sol\";\n\n/**\n * @title Compound's WhitePaperInterestRateModel Contract\n * @author Compound\n * @notice The parameterized model described in section 2.4 of the original Compound Protocol whitepaper\n */\ncontract WhitePaperInterestRateModel is InterestRateModel {\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public immutable multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public immutable baseRatePerBlock;\n\n event NewInterestParams(uint256 baseRatePerBlock, uint256 multiplierPerBlock);\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n */\n constructor(uint256 baseRatePerYear, uint256 multiplierPerYear) {\n baseRatePerBlock = baseRatePerYear / BLOCKS_PER_YEAR;\n multiplierPerBlock = multiplierPerYear / BLOCKS_PER_YEAR;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock);\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public view override returns (uint256) {\n uint256 ur = utilizationRate(cash, borrows, reserves, badDebt);\n return ((ur * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) public view override returns (uint256) {\n uint256 oneMinusReserveFactor = MANTISSA_ONE - reserveFactorMantissa;\n uint256 borrowRate = getBorrowRate(cash, borrows, reserves, badDebt);\n uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / EXP_SCALE;\n uint256 incomeToDistribute = borrows * rateToPool;\n uint256 supply = cash + borrows + badDebt - reserves;\n return incomeToDistribute / supply;\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `(borrows + badDebt) / (cash + borrows + badDebt - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @param badDebt The amount of badDebt in the market\n * @return The utilization rate as a mantissa between [0, MANTISSA_ONE]\n */\n function utilizationRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public pure returns (uint256) {\n // Utilization rate is 0 when there are no borrows and badDebt\n if ((borrows + badDebt) == 0) {\n return 0;\n }\n\n uint256 rate = ((borrows + badDebt) * EXP_SCALE) / (cash + borrows + badDebt - reserves);\n\n if (rate > EXP_SCALE) {\n rate = EXP_SCALE;\n }\n\n return rate;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200, + "details": { + "yul": true + } + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/bscmainnet_addresses.json b/deployments/bscmainnet_addresses.json index 8f3e502f8..61f476ec5 100644 --- a/deployments/bscmainnet_addresses.json +++ b/deployments/bscmainnet_addresses.json @@ -81,6 +81,7 @@ "VToken_vRACA_GameFi": "0xE5FE5527A5b76C75eedE77FdFA6B80D52444A465", "VToken_vSnBNB_LiquidStakedBNB": "0xd3CC9d8f3689B83c91b7B59cAB4946B063EB894A", "VToken_vTRX_Tron": "0x836beb2cB723C498136e1119248436A645845F4E", + "VToken_vTWT_DeFi": "0x736bf1D21A28b5DC19A1aC8cA71Fc2856C23c03F", "VToken_vUSDD_DeFi": "0xA615467caE6B9E0bb98BC04B4411d9296fd1dFa0", "VToken_vUSDD_GameFi": "0x9f2FD23bd0A5E08C5f2b9DD6CF9C96Bfb5fA515C", "VToken_vUSDD_LiquidStakedBNB": "0x3ee4be3425e5CC72445cd4C5325A6B5A15507670", diff --git a/deployments/bsctestnet.json b/deployments/bsctestnet.json index 39846eb7b..b2e43ff60 100644 --- a/deployments/bsctestnet.json +++ b/deployments/bsctestnet.json @@ -9047,6 +9047,624 @@ } ] }, + "MockTHE": { + "address": "0xB1cbD28Cb101c87b5F94a14A8EF081EA7F985593", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "faucet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] + }, + "MockTWT": { + "address": "0xb99c6b26fdf3678c6e2aff8466e3625a0e7182f8", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "faucet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ] + }, "MockUSDD": { "address": "0x2E2466e22FcbE0732Be385ee2FBb9C59a1098382", "abi": [ @@ -51829,6 +52447,80 @@ } ] }, + "VToken_vTWT_DeFi": { + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "beacon", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ] + }, "VToken_vUSDD_DeFi": { "address": "0xa109DE0abaeefC521Ec29D89eA42E64F37A6882E", "abi": [ diff --git a/deployments/bsctestnet/MockTHE.json b/deployments/bsctestnet/MockTHE.json new file mode 100644 index 000000000..5e36ada63 --- /dev/null +++ b/deployments/bsctestnet/MockTHE.json @@ -0,0 +1,450 @@ +{ + "address": "0xB1cbD28Cb101c87b5F94a14A8EF081EA7F985593", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "faucet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x8c15afee01b1f2543600cfb7a8a4cbe48d685421027ad8a8cd9c81f304342873", + "receipt": { + "to": null, + "from": "0x03862dFa5D0be8F64509C001cb8C6188194469DF", + "contractAddress": "0xB1cbD28Cb101c87b5F94a14A8EF081EA7F985593", + "transactionIndex": 3, + "gasUsed": "635956", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x77fc799254f7eae96aad28c93f15f158a803d1a29bdf97d736928ccd8c5d9392", + "transactionHash": "0x8c15afee01b1f2543600cfb7a8a4cbe48d685421027ad8a8cd9c81f304342873", + "logs": [], + "blockNumber": 32693684, + "cumulativeGasUsed": "779647", + "status": 1, + "byzantium": true + }, + "args": ["THENA", "THE", 18], + "numDeployments": 1, + "solcInputHash": "fe42e787f43c7b3c0c64f0274853de01", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"faucet\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"See {IERC20-allowance}.\"},\"approve(address,uint256)\":{\"details\":\"See {IERC20-approve}. NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address.\"},\"balanceOf(address)\":{\"details\":\"See {IERC20-balanceOf}.\"},\"decimals()\":{\"details\":\"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5.05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the default value returned by this function, unless it's overridden. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}.\"},\"decreaseAllowance(address,uint256)\":{\"details\":\"Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`.\"},\"increaseAllowance(address,uint256)\":{\"details\":\"Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address.\"},\"name()\":{\"details\":\"Returns the name of the token.\"},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See {IERC20-totalSupply}.\"},\"transfer(address,uint256)\":{\"details\":\"See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `amount`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `amount`. - the caller must have allowance for ``from``'s tokens of at least `amount`.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/test/Mocks/MockToken.sol\":\"MockToken\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * The default value of {decimals} is 18. To change this, you should override\\n * this function so it returns a different value.\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the default value returned by this function, unless\\n * it's overridden.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(address from, address to, uint256 amount) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(address owner, address spender, uint256 amount) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\\n}\\n\",\"keccak256\":\"0xa56ca923f70c1748830700250b19c61b70db9a683516dc5e216694a50445d99c\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\\n}\\n\",\"keccak256\":\"0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"contracts/test/Mocks/MockToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport { ERC20 } from \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\n\\ncontract MockToken is ERC20 {\\n uint8 private immutable _decimals;\\n\\n constructor(\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) ERC20(name_, symbol_) {\\n _decimals = decimals_;\\n }\\n\\n function faucet(uint256 amount) external {\\n _mint(msg.sender, amount);\\n }\\n\\n function decimals() public view virtual override returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0x12742c274df06975fbf8e8a23a1adc14ff9475ac7276be6b1b6e86260caca60a\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a06040523480156200001157600080fd5b5060405162000c4838038062000c488339810160408190526200003491620001e8565b8251839083906200004d90600390602085019062000075565b5080516200006390600490602084019062000075565b50505060ff1660805250620002a99050565b82805462000083906200026d565b90600052602060002090601f016020900481019282620000a75760008555620000f2565b82601f10620000c257805160ff1916838001178555620000f2565b82800160010185558215620000f2579182015b82811115620000f2578251825591602001919060010190620000d5565b506200010092915062000104565b5090565b5b8082111562000100576000815560010162000105565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200014357600080fd5b81516001600160401b03808211156200016057620001606200011b565b604051601f8301601f19908116603f011681019082821181831017156200018b576200018b6200011b565b81604052838152602092508683858801011115620001a857600080fd5b600091505b83821015620001cc5785820183015181830184015290820190620001ad565b83821115620001de5760008385830101525b9695505050505050565b600080600060608486031215620001fe57600080fd5b83516001600160401b03808211156200021657600080fd5b620002248783880162000131565b945060208601519150808211156200023b57600080fd5b506200024a8682870162000131565b925050604084015160ff811681146200026257600080fd5b809150509250925092565b600181811c908216806200028257607f821691505b602082108103620002a357634e487b7160e01b600052602260045260246000fd5b50919050565b608051610983620002c5600039600061012601526109836000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c80635791589711610071578063579158971461016357806370a082311461017857806395d89b41146101a1578063a457c2d7146101a9578063a9059cbb146101bc578063dd62ed3e146101cf57600080fd5b806306fdde03146100b9578063095ea7b3146100d757806318160ddd146100fa57806323b872dd1461010c578063313ce5671461011f5780633950935114610150575b600080fd5b6100c16101e2565b6040516100ce91906107a8565b60405180910390f35b6100ea6100e5366004610819565b610274565b60405190151581526020016100ce565b6002545b6040519081526020016100ce565b6100ea61011a366004610843565b61028c565b60405160ff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100ce565b6100ea61015e366004610819565b6102b0565b61017661017136600461087f565b6102d2565b005b6100fe610186366004610898565b6001600160a01b031660009081526020819052604090205490565b6100c16102df565b6100ea6101b7366004610819565b6102ee565b6100ea6101ca366004610819565b61036e565b6100fe6101dd3660046108ba565b61037c565b6060600380546101f1906108ed565b80601f016020809104026020016040519081016040528092919081815260200182805461021d906108ed565b801561026a5780601f1061023f5761010080835404028352916020019161026a565b820191906000526020600020905b81548152906001019060200180831161024d57829003601f168201915b5050505050905090565b6000336102828185856103a7565b5060019392505050565b60003361029a8582856104cb565b6102a5858585610545565b506001949350505050565b6000336102828185856102c3838361037c565b6102cd9190610927565b6103a7565b6102dc33826106e9565b50565b6060600480546101f1906108ed565b600033816102fc828661037c565b9050838110156103615760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102a582868684036103a7565b600033610282818585610545565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104095760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610358565b6001600160a01b03821661046a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610358565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006104d7848461037c565b9050600019811461053f57818110156105325760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610358565b61053f84848484036103a7565b50505050565b6001600160a01b0383166105a95760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610358565b6001600160a01b03821661060b5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610358565b6001600160a01b038316600090815260208190526040902054818110156106835760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610358565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361053f565b6001600160a01b03821661073f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610358565b80600260008282546107519190610927565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b818110156107d5578581018301518582016040015282016107b9565b818111156107e7576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461081457600080fd5b919050565b6000806040838503121561082c57600080fd5b610835836107fd565b946020939093013593505050565b60008060006060848603121561085857600080fd5b610861846107fd565b925061086f602085016107fd565b9150604084013590509250925092565b60006020828403121561089157600080fd5b5035919050565b6000602082840312156108aa57600080fd5b6108b3826107fd565b9392505050565b600080604083850312156108cd57600080fd5b6108d6836107fd565b91506108e4602084016107fd565b90509250929050565b600181811c9082168061090157607f821691505b60208210810361092157634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561094857634e487b7160e01b600052601160045260246000fd5b50019056fea2646970667358221220ad3749d07ad778d94ced64a644949d79ddd48e1fb7564746812dce99fc30b8ce64736f6c634300080d0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100b45760003560e01c80635791589711610071578063579158971461016357806370a082311461017857806395d89b41146101a1578063a457c2d7146101a9578063a9059cbb146101bc578063dd62ed3e146101cf57600080fd5b806306fdde03146100b9578063095ea7b3146100d757806318160ddd146100fa57806323b872dd1461010c578063313ce5671461011f5780633950935114610150575b600080fd5b6100c16101e2565b6040516100ce91906107a8565b60405180910390f35b6100ea6100e5366004610819565b610274565b60405190151581526020016100ce565b6002545b6040519081526020016100ce565b6100ea61011a366004610843565b61028c565b60405160ff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100ce565b6100ea61015e366004610819565b6102b0565b61017661017136600461087f565b6102d2565b005b6100fe610186366004610898565b6001600160a01b031660009081526020819052604090205490565b6100c16102df565b6100ea6101b7366004610819565b6102ee565b6100ea6101ca366004610819565b61036e565b6100fe6101dd3660046108ba565b61037c565b6060600380546101f1906108ed565b80601f016020809104026020016040519081016040528092919081815260200182805461021d906108ed565b801561026a5780601f1061023f5761010080835404028352916020019161026a565b820191906000526020600020905b81548152906001019060200180831161024d57829003601f168201915b5050505050905090565b6000336102828185856103a7565b5060019392505050565b60003361029a8582856104cb565b6102a5858585610545565b506001949350505050565b6000336102828185856102c3838361037c565b6102cd9190610927565b6103a7565b6102dc33826106e9565b50565b6060600480546101f1906108ed565b600033816102fc828661037c565b9050838110156103615760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102a582868684036103a7565b600033610282818585610545565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104095760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610358565b6001600160a01b03821661046a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610358565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006104d7848461037c565b9050600019811461053f57818110156105325760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610358565b61053f84848484036103a7565b50505050565b6001600160a01b0383166105a95760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610358565b6001600160a01b03821661060b5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610358565b6001600160a01b038316600090815260208190526040902054818110156106835760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610358565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361053f565b6001600160a01b03821661073f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610358565b80600260008282546107519190610927565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b818110156107d5578581018301518582016040015282016107b9565b818111156107e7576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461081457600080fd5b919050565b6000806040838503121561082c57600080fd5b610835836107fd565b946020939093013593505050565b60008060006060848603121561085857600080fd5b610861846107fd565b925061086f602085016107fd565b9150604084013590509250925092565b60006020828403121561089157600080fd5b5035919050565b6000602082840312156108aa57600080fd5b6108b3826107fd565b9392505050565b600080604083850312156108cd57600080fd5b6108d6836107fd565b91506108e4602084016107fd565b90509250929050565b600181811c9082168061090157607f821691505b60208210810361092157634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561094857634e487b7160e01b600052601160045260246000fd5b50019056fea2646970667358221220ad3749d07ad778d94ced64a644949d79ddd48e1fb7564746812dce99fc30b8ce64736f6c634300080d0033", + "devdoc": { + "kind": "dev", + "methods": { + "allowance(address,address)": { + "details": "See {IERC20-allowance}." + }, + "approve(address,uint256)": { + "details": "See {IERC20-approve}. NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address." + }, + "balanceOf(address)": { + "details": "See {IERC20-balanceOf}." + }, + "decimals()": { + "details": "Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5.05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the default value returned by this function, unless it's overridden. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}." + }, + "decreaseAllowance(address,uint256)": { + "details": "Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`." + }, + "increaseAllowance(address,uint256)": { + "details": "Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address." + }, + "name()": { + "details": "Returns the name of the token." + }, + "symbol()": { + "details": "Returns the symbol of the token, usually a shorter version of the name." + }, + "totalSupply()": { + "details": "See {IERC20-totalSupply}." + }, + "transfer(address,uint256)": { + "details": "See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `amount`." + }, + "transferFrom(address,address,uint256)": { + "details": "See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `amount`. - the caller must have allowance for ``from``'s tokens of at least `amount`." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 2454, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_balances", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 2460, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_allowances", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" + }, + { + "astId": 2462, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_totalSupply", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 2464, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_name", + "offset": 0, + "slot": "3", + "type": "t_string_storage" + }, + { + "astId": 2466, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_symbol", + "offset": 0, + "slot": "4", + "type": "t_string_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_uint256)" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/deployments/bsctestnet/MockTWT.json b/deployments/bsctestnet/MockTWT.json new file mode 100644 index 000000000..e4bfd6c6b --- /dev/null +++ b/deployments/bsctestnet/MockTWT.json @@ -0,0 +1,449 @@ +{ + "address": "0xb99c6b26fdf3678c6e2aff8466e3625a0e7182f8", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "faucet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0xd40c59aa59f5e4504e4b279a762a49889c5d2c1fea66ed3b0288d6c4dd993081", + "receipt": { + "to": null, + "from": "0x03862dfa5d0be8f64509c001cb8c6188194469df", + "contractAddress": "0xb99c6b26fdf3678c6e2aff8466e3625a0e7182f8", + "transactionIndex": "0x25", + "gasUsed": "0x9b488", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x76256e0af7c26266a2900752dcd9728830b851ce72337a7c15b8ec68c52a5101", + "transactionHash": "0xd40c59aa59f5e4504e4b279a762a49889c5d2c1fea66ed3b0288d6c4dd993081", + "logs": [], + "blockNumber": "0x1f2dd2f", + "cumulativeGasUsed": "0x262e964", + "status": "0x1" + }, + "args": ["Trust Wallet", "TWT", 18], + "numDeployments": 1, + "solcInputHash": "fe42e787f43c7b3c0c64f0274853de01", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"faucet\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"See {IERC20-allowance}.\"},\"approve(address,uint256)\":{\"details\":\"See {IERC20-approve}. NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address.\"},\"balanceOf(address)\":{\"details\":\"See {IERC20-balanceOf}.\"},\"decimals()\":{\"details\":\"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5.05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the default value returned by this function, unless it's overridden. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}.\"},\"decreaseAllowance(address,uint256)\":{\"details\":\"Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`.\"},\"increaseAllowance(address,uint256)\":{\"details\":\"Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address.\"},\"name()\":{\"details\":\"Returns the name of the token.\"},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See {IERC20-totalSupply}.\"},\"transfer(address,uint256)\":{\"details\":\"See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `amount`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `amount`. - the caller must have allowance for ``from``'s tokens of at least `amount`.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/test/Mocks/MockToken.sol\":\"MockToken\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * The default value of {decimals} is 18. To change this, you should override\\n * this function so it returns a different value.\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the default value returned by this function, unless\\n * it's overridden.\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(address from, address to, uint256 amount) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(address owner, address spender, uint256 amount) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\\n}\\n\",\"keccak256\":\"0xa56ca923f70c1748830700250b19c61b70db9a683516dc5e216694a50445d99c\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\\n}\\n\",\"keccak256\":\"0x287b55befed2961a7eabd7d7b1b2839cbca8a5b80ef8dcbb25ed3d4c2002c305\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/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\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"contracts/test/Mocks/MockToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport { ERC20 } from \\\"@openzeppelin/contracts/token/ERC20/ERC20.sol\\\";\\n\\ncontract MockToken is ERC20 {\\n uint8 private immutable _decimals;\\n\\n constructor(\\n string memory name_,\\n string memory symbol_,\\n uint8 decimals_\\n ) ERC20(name_, symbol_) {\\n _decimals = decimals_;\\n }\\n\\n function faucet(uint256 amount) external {\\n _mint(msg.sender, amount);\\n }\\n\\n function decimals() public view virtual override returns (uint8) {\\n return _decimals;\\n }\\n}\\n\",\"keccak256\":\"0x12742c274df06975fbf8e8a23a1adc14ff9475ac7276be6b1b6e86260caca60a\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a06040523480156200001157600080fd5b5060405162000c4838038062000c488339810160408190526200003491620001e8565b8251839083906200004d90600390602085019062000075565b5080516200006390600490602084019062000075565b50505060ff1660805250620002a99050565b82805462000083906200026d565b90600052602060002090601f016020900481019282620000a75760008555620000f2565b82601f10620000c257805160ff1916838001178555620000f2565b82800160010185558215620000f2579182015b82811115620000f2578251825591602001919060010190620000d5565b506200010092915062000104565b5090565b5b8082111562000100576000815560010162000105565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200014357600080fd5b81516001600160401b03808211156200016057620001606200011b565b604051601f8301601f19908116603f011681019082821181831017156200018b576200018b6200011b565b81604052838152602092508683858801011115620001a857600080fd5b600091505b83821015620001cc5785820183015181830184015290820190620001ad565b83821115620001de5760008385830101525b9695505050505050565b600080600060608486031215620001fe57600080fd5b83516001600160401b03808211156200021657600080fd5b620002248783880162000131565b945060208601519150808211156200023b57600080fd5b506200024a8682870162000131565b925050604084015160ff811681146200026257600080fd5b809150509250925092565b600181811c908216806200028257607f821691505b602082108103620002a357634e487b7160e01b600052602260045260246000fd5b50919050565b608051610983620002c5600039600061012601526109836000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c80635791589711610071578063579158971461016357806370a082311461017857806395d89b41146101a1578063a457c2d7146101a9578063a9059cbb146101bc578063dd62ed3e146101cf57600080fd5b806306fdde03146100b9578063095ea7b3146100d757806318160ddd146100fa57806323b872dd1461010c578063313ce5671461011f5780633950935114610150575b600080fd5b6100c16101e2565b6040516100ce91906107a8565b60405180910390f35b6100ea6100e5366004610819565b610274565b60405190151581526020016100ce565b6002545b6040519081526020016100ce565b6100ea61011a366004610843565b61028c565b60405160ff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100ce565b6100ea61015e366004610819565b6102b0565b61017661017136600461087f565b6102d2565b005b6100fe610186366004610898565b6001600160a01b031660009081526020819052604090205490565b6100c16102df565b6100ea6101b7366004610819565b6102ee565b6100ea6101ca366004610819565b61036e565b6100fe6101dd3660046108ba565b61037c565b6060600380546101f1906108ed565b80601f016020809104026020016040519081016040528092919081815260200182805461021d906108ed565b801561026a5780601f1061023f5761010080835404028352916020019161026a565b820191906000526020600020905b81548152906001019060200180831161024d57829003601f168201915b5050505050905090565b6000336102828185856103a7565b5060019392505050565b60003361029a8582856104cb565b6102a5858585610545565b506001949350505050565b6000336102828185856102c3838361037c565b6102cd9190610927565b6103a7565b6102dc33826106e9565b50565b6060600480546101f1906108ed565b600033816102fc828661037c565b9050838110156103615760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102a582868684036103a7565b600033610282818585610545565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104095760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610358565b6001600160a01b03821661046a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610358565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006104d7848461037c565b9050600019811461053f57818110156105325760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610358565b61053f84848484036103a7565b50505050565b6001600160a01b0383166105a95760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610358565b6001600160a01b03821661060b5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610358565b6001600160a01b038316600090815260208190526040902054818110156106835760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610358565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361053f565b6001600160a01b03821661073f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610358565b80600260008282546107519190610927565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b818110156107d5578581018301518582016040015282016107b9565b818111156107e7576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461081457600080fd5b919050565b6000806040838503121561082c57600080fd5b610835836107fd565b946020939093013593505050565b60008060006060848603121561085857600080fd5b610861846107fd565b925061086f602085016107fd565b9150604084013590509250925092565b60006020828403121561089157600080fd5b5035919050565b6000602082840312156108aa57600080fd5b6108b3826107fd565b9392505050565b600080604083850312156108cd57600080fd5b6108d6836107fd565b91506108e4602084016107fd565b90509250929050565b600181811c9082168061090157607f821691505b60208210810361092157634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561094857634e487b7160e01b600052601160045260246000fd5b50019056fea2646970667358221220ad3749d07ad778d94ced64a644949d79ddd48e1fb7564746812dce99fc30b8ce64736f6c634300080d0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100b45760003560e01c80635791589711610071578063579158971461016357806370a082311461017857806395d89b41146101a1578063a457c2d7146101a9578063a9059cbb146101bc578063dd62ed3e146101cf57600080fd5b806306fdde03146100b9578063095ea7b3146100d757806318160ddd146100fa57806323b872dd1461010c578063313ce5671461011f5780633950935114610150575b600080fd5b6100c16101e2565b6040516100ce91906107a8565b60405180910390f35b6100ea6100e5366004610819565b610274565b60405190151581526020016100ce565b6002545b6040519081526020016100ce565b6100ea61011a366004610843565b61028c565b60405160ff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100ce565b6100ea61015e366004610819565b6102b0565b61017661017136600461087f565b6102d2565b005b6100fe610186366004610898565b6001600160a01b031660009081526020819052604090205490565b6100c16102df565b6100ea6101b7366004610819565b6102ee565b6100ea6101ca366004610819565b61036e565b6100fe6101dd3660046108ba565b61037c565b6060600380546101f1906108ed565b80601f016020809104026020016040519081016040528092919081815260200182805461021d906108ed565b801561026a5780601f1061023f5761010080835404028352916020019161026a565b820191906000526020600020905b81548152906001019060200180831161024d57829003601f168201915b5050505050905090565b6000336102828185856103a7565b5060019392505050565b60003361029a8582856104cb565b6102a5858585610545565b506001949350505050565b6000336102828185856102c3838361037c565b6102cd9190610927565b6103a7565b6102dc33826106e9565b50565b6060600480546101f1906108ed565b600033816102fc828661037c565b9050838110156103615760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102a582868684036103a7565b600033610282818585610545565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104095760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610358565b6001600160a01b03821661046a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610358565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006104d7848461037c565b9050600019811461053f57818110156105325760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610358565b61053f84848484036103a7565b50505050565b6001600160a01b0383166105a95760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610358565b6001600160a01b03821661060b5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610358565b6001600160a01b038316600090815260208190526040902054818110156106835760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610358565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361053f565b6001600160a01b03821661073f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610358565b80600260008282546107519190610927565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b818110156107d5578581018301518582016040015282016107b9565b818111156107e7576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461081457600080fd5b919050565b6000806040838503121561082c57600080fd5b610835836107fd565b946020939093013593505050565b60008060006060848603121561085857600080fd5b610861846107fd565b925061086f602085016107fd565b9150604084013590509250925092565b60006020828403121561089157600080fd5b5035919050565b6000602082840312156108aa57600080fd5b6108b3826107fd565b9392505050565b600080604083850312156108cd57600080fd5b6108d6836107fd565b91506108e4602084016107fd565b90509250929050565b600181811c9082168061090157607f821691505b60208210810361092157634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561094857634e487b7160e01b600052601160045260246000fd5b50019056fea2646970667358221220ad3749d07ad778d94ced64a644949d79ddd48e1fb7564746812dce99fc30b8ce64736f6c634300080d0033", + "devdoc": { + "kind": "dev", + "methods": { + "allowance(address,address)": { + "details": "See {IERC20-allowance}." + }, + "approve(address,uint256)": { + "details": "See {IERC20-approve}. NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on `transferFrom`. This is semantically equivalent to an infinite approval. Requirements: - `spender` cannot be the zero address." + }, + "balanceOf(address)": { + "details": "See {IERC20-balanceOf}." + }, + "decimals()": { + "details": "Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5.05` (`505 / 10 ** 2`). Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. This is the default value returned by this function, unless it's overridden. NOTE: This information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including {IERC20-balanceOf} and {IERC20-transfer}." + }, + "decreaseAllowance(address,uint256)": { + "details": "Atomically decreases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`." + }, + "increaseAllowance(address,uint256)": { + "details": "Atomically increases the allowance granted to `spender` by the caller. This is an alternative to {approve} that can be used as a mitigation for problems described in {IERC20-approve}. Emits an {Approval} event indicating the updated allowance. Requirements: - `spender` cannot be the zero address." + }, + "name()": { + "details": "Returns the name of the token." + }, + "symbol()": { + "details": "Returns the symbol of the token, usually a shorter version of the name." + }, + "totalSupply()": { + "details": "See {IERC20-totalSupply}." + }, + "transfer(address,uint256)": { + "details": "See {IERC20-transfer}. Requirements: - `to` cannot be the zero address. - the caller must have a balance of at least `amount`." + }, + "transferFrom(address,address,uint256)": { + "details": "See {IERC20-transferFrom}. Emits an {Approval} event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of {ERC20}. NOTE: Does not update the allowance if the current allowance is the maximum `uint256`. Requirements: - `from` and `to` cannot be the zero address. - `from` must have a balance of at least `amount`. - the caller must have allowance for ``from``'s tokens of at least `amount`." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 2454, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_balances", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 2460, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_allowances", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" + }, + { + "astId": 2462, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_totalSupply", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 2464, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_name", + "offset": 0, + "slot": "3", + "type": "t_string_storage" + }, + { + "astId": 2466, + "contract": "contracts/test/Mocks/MockToken.sol:MockToken", + "label": "_symbol", + "offset": 0, + "slot": "4", + "type": "t_string_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_address,t_uint256)" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/deployments/bsctestnet/VToken_vTWT_DeFi.json b/deployments/bsctestnet/VToken_vTWT_DeFi.json new file mode 100644 index 000000000..9af9ad256 --- /dev/null +++ b/deployments/bsctestnet/VToken_vTWT_DeFi.json @@ -0,0 +1,246 @@ +{ + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "beacon", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "receipt": { + "to": null, + "from": "0x03862dFa5D0be8F64509C001cb8C6188194469DF", + "contractAddress": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "transactionIndex": 1, + "gasUsed": "675690", + "logsBloom": "0x00000000400400000000000000000080000000000000000000800000000000000000000000000040000000020000000000000000000000000000000800048040001000000000000000000000001000000001000000040000800000000000002000000000020000000080000000000800200000080000000000000000000000400000000000400000000000000000080000000000000080100000000000000000000000041000000100000000800400000000000010800000000001000010004000000004000000000002200200040000000000000000100000c00000000060000000000000000000008000800000040400000800000004000000004000010000", + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2", + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "logs": [ + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": [ + "0x1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e", + "0x000000000000000000000000bf85a90673e61956f8c79b9150bab7893b791bdd" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000003862dfa5d0be8f64509c001cb8c6188194469df" + ], + "data": "0x", + "logIndex": 1, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": ["0x66fd58e82f7b31a2a5c30e0888f3093efe4e111b00cd2b0c31fe014601293aa0"], + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045f8a08f534f34a97187626e05d4b6648eeaa9aa", + "logIndex": 2, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": [ + "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000023a73971a6b9f6580c048b9cb188869b2a2aa2ad" + ], + "data": "0x", + "logIndex": 3, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": [ + "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000009d812a63a5e33f2fc54810f71466fed862a5ef28" + ], + "data": "0x", + "logIndex": 4, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": ["0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460"], + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003782dace9d90000", + "logIndex": 5, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": [ + "0x6dbf1ff28f860de5edafa4c6505e37c0aba213288cc4166c5352b6d3776c79ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001" + ], + "data": "0x", + "logIndex": 6, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": [ + "0xafec95c8612496c3ecf5dddc71e393528fe29bd145fbaf9c6b496d78d7e2d79b", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000008b293600c50d6fbdc6ed4251cc75ece29880276f" + ], + "data": "0x", + "logIndex": 7, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x00000000000000000000000003862dfa5d0be8f64509c001cb8c6188194469df", + "0x000000000000000000000000ce10739590001705f7ff231611ba4a48b2820327" + ], + "data": "0x", + "logIndex": 8, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + }, + { + "transactionIndex": 1, + "blockNumber": 32725415, + "transactionHash": "0xe069974233806e0f558907242878a0a3eafccbfa03ebbeb328b1325c5616d508", + "address": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", + "topics": ["0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498"], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 9, + "blockHash": "0xfd178aa0d0d54d28e74451435ec9f020c2661641a2c87373631b22caa3f6faa2" + } + ], + "blockNumber": 32725415, + "cumulativeGasUsed": "721128", + "status": 1, + "byzantium": true + }, + "args": [ + "0xBF85A90673E61956f8c79b9150BAB7893b791bDd", + "0x8a42c319000000000000000000000000b99c6b26fdf3678c6e2aff8466e3625a0e7182f800000000000000000000000023a73971a6b9f6580c048b9cb188869b2a2aa2ad0000000000000000000000009d812a63a5e33f2fc54810f71466fed862a5ef280000000000000000000000000000000000000000204fce5e3e25026110000000000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000ce10739590001705f7ff231611ba4a48b282032700000000000000000000000045f8a08f534f34a97187626e05d4b6648eeaa9aa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000008b293600c50d6fbdc6ed4251cc75ece29880276f00000000000000000000000000000000000000000000000003782dace9d90000000000000000000000000000000000000000000000000000000000000000001056656e75732054575420284465466929000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009765457545f446546690000000000000000000000000000000000000000000000" + ], + "numDeployments": 1, + "solcInputHash": "fe42e787f43c7b3c0c64f0274853de01", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't conflict with the storage layout of the implementation behind the proxy. _Available since v3.4._\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"details\":\"Initializes the proxy with `beacon`. If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. Requirements: - `beacon` must be a contract with the interface {IBeacon}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\":\"BeaconProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/interfaces/IERC1967.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\\n *\\n * _Available since v4.8.3._\\n */\\ninterface IERC1967 {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Emitted when the beacon is changed.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n}\\n\",\"keccak256\":\"0x3cbef5ebc24b415252e2f8c0c9254555d30d9f085603b4b80d9b5ed20ab87e90\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/draft-IERC1822.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822Proxiable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x1d4afe6cb24200cc4545eed814ecf5847277dfe5d613a1707aad5fceecebcfff\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeacon.sol\\\";\\nimport \\\"../../interfaces/IERC1967.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/StorageSlot.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n */\\nabstract contract ERC1967Upgrade is IERC1967 {\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(Address.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(\\n Address.isContract(IBeacon(newBeacon).implementation()),\\n \\\"ERC1967: beacon implementation is not a contract\\\"\\n );\\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3b21ae06bf5957f73fa16754b0669c77b7abd8ba6c072d35c3281d446fdb86c2\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\\n * be specified by overriding the virtual {_implementation} function.\\n *\\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\\n * different contract through the {_delegate} function.\\n *\\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\\n */\\nabstract contract Proxy {\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal virtual {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n /**\\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\\n * and {_fallback} should delegate.\\n */\\n function _implementation() internal view virtual returns (address);\\n\\n /**\\n * @dev Delegates the current call to the address returned by `_implementation()`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _fallback() internal virtual {\\n _beforeFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\\n * is empty.\\n */\\n receive() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\\n * call, or as part of the Solidity `fallback` or `receive` functions.\\n *\\n * If overridden should call `super._beforeFallback()`.\\n */\\n function _beforeFallback() internal virtual {}\\n}\\n\",\"keccak256\":\"0xc130fe33f1b2132158531a87734153293f6d07bc263ff4ac90e85da9c82c0e27\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IBeacon.sol\\\";\\nimport \\\"../Proxy.sol\\\";\\nimport \\\"../ERC1967/ERC1967Upgrade.sol\\\";\\n\\n/**\\n * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.\\n *\\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\\n * conflict with the storage layout of the implementation behind the proxy.\\n *\\n * _Available since v3.4._\\n */\\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\\n /**\\n * @dev Initializes the proxy with `beacon`.\\n *\\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\\n * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity\\n * constructor.\\n *\\n * Requirements:\\n *\\n * - `beacon` must be a contract with the interface {IBeacon}.\\n */\\n constructor(address beacon, bytes memory data) payable {\\n _upgradeBeaconToAndCall(beacon, data, false);\\n }\\n\\n /**\\n * @dev Returns the current beacon address.\\n */\\n function _beacon() internal view virtual returns (address) {\\n return _getBeacon();\\n }\\n\\n /**\\n * @dev Returns the current implementation address of the associated beacon.\\n */\\n function _implementation() internal view virtual override returns (address) {\\n return IBeacon(_getBeacon()).implementation();\\n }\\n\\n /**\\n * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\\n *\\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\\n *\\n * Requirements:\\n *\\n * - `beacon` must be a contract.\\n * - The implementation returned by `beacon` must be a contract.\\n */\\n function _setBeacon(address beacon, bytes memory data) internal virtual {\\n _upgradeBeaconToAndCall(beacon, data, false);\\n }\\n}\\n\",\"keccak256\":\"0x85439e74ab467b6a23d45d32bdc9506cbc3760320289afd605f11638c4138e95\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/beacon/IBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeacon {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n *\\n * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)\\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```solidity\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._\\n * _Available since v4.9 for `string`, `bytes`._\\n */\\nlibrary StorageSlot {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n struct StringSlot {\\n string value;\\n }\\n\\n struct BytesSlot {\\n bytes value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `StringSlot` with member `value` located at `slot`.\\n */\\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\\n */\\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := store.slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BytesSlot` with member `value` located at `slot`.\\n */\\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\\n */\\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := store.slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf09e68aa0dc6722a25bc46490e8d48ed864466d17313b8a0b254c36b54e49899\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405260405161091438038061091483398101604081905261002291610463565b61002e82826000610035565b505061058d565b61003e83610100565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a260008251118061007f5750805b156100fb576100f9836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e99190610523565b836102a360201b6100291760201c565b505b505050565b610113816102cf60201b6100551760201c565b6101725760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101e6816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190610523565b6102cf60201b6100551760201c565b61024b5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610169565b806102827fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102de60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102c883836040518060600160405280602781526020016108ed602791396102e1565b9392505050565b6001600160a01b03163b151590565b90565b6060600080856001600160a01b0316856040516102fe919061053e565b600060405180830381855af49150503d8060008114610339576040519150601f19603f3d011682016040523d82523d6000602084013e61033e565b606091505b5090925090506103508683838761035a565b9695505050505050565b606083156103c95782516000036103c2576001600160a01b0385163b6103c25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610169565b50816103d3565b6103d383836103db565b949350505050565b8151156103eb5781518083602001fd5b8060405162461bcd60e51b8152600401610169919061055a565b80516001600160a01b038116811461041c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561045257818101518382015260200161043a565b838111156100f95750506000910152565b6000806040838503121561047657600080fd5b61047f83610405565b60208401519092506001600160401b038082111561049c57600080fd5b818501915085601f8301126104b057600080fd5b8151818111156104c2576104c2610421565b604051601f8201601f19908116603f011681019083821181831017156104ea576104ea610421565b8160405282815288602084870101111561050357600080fd5b610514836020830160208801610437565b80955050505050509250929050565b60006020828403121561053557600080fd5b6102c882610405565b60008251610550818460208701610437565b9190910192915050565b6020815260008251806020840152610579816040850160208701610437565b601f01601f19169190910160400192915050565b6103518061059c6000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f560279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061024c565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a5565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b60608315610210578251600003610209576001600160a01b0385163b6102095760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b508161021a565b61021a8383610222565b949350505050565b8151156102325781518083602001fd5b8060405162461bcd60e51b815260040161020091906102c1565b60006020828403121561025e57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b83811015610290578181015183820152602001610278565b8381111561029f576000848401525b50505050565b600082516102b7818460208701610275565b9190910192915050565b60208152600082518060208401526102e0816040850160208701610275565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220fe297b55fecce116ce1eb9330ed9a20786628fb8686af0694c83f972893aa55a64736f6c634300080d0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564", + "deployedBytecode": "0x60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102f560279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061024c565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b6060600080856001600160a01b03168560405161014191906102a5565b600060405180830381855af49150503d806000811461017c576040519150601f19603f3d011682016040523d82523d6000602084013e610181565b606091505b50915091506101928683838761019c565b9695505050505050565b60608315610210578251600003610209576001600160a01b0385163b6102095760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064015b60405180910390fd5b508161021a565b61021a8383610222565b949350505050565b8151156102325781518083602001fd5b8060405162461bcd60e51b815260040161020091906102c1565b60006020828403121561025e57600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b83811015610290578181015183820152602001610278565b8381111561029f576000848401525b50505050565b600082516102b7818460208701610275565b9190910192915050565b60208152600082518060208401526102e0816040850160208701610275565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220fe297b55fecce116ce1eb9330ed9a20786628fb8686af0694c83f972893aa55a64736f6c634300080d0033", + "devdoc": { + "details": "This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't conflict with the storage layout of the implementation behind the proxy. _Available since v3.4._", + "kind": "dev", + "methods": { + "constructor": { + "details": "Initializes the proxy with `beacon`. If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. Requirements: - `beacon` must be a contract with the interface {IBeacon}." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} diff --git a/deployments/bsctestnet/solcInputs/ad7e39c529776ba8e663b9883415bfcf.json b/deployments/bsctestnet/solcInputs/ad7e39c529776ba8e663b9883415bfcf.json new file mode 100644 index 000000000..e56a09c99 --- /dev/null +++ b/deployments/bsctestnet/solcInputs/ad7e39c529776ba8e663b9883415bfcf.json @@ -0,0 +1,285 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./OwnableUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides 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} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n function __Ownable2Step_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.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/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {\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 function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\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 /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized != type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n return _status == _ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n using AddressUpgradeable for address;\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to\n * 0 before setting it to a non-zero value.\n */\n function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n * Revert on invalid signature.\n */\n function safePermit(\n IERC20PermitUpgradeable token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return\n success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\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 ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\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 /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n /**\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n * address.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy.\n */\n function proxiableUUID() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC1967.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\n *\n * _Available since v4.8.3._\n */\ninterface IERC1967 {\n /**\n * @dev Emitted when the implementation is upgraded.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Emitted when the admin account has changed.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Emitted when the beacon is changed.\n */\n event BeaconUpgraded(address indexed beacon);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../Proxy.sol\";\nimport \"../ERC1967/ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.\n *\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\n * conflict with the storage layout of the implementation behind the proxy.\n *\n * _Available since v3.4._\n */\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\n /**\n * @dev Initializes the proxy with `beacon`.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\n * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity\n * constructor.\n *\n * Requirements:\n *\n * - `beacon` must be a contract with the interface {IBeacon}.\n */\n constructor(address beacon, bytes memory data) payable {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n\n /**\n * @dev Returns the current beacon address.\n */\n function _beacon() internal view virtual returns (address) {\n return _getBeacon();\n }\n\n /**\n * @dev Returns the current implementation address of the associated beacon.\n */\n function _implementation() internal view virtual override returns (address) {\n return IBeacon(_getBeacon()).implementation();\n }\n\n /**\n * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\n *\n * Requirements:\n *\n * - `beacon` must be a contract.\n * - The implementation returned by `beacon` must be a contract.\n */\n function _setBeacon(address beacon, bytes memory data) internal virtual {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n /**\n * @dev Must return an address that can be used as a delegate call target.\n *\n * {BeaconProxy} will check that this address is a contract.\n */\n function implementation() external view returns (address);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../../access/Ownable.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their\n * implementation contract, which is where they will delegate all function calls.\n *\n * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.\n */\ncontract UpgradeableBeacon is IBeacon, Ownable {\n address private _implementation;\n\n /**\n * @dev Emitted when the implementation returned by the beacon is changed.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the\n * beacon.\n */\n constructor(address implementation_) {\n _setImplementation(implementation_);\n }\n\n /**\n * @dev Returns the current implementation address.\n */\n function implementation() public view virtual override returns (address) {\n return _implementation;\n }\n\n /**\n * @dev Upgrades the beacon to a new implementation.\n *\n * Emits an {Upgraded} event.\n *\n * Requirements:\n *\n * - msg.sender must be the owner of the contract.\n * - `newImplementation` must be a contract.\n */\n function upgradeTo(address newImplementation) public virtual onlyOwner {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation contract address for this beacon\n *\n * Requirements:\n *\n * - `newImplementation` must be a contract.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"UpgradeableBeacon: implementation is not a contract\");\n _implementation = newImplementation;\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/IERC1967.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n */\nabstract contract ERC1967Upgrade is IERC1967 {\n // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation address.\n */\n function _getImplementation() internal view returns (address) {\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 implementation slot.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n }\n\n /**\n * @dev Perform implementation upgrade\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Perform implementation upgrade with additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {\n _upgradeTo(newImplementation);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(newImplementation, data);\n }\n }\n\n /**\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {\n // Upgrades from old implementations will perform a rollback test. This test requires the new\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n // this special case will break upgrade paths from old UUPS implementation to new ones.\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n _setImplementation(newImplementation);\n } else {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n } catch {\n revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n }\n _upgradeToAndCall(newImplementation, data, forceCall);\n }\n }\n\n /**\n * @dev Storage slot with the admin of the contract.\n * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /**\n * @dev Returns the current admin.\n */\n function _getAdmin() internal view returns (address) {\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 admin slot.\n */\n function _setAdmin(address newAdmin) private {\n require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n */\n function _changeAdmin(address newAdmin) internal {\n emit AdminChanged(_getAdmin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n */\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n /**\n * @dev Returns the current beacon.\n */\n function _getBeacon() internal view returns (address) {\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n }\n\n /**\n * @dev Stores a new beacon in the EIP1967 beacon slot.\n */\n function _setBeacon(address newBeacon) private {\n require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n require(\n Address.isContract(IBeacon(newBeacon).implementation()),\n \"ERC1967: beacon implementation is not a contract\"\n );\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n }\n\n /**\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n *\n * Emits a {BeaconUpgraded} event.\n */\n function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {\n _setBeacon(newBeacon);\n emit BeaconUpgraded(newBeacon);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n /**\n * @dev Delegates the current call to `implementation`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _delegate(address implementation) internal virtual {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n /**\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n * and {_fallback} should delegate.\n */\n function _implementation() internal view virtual returns (address);\n\n /**\n * @dev Delegates the current call to the address returned by `_implementation()`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _fallback() internal virtual {\n _beforeFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n * function in the contract matches the call data.\n */\n fallback() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n * is empty.\n */\n receive() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n * call, or as part of the Solidity `fallback` or `receive` functions.\n *\n * If overridden should call `super._beforeFallback()`.\n */\n function _beforeFallback() internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(address from, address to, uint256 amount) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n // decrementing then incrementing.\n _balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n unchecked {\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n _balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n // Overflow not possible: amount <= accountBalance <= totalSupply.\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(address owner, address spender, uint256 amount) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1, \"Math: mulDiv overflow\");\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/utils/StorageSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._\n * _Available since v4.9 for `string`, `bytes`._\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := store.slot\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toString(int256 value) internal pure returns (string memory) {\n return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return keccak256(bytes(a)) == keccak256(bytes(b));\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title Venus Access Control Contract.\n * @dev The AccessControlledV8 contract is a wrapper around the OpenZeppelin AccessControl contract\n * It provides a standardized way to control access to methods within the Venus Smart Contract Ecosystem.\n * The contract allows the owner to set an AccessControlManager contract address.\n * It can restrict method calls based on the sender's role and the method's signature.\n */\n\nabstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {\n /// @notice Access control manager contract\n IAccessControlManagerV8 private _accessControlManager;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when access control manager contract address is changed\n event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);\n\n /// @notice Thrown when the action is prohibited by AccessControlManager\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Sets the address of AccessControlManager\n * @dev Admin function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n * @custom:event Emits NewAccessControlManager event\n * @custom:access Only Governance\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Returns the address of the access control manager contract\n */\n function accessControlManager() external view returns (IAccessControlManagerV8) {\n return _accessControlManager;\n }\n\n /**\n * @dev Internal function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n */\n function _setAccessControlManager(address accessControlManager_) internal {\n require(address(accessControlManager_) != address(0), \"invalid acess control manager address\");\n address oldAccessControlManager = address(_accessControlManager);\n _accessControlManager = IAccessControlManagerV8(accessControlManager_);\n emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);\n }\n\n /**\n * @notice Reverts if the call is not allowed by AccessControlManager\n * @param signature Method signature\n */\n function _checkAccessAllowed(string memory signature) internal view {\n bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title Venus Access Control Contract\n * @author venus\n * @dev This contract is a wrapper of OpenZeppelin AccessControl\n *\t\textending it in a way to standartize access control\n *\t\twithin Venus Smart Contract Ecosystem\n */\ncontract AccessControlManager is AccessControl, IAccessControlManagerV8 {\n /// @notice Emitted when an account is given a permission to a certain contract function\n /// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and\n /// can call any contract function with this signature\n event PermissionGranted(address account, address contractAddress, string functionSig);\n\n /// @notice Emitted when an account is revoked a permission to a certain contract function\n event PermissionRevoked(address account, address contractAddress, string functionSig);\n\n constructor() {\n // Grant the contract deployer the default admin role: it will be able\n // to grant and revoke any roles\n _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n /**\n * @notice Gives a function call permission to one single account\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * @param contractAddress address of contract for which call permissions will be granted\n * @dev if contractAddress is zero address, the account can access the specified function\n * on **any** contract managed by this ACL\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @param accountToPermit account that will be given access to the contract function\n * @custom:event Emits a {RoleGranted} and {PermissionGranted} events.\n */\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n grantRole(role, accountToPermit);\n emit PermissionGranted(accountToPermit, contractAddress, functionSig);\n }\n\n /**\n * @notice Revokes an account's permission to a particular function call\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * \t\tMay emit a {RoleRevoked} event.\n * @param contractAddress address of contract for which call permissions will be revoked\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.\n */\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n revokeRole(role, accountToRevoke);\n emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender\n * @param account for which call permissions will be checked\n * @param functionSig restricted function signature e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n *\n */\n function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));\n\n if (hasRole(role, account)) {\n return true;\n } else {\n role = keccak256(abi.encodePacked(address(0), functionSig));\n return hasRole(role, account);\n }\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.\n * @param account for which call permissions will be checked against\n * @param contractAddress address of the restricted contract\n * @param functionSig signature of the restricted function e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n */\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n return hasRole(role, account);\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/FeedRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface FeedRegistryInterface {\n function latestRoundDataByName(\n string memory base,\n string memory quote\n )\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n function decimalsByName(string memory base, string memory quote) external view returns (uint8);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface OracleInterface {\n function getPrice(address asset) external view returns (uint256);\n}\n\ninterface ResilientOracleInterface is OracleInterface {\n function updatePrice(address vToken) external;\n\n function updateAssetPrice(address asset) external;\n\n function getUnderlyingPrice(address vToken) external view returns (uint256);\n}\n\ninterface TwapInterface is OracleInterface {\n function updateTwap(address asset) external returns (uint256);\n}\n\ninterface BoundValidatorInterface {\n function validatePriceWithAnchorPrice(\n address asset,\n uint256 reporterPrice,\n uint256 anchorPrice\n ) external view returns (bool);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/PublicResolverInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.13;\n\ninterface PublicResolverInterface {\n function addr(bytes32 node) external view returns (address payable);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/SIDRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.13;\n\ninterface SIDRegistryInterface {\n function resolver(bytes32 node) external view returns (address);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/VBep20Interface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\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" + }, + "@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/SIDRegistryInterface.sol\";\nimport \"../interfaces/FeedRegistryInterface.sol\";\nimport \"../interfaces/PublicResolverInterface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport \"../interfaces/OracleInterface.sol\";\n\n/**\n * @title BinanceOracle\n * @author Venus\n * @notice This oracle fetches price of assets from Binance.\n */\ncontract BinanceOracle is AccessControlledV8, OracleInterface {\n address public sidRegistryAddress;\n\n /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Max stale period configuration for assets\n mapping(string => uint256) public maxStalePeriod;\n\n /// @notice Override symbols to be compatible with Binance feed registry\n mapping(string => string) public symbols;\n\n event MaxStalePeriodAdded(string indexed asset, uint256 maxStalePeriod);\n\n event SymbolOverridden(string indexed symbol, string overriddenSymbol);\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 /// @notice Constructor for the implementation contract.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Used to set the max stale period of an asset\n * @param symbol The symbol of the asset\n * @param _maxStalePeriod The max stake period\n */\n function setMaxStalePeriod(string memory symbol, uint256 _maxStalePeriod) external {\n _checkAccessAllowed(\"setMaxStalePeriod(string,uint256)\");\n if (_maxStalePeriod == 0) revert(\"stale period can't be zero\");\n if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n maxStalePeriod[symbol] = _maxStalePeriod;\n emit MaxStalePeriodAdded(symbol, _maxStalePeriod);\n }\n\n /**\n * @notice Used to override a symbol when fetching price\n * @param symbol The symbol to override\n * @param overrideSymbol The symbol after override\n */\n function setSymbolOverride(string calldata symbol, string calldata overrideSymbol) external {\n _checkAccessAllowed(\"setSymbolOverride(string,string)\");\n if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n symbols[symbol] = overrideSymbol;\n emit SymbolOverridden(symbol, overrideSymbol);\n }\n\n /**\n * @notice Sets the contracts required to fetch prices\n * @param _sidRegistryAddress Address of SID registry\n * @param _accessControlManager Address of the access control manager contract\n */\n function initialize(\n address _sidRegistryAddress,\n address _accessControlManager\n ) external initializer notNullAddress(_sidRegistryAddress) {\n sidRegistryAddress = _sidRegistryAddress;\n __AccessControlled_init(_accessControlManager);\n }\n\n /**\n * @notice Uses Space ID to fetch the feed registry address\n * @return feedRegistryAddress Address of binance oracle feed registry.\n */\n function getFeedRegistryAddress() public view returns (address) {\n bytes32 nodeHash = 0x94fe3821e0768eb35012484db4df61890f9a6ca5bfa984ef8ff717e73139faff;\n\n SIDRegistryInterface sidRegistry = SIDRegistryInterface(sidRegistryAddress);\n address publicResolverAddress = sidRegistry.resolver(nodeHash);\n PublicResolverInterface publicResolver = PublicResolverInterface(publicResolverAddress);\n\n return publicResolver.addr(nodeHash);\n }\n\n /**\n * @notice Gets the price of a asset from the binance oracle\n * @param asset Address of the asset\n * @return Price in USD\n */\n function getPrice(address asset) public view returns (uint256) {\n string memory symbol;\n uint256 decimals;\n\n if (asset == BNB_ADDR) {\n symbol = \"BNB\";\n decimals = 18;\n } else {\n IERC20Metadata token = IERC20Metadata(asset);\n symbol = token.symbol();\n decimals = token.decimals();\n }\n\n string memory overrideSymbol = symbols[symbol];\n\n if (bytes(overrideSymbol).length != 0) {\n symbol = overrideSymbol;\n }\n\n return _getPrice(symbol, decimals);\n }\n\n function _getPrice(string memory symbol, uint256 decimals) internal view returns (uint256) {\n FeedRegistryInterface feedRegistry = FeedRegistryInterface(getFeedRegistryAddress());\n\n (, int256 answer, , uint256 updatedAt, ) = feedRegistry.latestRoundDataByName(symbol, \"USD\");\n if (answer <= 0) revert(\"invalid binance oracle price\");\n if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n uint256 deltaTime;\n unchecked {\n deltaTime = block.timestamp - updatedAt;\n }\n if (deltaTime > maxStalePeriod[symbol]) revert(\"binance oracle price expired\");\n\n uint256 decimalDelta = feedRegistry.decimalsByName(symbol, \"USD\");\n return (uint256(answer) * (10 ** (18 - decimalDelta))) * (10 ** (18 - decimals));\n }\n}\n" + }, + "@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\n/**\n * @title ChainlinkOracle\n * @author Venus\n * @notice This oracle fetches prices of assets from the Chainlink oracle.\n */\ncontract ChainlinkOracle is AccessControlledV8, OracleInterface {\n struct TokenConfig {\n /// @notice Underlying token address, which can't be a null address\n /// @notice Used to check if a token is supported\n /// @notice 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB for BNB\n address asset;\n /// @notice Chainlink feed address\n address feed;\n /// @notice Price expiration period of this asset\n uint256 maxStalePeriod;\n }\n\n /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Manually set an override price, useful under extenuating conditions such as price feed failure\n mapping(address => uint256) public prices;\n\n /// @notice Token config by assets\n mapping(address => TokenConfig) public tokenConfigs;\n\n /// @notice Emit when a price is manually set\n event PricePosted(address indexed asset, uint256 previousPriceMantissa, uint256 newPriceMantissa);\n\n /// @notice Emit when a token config is added\n event TokenConfigAdded(address indexed asset, address feed, uint256 maxStalePeriod);\n\n modifier notNullAddress(address someone) {\n if (someone == address(0)) revert(\"can't be zero address\");\n _;\n }\n\n /// @notice Constructor for the implementation contract.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Manually set the price of a given asset\n * @param asset Asset address\n * @param price Asset price in 18 decimals\n * @custom:access Only Governance\n * @custom:event Emits PricePosted event on succesfully setup of asset price\n */\n function setDirectPrice(address asset, uint256 price) external notNullAddress(asset) {\n _checkAccessAllowed(\"setDirectPrice(address,uint256)\");\n\n uint256 previousPriceMantissa = prices[asset];\n prices[asset] = price;\n emit PricePosted(asset, previousPriceMantissa, price);\n }\n\n /**\n * @notice Add multiple token configs at the same time\n * @param tokenConfigs_ config array\n * @custom:access Only Governance\n * @custom:error Zero length error thrown, if length of the array in parameter 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 Initializes the owner of the contract\n * @param accessControlManager_ Address of the access control manager contract\n */\n function initialize(address accessControlManager_) external initializer {\n __AccessControlled_init(accessControlManager_);\n }\n\n /**\n * @notice Add single token config. asset & feed cannot be null addresses and maxStalePeriod must be positive\n * @param tokenConfig Token config struct\n * @custom:access Only Governance\n * @custom:error NotNullAddress error is thrown if asset address is null\n * @custom:error NotNullAddress error is thrown if token feed address is null\n * @custom:error Range error is thrown if maxStale period of token is not greater than zero\n * @custom:event Emits TokenConfigAdded event on succesfully setting of the token config\n */\n function setTokenConfig(\n TokenConfig memory tokenConfig\n ) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.feed) {\n _checkAccessAllowed(\"setTokenConfig(TokenConfig)\");\n\n if (tokenConfig.maxStalePeriod == 0) revert(\"stale period can't be zero\");\n tokenConfigs[tokenConfig.asset] = tokenConfig;\n emit TokenConfigAdded(tokenConfig.asset, tokenConfig.feed, tokenConfig.maxStalePeriod);\n }\n\n /**\n * @notice Gets the price of a asset from the chainlink oracle\n * @param asset Address of the asset\n * @return Price in USD from Chainlink or a manually set price for the asset\n */\n function getPrice(address asset) public view returns (uint256) {\n uint256 decimals;\n\n if (asset == BNB_ADDR) {\n decimals = 18;\n } else {\n IERC20Metadata token = IERC20Metadata(asset);\n decimals = token.decimals();\n }\n\n return _getPriceInternal(asset, decimals);\n }\n\n /**\n * @notice Gets the Chainlink price for a given asset\n * @param asset address of the asset\n * @param decimals decimals of the asset\n * @return price Asset price in USD or a manually set price of the asset\n */\n function _getPriceInternal(address asset, uint256 decimals) internal view returns (uint256 price) {\n uint256 tokenPrice = prices[asset];\n if (tokenPrice != 0) {\n price = tokenPrice;\n } else {\n price = _getChainlinkPrice(asset);\n }\n\n uint256 decimalDelta = 18 - decimals;\n return price * (10 ** decimalDelta);\n }\n\n /**\n * @notice Get the Chainlink price for an asset, revert if token config doesn't exist\n * @dev The precision of the price feed is used to ensure the returned price has 18 decimals of precision\n * @param asset Address of the asset\n * @return price Price in USD, with 18 decimals of precision\n * @custom:error NotNullAddress error is thrown if the asset address is null\n * @custom:error Price error is thrown if the Chainlink price of asset is not greater than zero\n * @custom:error Timing error is thrown if current timestamp is less than the last updatedAt timestamp\n * @custom:error Timing error is thrown if time difference between current time and last updated time\n * is greater than maxStalePeriod\n */\n function _getChainlinkPrice(\n address asset\n ) private view notNullAddress(tokenConfigs[asset].asset) returns (uint256) {\n TokenConfig memory tokenConfig = tokenConfigs[asset];\n AggregatorV3Interface feed = AggregatorV3Interface(tokenConfig.feed);\n\n // note: maxStalePeriod cannot be 0\n uint256 maxStalePeriod = tokenConfig.maxStalePeriod;\n\n // Chainlink USD-denominated feeds store answers at 8 decimals, mostly\n uint256 decimalDelta = 18 - feed.decimals();\n\n (, int256 answer, , uint256 updatedAt, ) = feed.latestRoundData();\n if (answer <= 0) revert(\"chainlink price must be positive\");\n if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n uint256 deltaTime;\n unchecked {\n deltaTime = block.timestamp - updatedAt;\n }\n\n if (deltaTime > maxStalePeriod) revert(\"chainlink price expired\");\n\n return uint256(answer) * (10 ** decimalDelta);\n }\n}\n" + }, + "contracts/BaseJumpRateModelV2.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\n\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { EXP_SCALE, MANTISSA_ONE } from \"./lib/constants.sol\";\n\n/**\n * @title Logic for Compound's JumpRateModel Contract V2.\n * @author Compound (modified by Dharma Labs, Arr00 and Venus)\n * @notice An interest rate model with a steep increase after a certain utilization threshold called **kink** is reached.\n * The parameters of this interest rate model can be adjusted by the owner. Version 2 modifies Version 1 by enabling updateable parameters.\n */\nabstract contract BaseJumpRateModelV2 is InterestRateModel {\n /**\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\n */\n uint256 public immutable blocksPerYear;\n /**\n * @notice The address of the AccessControlManager contract\n */\n IAccessControlManagerV8 public accessControlManager;\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public baseRatePerBlock;\n\n /**\n * @notice The multiplier per block after hitting a specified utilization point\n */\n uint256 public jumpMultiplierPerBlock;\n\n /**\n * @notice The utilization point at which the jump multiplier is applied\n */\n uint256 public kink;\n\n event NewInterestParams(\n uint256 baseRatePerBlock,\n uint256 multiplierPerBlock,\n uint256 jumpMultiplierPerBlock,\n uint256 kink\n );\n\n /**\n * @notice Thrown when the action is prohibited by AccessControlManager\n */\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n /**\n * @notice Construct an interest rate model\n * @param blocksPerYear_ The approximate number of blocks per year that is assumed by the interest rate model.\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @param accessControlManager_ The address of the AccessControlManager contract\n */\n constructor(\n uint256 blocksPerYear_,\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n IAccessControlManagerV8 accessControlManager_\n ) {\n require(address(accessControlManager_) != address(0), \"invalid ACM address\");\n require(blocksPerYear_ != 0, \"Invalid blocks per year\");\n accessControlManager = accessControlManager_;\n blocksPerYear = blocksPerYear_;\n\n _updateJumpRateModel(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @custom:error Unauthorized if the sender is not allowed to call this function\n * @custom:access Controlled by AccessControlManager\n */\n function updateJumpRateModel(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) external virtual {\n string memory signature = \"updateJumpRateModel(uint256,uint256,uint256,uint256)\";\n bool isAllowedToCall = accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n\n _updateJumpRateModel(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) public view virtual override returns (uint256) {\n uint256 oneMinusReserveFactor = MANTISSA_ONE - reserveFactorMantissa;\n uint256 borrowRate = _getBorrowRate(cash, borrows, reserves, badDebt);\n uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / EXP_SCALE;\n uint256 incomeToDistribute = borrows * rateToPool;\n uint256 supply = cash + borrows + badDebt - reserves;\n return incomeToDistribute / supply;\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `(borrows + badDebt) / (cash + borrows + badDebt - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @param badDebt The amount of badDebt in the market\n * @return The utilization rate as a mantissa between [0, MANTISSA_ONE]\n */\n function utilizationRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public pure returns (uint256) {\n // Utilization rate is 0 when there are no borrows and badDebt\n if ((borrows + badDebt) == 0) {\n return 0;\n }\n\n uint256 rate = ((borrows + badDebt) * EXP_SCALE) / (cash + borrows + badDebt - reserves);\n\n if (rate > EXP_SCALE) {\n rate = EXP_SCALE;\n }\n\n return rate;\n }\n\n /**\n * @notice Internal function to update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n */\n function _updateJumpRateModel(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) internal {\n baseRatePerBlock = baseRatePerYear / blocksPerYear;\n multiplierPerBlock = multiplierPerYear / blocksPerYear;\n jumpMultiplierPerBlock = jumpMultiplierPerYear / blocksPerYear;\n kink = kink_;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function _getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) internal view returns (uint256) {\n uint256 util = utilizationRate(cash, borrows, reserves, badDebt);\n uint256 kink_ = kink;\n\n if (util <= kink_) {\n return ((util * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n }\n uint256 normalRate = ((kink_ * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n uint256 excessUtil;\n unchecked {\n excessUtil = util - kink_;\n }\n return ((excessUtil * jumpMultiplierPerBlock) / EXP_SCALE) + normalRate;\n }\n}\n" + }, + "contracts/Comptroller.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { ComptrollerStorage } from \"./ComptrollerStorage.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\nimport { MaxLoopsLimitHelper } from \"./MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title Comptroller\n * @author Venus\n * @notice The Comptroller is designed to provide checks for all minting, redeeming, transferring, borrowing, lending, repaying, liquidating,\n * and seizing done by the `vToken` contract. Each pool has one `Comptroller` checking these interactions across markets. When a user interacts\n * with a given market by one of these main actions, a call is made to a corresponding hook in the associated `Comptroller`, which either allows\n * or reverts the transaction. These hooks also update supply and borrow rewards as they are called. The comptroller holds the logic for assessing\n * liquidity snapshots of an account via the collateral factor and liquidation threshold. This check determines the collateral needed for a borrow,\n * as well as how much of a borrow may be liquidated. A user may borrow a portion of their collateral with the maximum amount determined by the\n * markets collateral factor. However, if their borrowed amount exceeds an amount calculated using the market’s corresponding liquidation threshold,\n * the borrow is eligible for liquidation.\n *\n * The `Comptroller` also includes two functions `liquidateAccount()` and `healAccount()`, which are meant to handle accounts that do not exceed\n * the `minLiquidatableCollateral` for the `Comptroller`:\n *\n * - `healAccount()`: This function is called to seize all of a given user’s collateral, requiring the `msg.sender` repay a certain percentage\n * of the debt calculated by `collateral/(borrows*liquidationIncentive)`. The function can only be called if the calculated percentage does not exceed\n * 100%, because otherwise no `badDebt` would be created and `liquidateAccount()` should be used instead. The difference in the actual amount of debt\n * and debt paid off is recorded as `badDebt` for each market, which can then be auctioned off for the risk reserves of the associated pool.\n * - `liquidateAccount()`: This function can only be called if the collateral seized will cover all borrows of an account, as well as the liquidation\n * incentive. Otherwise, the pool will incur bad debt, in which case the function `healAccount()` should be used instead. This function skips the logic\n * verifying that the repay amount does not exceed the close factor.\n */\ncontract Comptroller is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n ComptrollerStorage,\n ComptrollerInterface,\n ExponentialNoError,\n MaxLoopsLimitHelper\n{\n // PoolRegistry, immutable to save on gas\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable poolRegistry;\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(VToken indexed vToken, address indexed account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(VToken indexed vToken, address indexed account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint256 oldCloseFactorMantissa, uint256 newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(VToken vToken, uint256 oldCollateralFactorMantissa, uint256 newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation threshold is changed by admin\n event NewLiquidationThreshold(\n VToken vToken,\n uint256 oldLiquidationThresholdMantissa,\n uint256 newLiquidationThresholdMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint256 oldLiquidationIncentiveMantissa, uint256 newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(ResilientOracleInterface oldPriceOracle, ResilientOracleInterface newPriceOracle);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPausedMarket(VToken vToken, Action action, bool pauseState);\n\n /// @notice Emitted when borrow cap for a vToken is changed\n event NewBorrowCap(VToken indexed vToken, uint256 newBorrowCap);\n\n /// @notice Emitted when the collateral threshold (in USD) for non-batch liquidations is changed\n event NewMinLiquidatableCollateral(uint256 oldMinLiquidatableCollateral, uint256 newMinLiquidatableCollateral);\n\n /// @notice Emitted when supply cap for a vToken is changed\n event NewSupplyCap(VToken indexed vToken, uint256 newSupplyCap);\n\n /// @notice Emitted when a rewards distributor is added\n event NewRewardsDistributor(address indexed rewardsDistributor, address indexed rewardToken);\n\n /// @notice Emitted when a market is supported\n event MarketSupported(VToken vToken);\n\n /// @notice Thrown when collateral factor exceeds the upper bound\n error InvalidCollateralFactor();\n\n /// @notice Thrown when liquidation threshold exceeds the collateral factor\n error InvalidLiquidationThreshold();\n\n /// @notice Thrown when the action is only available to specific sender, but the real sender was different\n error UnexpectedSender(address expectedSender, address actualSender);\n\n /// @notice Thrown when the oracle returns an invalid price for some asset\n error PriceError(address vToken);\n\n /// @notice Thrown if VToken unexpectedly returned a nonzero error code while trying to get account snapshot\n error SnapshotError(address vToken, address user);\n\n /// @notice Thrown when the market is not listed\n error MarketNotListed(address market);\n\n /// @notice Thrown when a market has an unexpected comptroller\n error ComptrollerMismatch();\n\n /// @notice Thrown when user is not member of market\n error MarketNotCollateral(address vToken, address user);\n\n /**\n * @notice Thrown during the liquidation if user's total collateral amount is lower than\n * a predefined threshold. In this case only batch liquidations (either liquidateAccount\n * or healAccount) are available.\n */\n error MinimalCollateralViolated(uint256 expectedGreaterThan, uint256 actual);\n error CollateralExceedsThreshold(uint256 expectedLessThanOrEqualTo, uint256 actual);\n error InsufficientCollateral(uint256 collateralToSeize, uint256 availableCollateral);\n\n /// @notice Thrown when the account doesn't have enough liquidity to redeem or borrow\n error InsufficientLiquidity();\n\n /// @notice Thrown when trying to liquidate a healthy account\n error InsufficientShortfall();\n\n /// @notice Thrown when trying to repay more than allowed by close factor\n error TooMuchRepay();\n\n /// @notice Thrown if the user is trying to exit a market in which they have an outstanding debt\n error NonzeroBorrowBalance();\n\n /// @notice Thrown when trying to perform an action that is paused\n error ActionPaused(address market, Action action);\n\n /// @notice Thrown when trying to add a market that is already listed\n error MarketAlreadyListed(address market);\n\n /// @notice Thrown if the supply cap is exceeded\n error SupplyCapExceeded(address market, uint256 cap);\n\n /// @notice Thrown if the borrow cap is exceeded\n error BorrowCapExceeded(address market, uint256 cap);\n\n /// @param poolRegistry_ Pool registry address\n /// @custom:oz-upgrades-unsafe-allow constructor\n /// @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n constructor(address poolRegistry_) {\n ensureNonzeroAddress(poolRegistry_);\n\n poolRegistry = poolRegistry_;\n _disableInitializers();\n }\n\n /**\n * @param loopLimit Limit for the loops can iterate to avoid the DOS\n * @param accessControlManager Access control manager contract address\n */\n function initialize(uint256 loopLimit, address accessControlManager) external initializer {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager);\n\n _setMaxLoopsLimit(loopLimit);\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation; enabling them to be used as collateral\n * @param vTokens The list of addresses of the vToken markets to be enabled\n * @return errors An array of NO_ERROR for compatibility with Venus core tooling\n * @custom:event MarketEntered is emitted for each market on success\n * @custom:error ActionPaused error is thrown if entering any of the markets is paused\n * @custom:error MarketNotListed error is thrown if any of the markets is not listed\n * @custom:access Not restricted\n */\n function enterMarkets(address[] memory vTokens) external override returns (uint256[] memory) {\n uint256 len = vTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i; i < len; ++i) {\n VToken vToken = VToken(vTokens[i]);\n\n _addToMarket(vToken, msg.sender);\n results[i] = NO_ERROR;\n }\n\n return results;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation; disabling them as collateral\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing necessary collateral for an outstanding borrow.\n * @param vTokenAddress The address of the asset to be removed\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event MarketExited is emitted on success\n * @custom:error ActionPaused error is thrown if exiting the market is paused\n * @custom:error NonzeroBorrowBalance error is thrown if the user has an outstanding borrow in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if exiting the market would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function exitMarket(address vTokenAddress) external override returns (uint256) {\n _checkActionPauseState(vTokenAddress, Action.EXIT_MARKET);\n VToken vToken = VToken(vTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the vToken */\n (uint256 tokensHeld, uint256 amountOwed, ) = _safeGetAccountSnapshot(vToken, msg.sender);\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n revert NonzeroBorrowBalance();\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n _checkRedeemAllowed(vTokenAddress, msg.sender, tokensHeld);\n\n Market storage marketToExit = markets[address(vToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return NO_ERROR;\n }\n\n /* Set vToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete vToken from the account’s list of assets */\n // load into memory for faster iteration\n VToken[] memory userAssetList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n\n uint256 assetIndex = len;\n for (uint256 i; i < len; ++i) {\n if (userAssetList[i] == vToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n VToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.pop();\n\n emit MarketExited(vToken, msg.sender);\n\n return NO_ERROR;\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param vToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @custom:error ActionPaused error is thrown if supplying to this market is paused\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error SupplyCapExceeded error is thrown if the total supply exceeds the cap after minting\n * @custom:access Not restricted\n */\n function preMintHook(address vToken, address minter, uint256 mintAmount) external override {\n _checkActionPauseState(vToken, Action.MINT);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n uint256 supplyCap = supplyCaps[vToken];\n // Skipping the cap check for uncapped coins to save some gas\n if (supplyCap != type(uint256).max) {\n uint256 vTokenSupply = VToken(vToken).totalSupply();\n Exp memory exchangeRate = Exp({ mantissa: VToken(vToken).exchangeRateStored() });\n uint256 nextTotalSupply = mul_ScalarTruncateAddUInt(exchangeRate, vTokenSupply, mintAmount);\n if (nextTotalSupply > supplyCap) {\n revert SupplyCapExceeded(vToken, supplyCap);\n }\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, minter);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param vToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of vTokens to exchange for the underlying asset in the market\n * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function preRedeemHook(address vToken, address redeemer, uint256 redeemTokens) external override {\n _checkActionPauseState(vToken, Action.REDEEM);\n\n _checkRedeemAllowed(vToken, redeemer, redeemTokens);\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, redeemer);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param vToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @custom:error ActionPaused error is thrown if borrowing is paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if there is not enough collateral to borrow\n * @custom:error BorrowCapExceeded is thrown if the borrow cap will be exceeded should this borrow succeed\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted if vToken is enabled as collateral, otherwise only vToken\n */\n /// disable-eslint\n function preBorrowHook(address vToken, address borrower, uint256 borrowAmount) external override {\n _checkActionPauseState(vToken, Action.BORROW);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n if (!markets[vToken].accountMembership[borrower]) {\n // only vTokens may call borrowAllowed if borrower not in market\n _checkSenderIs(vToken);\n\n // attempt to add borrower to the market or revert\n _addToMarket(VToken(msg.sender), borrower);\n }\n\n // Update the prices of tokens\n updatePrices(borrower);\n\n if (oracle.getUnderlyingPrice(vToken) == 0) {\n revert PriceError(address(vToken));\n }\n\n uint256 borrowCap = borrowCaps[vToken];\n // Skipping the cap check for uncapped coins to save some gas\n if (borrowCap != type(uint256).max) {\n uint256 totalBorrows = VToken(vToken).totalBorrows();\n uint256 badDebt = VToken(vToken).badDebt();\n uint256 nextTotalBorrows = totalBorrows + borrowAmount + badDebt;\n if (nextTotalBorrows > borrowCap) {\n revert BorrowCapExceeded(vToken, borrowCap);\n }\n }\n\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n borrower,\n VToken(vToken),\n 0,\n borrowAmount,\n _getCollateralFactor\n );\n\n if (snapshot.shortfall > 0) {\n revert InsufficientLiquidity();\n }\n\n Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param vToken The market to verify the repay against\n * @param borrower The account which would borrowed the asset\n * @custom:error ActionPaused error is thrown if repayments are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:access Not restricted\n */\n function preRepayHook(address vToken, address borrower) external override {\n _checkActionPauseState(vToken, Action.REPAY);\n\n oracle.updatePrice(vToken);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param vTokenBorrowed Asset which was borrowed by the borrower\n * @param vTokenCollateral Asset which was used as collateral and will be seized\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n * @param skipLiquidityCheck Allows the borrow to be liquidated regardless of the account liquidity\n * @custom:error ActionPaused error is thrown if liquidations are paused in this market\n * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n * @custom:error TooMuchRepay error is thrown if the liquidator is trying to repay more than allowed by close factor\n * @custom:error MinimalCollateralViolated is thrown if the users' total collateral is lower than the threshold for non-batch liquidations\n * @custom:error InsufficientShortfall is thrown when trying to liquidate a healthy account\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n */\n function preLiquidateHook(\n address vTokenBorrowed,\n address vTokenCollateral,\n address borrower,\n uint256 repayAmount,\n bool skipLiquidityCheck\n ) external override {\n // Pause Action.LIQUIDATE on BORROWED TOKEN to prevent liquidating it.\n // If we want to pause liquidating to vTokenCollateral, we should pause\n // Action.SEIZE on it\n _checkActionPauseState(vTokenBorrowed, Action.LIQUIDATE);\n\n // Update the prices of tokens\n updatePrices(borrower);\n\n if (!markets[vTokenBorrowed].isListed) {\n revert MarketNotListed(address(vTokenBorrowed));\n }\n if (!markets[vTokenCollateral].isListed) {\n revert MarketNotListed(address(vTokenCollateral));\n }\n\n uint256 borrowBalance = VToken(vTokenBorrowed).borrowBalanceStored(borrower);\n\n /* Allow accounts to be liquidated if the market is deprecated or it is a forced liquidation */\n if (skipLiquidityCheck || isDeprecated(VToken(vTokenBorrowed))) {\n if (repayAmount > borrowBalance) {\n revert TooMuchRepay();\n }\n return;\n }\n\n /* The borrower must have shortfall and collateral > threshold in order to be liquidatable */\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral <= minLiquidatableCollateral) {\n /* The liquidator should use either liquidateAccount or healAccount */\n revert MinimalCollateralViolated(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 maxClose = mul_ScalarTruncate(Exp({ mantissa: closeFactorMantissa }), borrowBalance);\n if (repayAmount > maxClose) {\n revert TooMuchRepay();\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param vTokenCollateral Asset which was used as collateral and will be seized\n * @param seizerContract Contract that tries to seize the asset (either borrowed vToken or Comptroller)\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @custom:error ActionPaused error is thrown if seizing this type of collateral is paused\n * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n * @custom:error ComptrollerMismatch error is when seizer contract or seized asset belong to different pools\n * @custom:access Not restricted\n */\n function preSeizeHook(\n address vTokenCollateral,\n address seizerContract,\n address liquidator,\n address borrower\n ) external override {\n // Pause Action.SEIZE on COLLATERAL to prevent seizing it.\n // If we want to pause liquidating vTokenBorrowed, we should pause\n // Action.LIQUIDATE on it\n _checkActionPauseState(vTokenCollateral, Action.SEIZE);\n\n Market storage market = markets[vTokenCollateral];\n\n if (!market.isListed) {\n revert MarketNotListed(vTokenCollateral);\n }\n\n if (seizerContract == address(this)) {\n // If Comptroller is the seizer, just check if collateral's comptroller\n // is equal to the current address\n if (address(VToken(vTokenCollateral).comptroller()) != address(this)) {\n revert ComptrollerMismatch();\n }\n } else {\n // If the seizer is not the Comptroller, check that the seizer is a\n // listed market, and that the markets' comptrollers match\n if (!markets[seizerContract].isListed) {\n revert MarketNotListed(seizerContract);\n }\n if (VToken(vTokenCollateral).comptroller() != VToken(seizerContract).comptroller()) {\n revert ComptrollerMismatch();\n }\n }\n\n if (!market.accountMembership[borrower]) {\n revert MarketNotCollateral(vTokenCollateral, borrower);\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vTokenCollateral);\n rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, borrower);\n rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, liquidator);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param vToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of vTokens to transfer\n * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function preTransferHook(address vToken, address src, address dst, uint256 transferTokens) external override {\n _checkActionPauseState(vToken, Action.TRANSFER);\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n _checkRedeemAllowed(vToken, src, transferTokens);\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, src);\n rewardsDistributor.distributeSupplierRewardToken(vToken, dst);\n }\n }\n\n /*** Pool-level operations ***/\n\n /**\n * @notice Seizes all the remaining collateral, makes msg.sender repay the existing\n * borrows, and treats the rest of the debt as bad debt (for each market).\n * The sender has to repay a certain percentage of the debt, computed as\n * collateral / (borrows * liquidationIncentive).\n * @param user account to heal\n * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for healing\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function healAccount(address user) external {\n VToken[] memory userAssets = accountAssets[user];\n uint256 userAssetsCount = userAssets.length;\n\n address liquidator = msg.sender;\n {\n ResilientOracleInterface oracle_ = oracle;\n // We need all user's markets to be fresh for the computations to be correct\n for (uint256 i; i < userAssetsCount; ++i) {\n userAssets[i].accrueInterest();\n oracle_.updatePrice(address(userAssets[i]));\n }\n }\n\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(user, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral > minLiquidatableCollateral) {\n revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n // percentage = collateral / (borrows * liquidation incentive)\n Exp memory collateral = Exp({ mantissa: snapshot.totalCollateral });\n Exp memory scaledBorrows = mul_(\n Exp({ mantissa: snapshot.borrows }),\n Exp({ mantissa: liquidationIncentiveMantissa })\n );\n\n Exp memory percentage = div_(collateral, scaledBorrows);\n if (lessThanExp(Exp({ mantissa: MANTISSA_ONE }), percentage)) {\n revert CollateralExceedsThreshold(scaledBorrows.mantissa, collateral.mantissa);\n }\n\n for (uint256 i; i < userAssetsCount; ++i) {\n VToken market = userAssets[i];\n\n (uint256 tokens, uint256 borrowBalance, ) = _safeGetAccountSnapshot(market, user);\n uint256 repaymentAmount = mul_ScalarTruncate(percentage, borrowBalance);\n\n // Seize the entire collateral\n if (tokens != 0) {\n market.seize(liquidator, user, tokens);\n }\n // Repay a certain percentage of the borrow, forgive the rest\n if (borrowBalance != 0) {\n market.healBorrow(liquidator, user, repaymentAmount);\n }\n }\n }\n\n /**\n * @notice Liquidates all borrows of the borrower. Callable only if the collateral is less than\n * a predefined threshold, and the account collateral can be seized to cover all borrows. If\n * the collateral is higher than the threshold, use regular liquidations. If the collateral is\n * below the threshold, and the account is insolvent, use healAccount.\n * @param borrower the borrower address\n * @param orders an array of liquidation orders\n * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for a batch liquidation\n * @custom:error InsufficientCollateral error is thrown when there is not enough collateral to cover the debt\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function liquidateAccount(address borrower, LiquidationOrder[] calldata orders) external {\n // We will accrue interest and update the oracle prices later during the liquidation\n\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral > minLiquidatableCollateral) {\n // You should use the regular vToken.liquidateBorrow(...) call\n revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n uint256 collateralToSeize = mul_ScalarTruncate(\n Exp({ mantissa: liquidationIncentiveMantissa }),\n snapshot.borrows\n );\n if (collateralToSeize >= snapshot.totalCollateral) {\n // There is not enough collateral to seize. Use healBorrow to repay some part of the borrow\n // and record bad debt.\n revert InsufficientCollateral(collateralToSeize, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n uint256 ordersCount = orders.length;\n\n _ensureMaxLoops(ordersCount / 2);\n\n for (uint256 i; i < ordersCount; ++i) {\n if (!markets[address(orders[i].vTokenBorrowed)].isListed) {\n revert MarketNotListed(address(orders[i].vTokenBorrowed));\n }\n if (!markets[address(orders[i].vTokenCollateral)].isListed) {\n revert MarketNotListed(address(orders[i].vTokenCollateral));\n }\n\n LiquidationOrder calldata order = orders[i];\n order.vTokenBorrowed.forceLiquidateBorrow(\n msg.sender,\n borrower,\n order.repayAmount,\n order.vTokenCollateral,\n true\n );\n }\n\n VToken[] memory borrowMarkets = accountAssets[borrower];\n uint256 marketsCount = borrowMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n (, uint256 borrowBalance, ) = _safeGetAccountSnapshot(borrowMarkets[i], borrower);\n require(borrowBalance == 0, \"Nonzero borrow balance after liquidation\");\n }\n }\n\n /**\n * @notice Sets the closeFactor to use when liquidating borrows\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @custom:event Emits NewCloseFactor on success\n * @custom:access Controlled by AccessControlManager\n */\n function setCloseFactor(uint256 newCloseFactorMantissa) external {\n _checkAccessAllowed(\"setCloseFactor(uint256)\");\n require(MAX_CLOSE_FACTOR_MANTISSA >= newCloseFactorMantissa, \"Close factor greater than maximum close factor\");\n require(MIN_CLOSE_FACTOR_MANTISSA <= newCloseFactorMantissa, \"Close factor smaller than minimum close factor\");\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, newCloseFactorMantissa);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev This function is restricted by the AccessControlManager\n * @param vToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @param newLiquidationThresholdMantissa The new liquidation threshold, scaled by 1e18\n * @custom:event Emits NewCollateralFactor when collateral factor is updated\n * and NewLiquidationThreshold when liquidation threshold is updated\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InvalidCollateralFactor error is thrown when collateral factor is too high\n * @custom:error InvalidLiquidationThreshold error is thrown when liquidation threshold is lower than collateral factor\n * @custom:error PriceError is thrown when the oracle returns an invalid price for the asset\n * @custom:access Controlled by AccessControlManager\n */\n function setCollateralFactor(\n VToken vToken,\n uint256 newCollateralFactorMantissa,\n uint256 newLiquidationThresholdMantissa\n ) external {\n _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n\n // Verify market is listed\n Market storage market = markets[address(vToken)];\n if (!market.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n // Check collateral factor <= 0.9\n if (newCollateralFactorMantissa > MAX_COLLATERAL_FACTOR_MANTISSA) {\n revert InvalidCollateralFactor();\n }\n\n // Ensure that liquidation threshold <= 1\n if (newLiquidationThresholdMantissa > MANTISSA_ONE) {\n revert InvalidLiquidationThreshold();\n }\n\n // Ensure that liquidation threshold >= CF\n if (newLiquidationThresholdMantissa < newCollateralFactorMantissa) {\n revert InvalidLiquidationThreshold();\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(address(vToken)) == 0) {\n revert PriceError(address(vToken));\n }\n\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n if (newCollateralFactorMantissa != oldCollateralFactorMantissa) {\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n emit NewCollateralFactor(vToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n }\n\n uint256 oldLiquidationThresholdMantissa = market.liquidationThresholdMantissa;\n if (newLiquidationThresholdMantissa != oldLiquidationThresholdMantissa) {\n market.liquidationThresholdMantissa = newLiquidationThresholdMantissa;\n emit NewLiquidationThreshold(vToken, oldLiquidationThresholdMantissa, newLiquidationThresholdMantissa);\n }\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev This function is restricted by the AccessControlManager\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @custom:event Emits NewLiquidationIncentive on success\n * @custom:access Controlled by AccessControlManager\n */\n function setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) external {\n require(newLiquidationIncentiveMantissa >= MANTISSA_ONE, \"liquidation incentive should be greater than 1e18\");\n\n _checkAccessAllowed(\"setLiquidationIncentive(uint256)\");\n\n // Save current value for use in log\n uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Only callable by the PoolRegistry\n * @param vToken The address of the market (token) to list\n * @custom:error MarketAlreadyListed is thrown if the market is already listed in this pool\n * @custom:access Only PoolRegistry\n */\n function supportMarket(VToken vToken) external {\n _checkSenderIs(poolRegistry);\n\n if (markets[address(vToken)].isListed) {\n revert MarketAlreadyListed(address(vToken));\n }\n\n require(vToken.isVToken(), \"Comptroller: Invalid vToken\"); // Sanity check to make sure its really a VToken\n\n Market storage newMarket = markets[address(vToken)];\n newMarket.isListed = true;\n newMarket.collateralFactorMantissa = 0;\n newMarket.liquidationThresholdMantissa = 0;\n\n _addMarket(address(vToken));\n\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n rewardsDistributors[i].initializeMarket(address(vToken));\n }\n\n emit MarketSupported(vToken);\n }\n\n /**\n * @notice Set the given borrow caps for the given vToken markets. Borrowing that brings total borrows to or above borrow cap will revert.\n * @dev This function is restricted by the AccessControlManager\n * @dev A borrow cap of type(uint256).max corresponds to unlimited borrowing.\n * @dev Borrow caps smaller than the current total borrows are accepted. This way, new borrows will not be allowed\n until the total borrows amount goes below the new borrow cap\n * @param vTokens The addresses of the markets (tokens) to change the borrow caps for\n * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited borrowing.\n * @custom:access Controlled by AccessControlManager\n */\n function setMarketBorrowCaps(VToken[] calldata vTokens, uint256[] calldata newBorrowCaps) external {\n _checkAccessAllowed(\"setMarketBorrowCaps(address[],uint256[])\");\n\n uint256 numMarkets = vTokens.length;\n uint256 numBorrowCaps = newBorrowCaps.length;\n\n require(numMarkets != 0 && numMarkets == numBorrowCaps, \"invalid input\");\n\n _ensureMaxLoops(numMarkets);\n\n for (uint256 i; i < numMarkets; ++i) {\n borrowCaps[address(vTokens[i])] = newBorrowCaps[i];\n emit NewBorrowCap(vTokens[i], newBorrowCaps[i]);\n }\n }\n\n /**\n * @notice Set the given supply caps for the given vToken markets. Supply that brings total Supply to or above supply cap will revert.\n * @dev This function is restricted by the AccessControlManager\n * @dev A supply cap of type(uint256).max corresponds to unlimited supply.\n * @dev Supply caps smaller than the current total supplies are accepted. This way, new supplies will not be allowed\n until the total supplies amount goes below the new supply cap\n * @param vTokens The addresses of the markets (tokens) to change the supply caps for\n * @param newSupplyCaps The new supply cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited supply.\n * @custom:access Controlled by AccessControlManager\n */\n function setMarketSupplyCaps(VToken[] calldata vTokens, uint256[] calldata newSupplyCaps) external {\n _checkAccessAllowed(\"setMarketSupplyCaps(address[],uint256[])\");\n uint256 vTokensCount = vTokens.length;\n\n require(vTokensCount != 0, \"invalid number of markets\");\n require(vTokensCount == newSupplyCaps.length, \"invalid number of markets\");\n\n _ensureMaxLoops(vTokensCount);\n\n for (uint256 i; i < vTokensCount; ++i) {\n supplyCaps[address(vTokens[i])] = newSupplyCaps[i];\n emit NewSupplyCap(vTokens[i], newSupplyCaps[i]);\n }\n }\n\n /**\n * @notice Pause/unpause specified actions\n * @dev This function is restricted by the AccessControlManager\n * @param marketsList Markets to pause/unpause the actions on\n * @param actionsList List of action ids to pause/unpause\n * @param paused The new paused state (true=paused, false=unpaused)\n * @custom:access Controlled by AccessControlManager\n */\n function setActionsPaused(VToken[] calldata marketsList, Action[] calldata actionsList, bool paused) external {\n _checkAccessAllowed(\"setActionsPaused(address[],uint256[],bool)\");\n\n uint256 marketsCount = marketsList.length;\n uint256 actionsCount = actionsList.length;\n\n _ensureMaxLoops(marketsCount * actionsCount);\n\n for (uint256 marketIdx; marketIdx < marketsCount; ++marketIdx) {\n for (uint256 actionIdx; actionIdx < actionsCount; ++actionIdx) {\n _setActionPaused(address(marketsList[marketIdx]), actionsList[actionIdx], paused);\n }\n }\n }\n\n /**\n * @notice Set the given collateral threshold for non-batch liquidations. Regular liquidations\n * will fail if the collateral amount is less than this threshold. Liquidators should use batch\n * operations like liquidateAccount or healAccount.\n * @dev This function is restricted by the AccessControlManager\n * @param newMinLiquidatableCollateral The new min liquidatable collateral (in USD).\n * @custom:access Controlled by AccessControlManager\n */\n function setMinLiquidatableCollateral(uint256 newMinLiquidatableCollateral) external {\n _checkAccessAllowed(\"setMinLiquidatableCollateral(uint256)\");\n\n uint256 oldMinLiquidatableCollateral = minLiquidatableCollateral;\n minLiquidatableCollateral = newMinLiquidatableCollateral;\n emit NewMinLiquidatableCollateral(oldMinLiquidatableCollateral, newMinLiquidatableCollateral);\n }\n\n /**\n * @notice Add a new RewardsDistributor and initialize it with all markets. We can add several RewardsDistributor\n * contracts with the same rewardToken, and there could be overlaping among them considering the last reward block\n * @dev Only callable by the admin\n * @param _rewardsDistributor Address of the RewardDistributor contract to add\n * @custom:access Only Governance\n * @custom:event Emits NewRewardsDistributor with distributor address\n */\n function addRewardsDistributor(RewardsDistributor _rewardsDistributor) external onlyOwner {\n require(!rewardsDistributorExists[address(_rewardsDistributor)], \"already exists\");\n\n uint256 rewardsDistributorsLen = rewardsDistributors.length;\n _ensureMaxLoops(rewardsDistributorsLen + 1);\n\n rewardsDistributors.push(_rewardsDistributor);\n rewardsDistributorExists[address(_rewardsDistributor)] = true;\n\n uint256 marketsCount = allMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n _rewardsDistributor.initializeMarket(address(allMarkets[i]));\n }\n\n emit NewRewardsDistributor(address(_rewardsDistributor), address(_rewardsDistributor.rewardToken()));\n }\n\n /**\n * @notice Sets a new price oracle for the Comptroller\n * @dev Only callable by the admin\n * @param newOracle Address of the new price oracle to set\n * @custom:event Emits NewPriceOracle on success\n * @custom:error ZeroAddressNotAllowed is thrown when the new oracle address is zero\n */\n function setPriceOracle(ResilientOracleInterface newOracle) external onlyOwner {\n ensureNonzeroAddress(address(newOracle));\n\n ResilientOracleInterface oldOracle = oracle;\n oracle = newOracle;\n emit NewPriceOracle(oldOracle, newOracle);\n }\n\n /**\n * @notice Set the for loop iteration limit to avoid DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Determine the current account liquidity with respect to liquidation threshold requirements\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param account The account get liquidity for\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Account liquidity in excess of liquidation threshold requirements,\n * @return shortfall Account shortfall below liquidation threshold requirements\n */\n function getAccountLiquidity(\n address account\n ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getLiquidationThreshold);\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity with respect to collateral requirements\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param account The account get liquidity for\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Account liquidity in excess of collateral requirements,\n * @return shortfall Account shortfall below collateral requirements\n */\n function getBorrowingPower(\n address account\n ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getCollateralFactor);\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param vTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Hypothetical account liquidity in excess of collateral requirements,\n * @return shortfall Hypothetical account shortfall below collateral requirements\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address vTokenModify,\n uint256 redeemTokens,\n uint256 borrowAmount\n ) external view returns (uint256 error, uint256 liquidity, uint256 shortfall) {\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n account,\n VToken(vTokenModify),\n redeemTokens,\n borrowAmount,\n _getCollateralFactor\n );\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return markets The list of market addresses\n */\n function getAllMarkets() external view override returns (VToken[] memory) {\n return allMarkets;\n }\n\n /**\n * @notice Check if a market is marked as listed (active)\n * @param vToken vToken Address for the market to check\n * @return listed True if listed otherwise false\n */\n function isMarketListed(VToken vToken) external view returns (bool) {\n return markets[address(vToken)].isListed;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (VToken[] memory) {\n VToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in a given market\n * @param account The address of the account to check\n * @param vToken The vToken to check\n * @return True if the account is in the market specified, otherwise false.\n */\n function checkMembership(address account, VToken vToken) external view returns (bool) {\n return markets[address(vToken)].accountMembership[account];\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in vToken.liquidateBorrowFresh)\n * @param vTokenBorrowed The address of the borrowed vToken\n * @param vTokenCollateral The address of the collateral vToken\n * @param actualRepayAmount The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return tokensToSeize Number of vTokenCollateral tokens to be seized in a liquidation\n * @custom:error PriceError if the oracle returns an invalid price\n */\n function liquidateCalculateSeizeTokens(\n address vTokenBorrowed,\n address vTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256 error, uint256 tokensToSeize) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = _safeGetUnderlyingPrice(VToken(vTokenBorrowed));\n uint256 priceCollateralMantissa = _safeGetUnderlyingPrice(VToken(vTokenCollateral));\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint256 exchangeRateMantissa = VToken(vTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n\n numerator = mul_(Exp({ mantissa: liquidationIncentiveMantissa }), Exp({ mantissa: priceBorrowedMantissa }));\n denominator = mul_(Exp({ mantissa: priceCollateralMantissa }), Exp({ mantissa: exchangeRateMantissa }));\n ratio = div_(numerator, denominator);\n\n seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n return (NO_ERROR, seizeTokens);\n }\n\n /**\n * @notice Returns reward speed given a vToken\n * @param vToken The vToken to get the reward speeds for\n * @return rewardSpeeds Array of total supply and borrow speeds and reward token for all reward distributors\n */\n function getRewardsByMarket(address vToken) external view returns (RewardSpeeds[] memory rewardSpeeds) {\n uint256 rewardsDistributorsLength = rewardsDistributors.length;\n rewardSpeeds = new RewardSpeeds[](rewardsDistributorsLength);\n for (uint256 i; i < rewardsDistributorsLength; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n address rewardToken = address(rewardsDistributor.rewardToken());\n rewardSpeeds[i] = RewardSpeeds({\n rewardToken: rewardToken,\n supplySpeed: rewardsDistributor.rewardTokenSupplySpeeds(vToken),\n borrowSpeed: rewardsDistributor.rewardTokenBorrowSpeeds(vToken)\n });\n }\n return rewardSpeeds;\n }\n\n /**\n * @notice Return all reward distributors for this pool\n * @return Array of RewardDistributor addresses\n */\n function getRewardDistributors() external view returns (RewardsDistributor[] memory) {\n return rewardsDistributors;\n }\n\n /**\n * @notice A marker method that returns true for a valid Comptroller contract\n * @return Always true\n */\n function isComptroller() external pure override returns (bool) {\n return true;\n }\n\n /**\n * @notice Update the prices of all the tokens associated with the provided account\n * @param account Address of the account to get associated tokens with\n */\n function updatePrices(address account) public {\n VToken[] memory vTokens = accountAssets[account];\n uint256 vTokensCount = vTokens.length;\n\n ResilientOracleInterface oracle_ = oracle;\n\n for (uint256 i; i < vTokensCount; ++i) {\n oracle_.updatePrice(address(vTokens[i]));\n }\n }\n\n /**\n * @notice Checks if a certain action is paused on a market\n * @param market vToken address\n * @param action Action to check\n * @return paused True if the action is paused otherwise false\n */\n function actionPaused(address market, Action action) public view returns (bool) {\n return _actionPaused[market][action];\n }\n\n /**\n * @notice Check if a vToken market has been deprecated\n * @dev All borrows in a deprecated vToken market can be immediately liquidated\n * @param vToken The market to check if deprecated\n * @return deprecated True if the given vToken market has been deprecated\n */\n function isDeprecated(VToken vToken) public view returns (bool) {\n return\n markets[address(vToken)].collateralFactorMantissa == 0 &&\n actionPaused(address(vToken), Action.BORROW) &&\n vToken.reserveFactorMantissa() == MANTISSA_ONE;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param vToken The market to enter\n * @param borrower The address of the account to modify\n */\n function _addToMarket(VToken vToken, address borrower) internal {\n _checkActionPauseState(address(vToken), Action.ENTER_MARKET);\n Market storage marketToJoin = markets[address(vToken)];\n\n if (!marketToJoin.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n if (marketToJoin.accountMembership[borrower]) {\n // already joined\n return;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(vToken);\n\n emit MarketEntered(vToken, borrower);\n }\n\n /**\n * @notice Internal function to validate that a market hasn't already been added\n * and if it hasn't adds it\n * @param vToken The market to support\n */\n function _addMarket(address vToken) internal {\n uint256 marketsCount = allMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n if (allMarkets[i] == VToken(vToken)) {\n revert MarketAlreadyListed(vToken);\n }\n }\n allMarkets.push(VToken(vToken));\n marketsCount = allMarkets.length;\n _ensureMaxLoops(marketsCount);\n }\n\n /**\n * @dev Pause/unpause an action on a market\n * @param market Market to pause/unpause the action on\n * @param action Action id to pause/unpause\n * @param paused The new paused state (true=paused, false=unpaused)\n */\n function _setActionPaused(address market, Action action, bool paused) internal {\n require(markets[market].isListed, \"cannot pause a market that is not listed\");\n _actionPaused[market][action] = paused;\n emit ActionPausedMarket(VToken(market), action, paused);\n }\n\n /**\n * @dev Internal function to check that vTokens can be safely redeemed for the underlying asset.\n * @param vToken Address of the vTokens to redeem\n * @param redeemer Account redeeming the tokens\n * @param redeemTokens The number of tokens to redeem\n */\n function _checkRedeemAllowed(address vToken, address redeemer, uint256 redeemTokens) internal {\n Market storage market = markets[vToken];\n\n if (!market.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!market.accountMembership[redeemer]) {\n return;\n }\n\n // Update the prices of tokens\n updatePrices(redeemer);\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n redeemer,\n VToken(vToken),\n redeemTokens,\n 0,\n _getCollateralFactor\n );\n if (snapshot.shortfall > 0) {\n revert InsufficientLiquidity();\n }\n }\n\n /**\n * @notice Get the total collateral, weighted collateral, borrow balance, liquidity, shortfall\n * @param account The account to get the snapshot for\n * @param weight The function to compute the weight of the collateral – either collateral factor or\n * liquidation threshold. Accepts the address of the vToken and returns the weight as Exp.\n * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n * without calculating accumulated interest.\n * @return snapshot Account liquidity snapshot\n */\n function _getCurrentLiquiditySnapshot(\n address account,\n function(VToken) internal view returns (Exp memory) weight\n ) internal view returns (AccountLiquiditySnapshot memory snapshot) {\n return _getHypotheticalLiquiditySnapshot(account, VToken(address(0)), 0, 0, weight);\n }\n\n /**\n * @notice Determine what the supply/borrow balances would be if the given amounts were redeemed/borrowed\n * @param vTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @param weight The function to compute the weight of the collateral – either collateral factor or\n liquidation threshold. Accepts the address of the VToken and returns the weight\n * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n * without calculating accumulated interest.\n * @return snapshot Account liquidity snapshot\n */\n function _getHypotheticalLiquiditySnapshot(\n address account,\n VToken vTokenModify,\n uint256 redeemTokens,\n uint256 borrowAmount,\n function(VToken) internal view returns (Exp memory) weight\n ) internal view returns (AccountLiquiditySnapshot memory snapshot) {\n // For each asset the account is in\n VToken[] memory assets = accountAssets[account];\n uint256 assetsCount = assets.length;\n\n for (uint256 i; i < assetsCount; ++i) {\n VToken asset = assets[i];\n\n // Read the balances and exchange rate from the vToken\n (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) = _safeGetAccountSnapshot(\n asset,\n account\n );\n\n // Get the normalized price of the asset\n Exp memory oraclePrice = Exp({ mantissa: _safeGetUnderlyingPrice(asset) });\n\n // Pre-compute conversion factors from vTokens -> usd\n Exp memory vTokenPrice = mul_(Exp({ mantissa: exchangeRateMantissa }), oraclePrice);\n Exp memory weightedVTokenPrice = mul_(weight(asset), vTokenPrice);\n\n // weightedCollateral += weightedVTokenPrice * vTokenBalance\n snapshot.weightedCollateral = mul_ScalarTruncateAddUInt(\n weightedVTokenPrice,\n vTokenBalance,\n snapshot.weightedCollateral\n );\n\n // totalCollateral += vTokenPrice * vTokenBalance\n snapshot.totalCollateral = mul_ScalarTruncateAddUInt(vTokenPrice, vTokenBalance, snapshot.totalCollateral);\n\n // borrows += oraclePrice * borrowBalance\n snapshot.borrows = mul_ScalarTruncateAddUInt(oraclePrice, borrowBalance, snapshot.borrows);\n\n // Calculate effects of interacting with vTokenModify\n if (asset == vTokenModify) {\n // redeem effect\n // effects += tokensToDenom * redeemTokens\n snapshot.effects = mul_ScalarTruncateAddUInt(weightedVTokenPrice, redeemTokens, snapshot.effects);\n\n // borrow effect\n // effects += oraclePrice * borrowAmount\n snapshot.effects = mul_ScalarTruncateAddUInt(oraclePrice, borrowAmount, snapshot.effects);\n }\n }\n\n uint256 borrowPlusEffects = snapshot.borrows + snapshot.effects;\n // These are safe, as the underflow condition is checked first\n unchecked {\n if (snapshot.weightedCollateral > borrowPlusEffects) {\n snapshot.liquidity = snapshot.weightedCollateral - borrowPlusEffects;\n snapshot.shortfall = 0;\n } else {\n snapshot.liquidity = 0;\n snapshot.shortfall = borrowPlusEffects - snapshot.weightedCollateral;\n }\n }\n\n return snapshot;\n }\n\n /**\n * @dev Retrieves price from oracle for an asset and checks it is nonzero\n * @param asset Address for asset to query price\n * @return Underlying price\n */\n function _safeGetUnderlyingPrice(VToken asset) internal view returns (uint256) {\n uint256 oraclePriceMantissa = oracle.getUnderlyingPrice(address(asset));\n if (oraclePriceMantissa == 0) {\n revert PriceError(address(asset));\n }\n return oraclePriceMantissa;\n }\n\n /**\n * @dev Return collateral factor for a market\n * @param asset Address for asset\n * @return Collateral factor as exponential\n */\n function _getCollateralFactor(VToken asset) internal view returns (Exp memory) {\n return Exp({ mantissa: markets[address(asset)].collateralFactorMantissa });\n }\n\n /**\n * @dev Retrieves liquidation threshold for a market as an exponential\n * @param asset Address for asset to liquidation threshold\n * @return Liquidation threshold as exponential\n */\n function _getLiquidationThreshold(VToken asset) internal view returns (Exp memory) {\n return Exp({ mantissa: markets[address(asset)].liquidationThresholdMantissa });\n }\n\n /**\n * @dev Returns supply and borrow balances of user in vToken, reverts on failure\n * @param vToken Market to query\n * @param user Account address\n * @return vTokenBalance Balance of vTokens, the same as vToken.balanceOf(user)\n * @return borrowBalance Borrowed amount, including the interest\n * @return exchangeRateMantissa Stored exchange rate\n */\n function _safeGetAccountSnapshot(\n VToken vToken,\n address user\n ) internal view returns (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) {\n uint256 err;\n (err, vTokenBalance, borrowBalance, exchangeRateMantissa) = vToken.getAccountSnapshot(user);\n if (err != 0) {\n revert SnapshotError(address(vToken), user);\n }\n return (vTokenBalance, borrowBalance, exchangeRateMantissa);\n }\n\n /// @notice Reverts if the call is not from expectedSender\n /// @param expectedSender Expected transaction sender\n function _checkSenderIs(address expectedSender) internal view {\n if (msg.sender != expectedSender) {\n revert UnexpectedSender(expectedSender, msg.sender);\n }\n }\n\n /// @notice Reverts if a certain action is paused on a market\n /// @param market Market to check\n /// @param action Action to check\n function _checkActionPauseState(address market, Action action) private view {\n if (actionPaused(market, action)) {\n revert ActionPaused(market, action);\n }\n }\n}\n" + }, + "contracts/ComptrollerInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\n/**\n * @title ComptrollerInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract.\n */\ninterface ComptrollerInterface {\n /*** Assets You Are In ***/\n\n function enterMarkets(address[] calldata vTokens) external returns (uint256[] memory);\n\n function exitMarket(address vToken) external returns (uint256);\n\n /*** Policy Hooks ***/\n\n function preMintHook(address vToken, address minter, uint256 mintAmount) external;\n\n function preRedeemHook(address vToken, address redeemer, uint256 redeemTokens) external;\n\n function preBorrowHook(address vToken, address borrower, uint256 borrowAmount) external;\n\n function preRepayHook(address vToken, address borrower) external;\n\n function preLiquidateHook(\n address vTokenBorrowed,\n address vTokenCollateral,\n address borrower,\n uint256 repayAmount,\n bool skipLiquidityCheck\n ) external;\n\n function preSeizeHook(\n address vTokenCollateral,\n address vTokenBorrowed,\n address liquidator,\n address borrower\n ) external;\n\n function preTransferHook(address vToken, address src, address dst, uint256 transferTokens) external;\n\n function isComptroller() external view returns (bool);\n\n /*** Liquidity/Liquidation Calculations ***/\n\n function liquidateCalculateSeizeTokens(\n address vTokenBorrowed,\n address vTokenCollateral,\n uint256 repayAmount\n ) external view returns (uint256, uint256);\n\n function getAllMarkets() external view returns (VToken[] memory);\n}\n\n/**\n * @title ComptrollerViewInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract, including only some util view functions.\n */\ninterface ComptrollerViewInterface {\n function markets(address) external view returns (bool, uint256);\n\n function oracle() external view returns (ResilientOracleInterface);\n\n function getAssetsIn(address) external view returns (VToken[] memory);\n\n function closeFactorMantissa() external view returns (uint256);\n\n function liquidationIncentiveMantissa() external view returns (uint256);\n\n function minLiquidatableCollateral() external view returns (uint256);\n\n function getRewardDistributors() external view returns (RewardsDistributor[] memory);\n\n function getAllMarkets() external view returns (VToken[] memory);\n\n function borrowCaps(address) external view returns (uint256);\n\n function supplyCaps(address) external view returns (uint256);\n}\n" + }, + "contracts/ComptrollerStorage.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\n/**\n * @title ComptrollerStorage\n * @author Venus\n * @notice Storage layout for the `Comptroller` contract.\n */\ncontract ComptrollerStorage {\n struct LiquidationOrder {\n VToken vTokenCollateral;\n VToken vTokenBorrowed;\n uint256 repayAmount;\n }\n\n struct AccountLiquiditySnapshot {\n uint256 totalCollateral;\n uint256 weightedCollateral;\n uint256 borrows;\n uint256 effects;\n uint256 liquidity;\n uint256 shortfall;\n }\n\n struct RewardSpeeds {\n address rewardToken;\n uint256 supplySpeed;\n uint256 borrowSpeed;\n }\n\n struct Market {\n // Whether or not this market is listed\n bool isListed;\n // Multiplier representing the most one can borrow against their collateral in this market.\n // For instance, 0.9 to allow borrowing 90% of collateral value.\n // Must be between 0 and 1, and stored as a mantissa.\n uint256 collateralFactorMantissa;\n // Multiplier representing the collateralization after which the borrow is eligible\n // for liquidation. For instance, 0.8 liquidate when the borrow is 80% of collateral\n // value. Must be between 0 and collateral factor, stored as a mantissa.\n uint256 liquidationThresholdMantissa;\n // Per-market mapping of \"accounts in this asset\"\n mapping(address => bool) accountMembership;\n }\n\n enum Action {\n MINT,\n REDEEM,\n BORROW,\n REPAY,\n SEIZE,\n LIQUIDATE,\n TRANSFER,\n ENTER_MARKET,\n EXIT_MARKET\n }\n\n /**\n * @notice Oracle which gives the price of any given asset\n */\n ResilientOracleInterface public oracle;\n\n /**\n * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow\n */\n uint256 public closeFactorMantissa;\n\n /**\n * @notice Multiplier representing the discount on collateral that a liquidator receives\n */\n uint256 public liquidationIncentiveMantissa;\n\n /**\n * @notice Per-account mapping of \"assets you are in\"\n */\n mapping(address => VToken[]) public accountAssets;\n\n /**\n * @notice Official mapping of vTokens -> Market metadata\n * @dev Used e.g. to determine if a market is supported\n */\n mapping(address => Market) public markets;\n\n /// @notice A list of all markets\n VToken[] public allMarkets;\n\n /// @notice Borrow caps enforced by borrowAllowed for each vToken address. Defaults to zero which restricts borrowing.\n mapping(address => uint256) public borrowCaps;\n\n /// @notice Minimal collateral required for regular (non-batch) liquidations\n uint256 public minLiquidatableCollateral;\n\n /// @notice Supply caps enforced by mintAllowed for each vToken address. Defaults to zero which corresponds to minting not allowed\n mapping(address => uint256) public supplyCaps;\n\n /// @notice True if a certain action is paused on a certain market\n mapping(address => mapping(Action => bool)) internal _actionPaused;\n\n // List of Reward Distributors added\n RewardsDistributor[] internal rewardsDistributors;\n\n // Used to check if rewards distributor is added\n mapping(address => bool) internal rewardsDistributorExists;\n\n uint256 internal constant NO_ERROR = 0;\n\n // closeFactorMantissa must be strictly greater than this value\n uint256 internal constant MIN_CLOSE_FACTOR_MANTISSA = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant MAX_CLOSE_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant MAX_COLLATERAL_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "contracts/ErrorReporter.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title TokenErrorReporter\n * @author Venus\n * @notice Errors that can be thrown by the `VToken` contract.\n */\ncontract TokenErrorReporter {\n uint256 public constant NO_ERROR = 0; // support legacy return codes\n\n error TransferNotAllowed();\n\n error MintFreshnessCheck();\n\n error RedeemFreshnessCheck();\n error RedeemTransferOutNotPossible();\n\n error BorrowFreshnessCheck();\n error BorrowCashNotAvailable();\n\n error RepayBorrowFreshnessCheck();\n\n error HealBorrowUnauthorized();\n error ForceLiquidateBorrowUnauthorized();\n\n error LiquidateFreshnessCheck();\n error LiquidateCollateralFreshnessCheck();\n error LiquidateAccrueCollateralInterestFailed(uint256 errorCode);\n error LiquidateLiquidatorIsBorrower();\n error LiquidateCloseAmountIsZero();\n error LiquidateCloseAmountIsUintMax();\n\n error LiquidateSeizeLiquidatorIsBorrower();\n\n error ProtocolSeizeShareTooBig();\n\n error SetReserveFactorFreshCheck();\n error SetReserveFactorBoundsCheck();\n\n error AddReservesFactorFreshCheck(uint256 actualAddAmount);\n\n error ReduceReservesFreshCheck();\n error ReduceReservesCashNotAvailable();\n error ReduceReservesCashValidation();\n\n error SetInterestRateModelFreshCheck();\n}\n" + }, + "contracts/ExponentialNoError.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { EXP_SCALE as EXP_SCALE_, MANTISSA_ONE as MANTISSA_ONE_ } from \"./lib/constants.sol\";\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author Compound\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\n * `Exp({mantissa: 5100000000000000000})`.\n */\ncontract ExponentialNoError {\n struct Exp {\n uint256 mantissa;\n }\n\n struct Double {\n uint256 mantissa;\n }\n\n uint256 internal constant EXP_SCALE = EXP_SCALE_;\n uint256 internal constant DOUBLE_SCALE = 1e36;\n uint256 internal constant HALF_EXP_SCALE = EXP_SCALE / 2;\n uint256 internal constant MANTISSA_ONE = MANTISSA_ONE_;\n\n /**\n * @dev Truncates the given exp to a whole number value.\n * For example, truncate(Exp{mantissa: 15 * EXP_SCALE}) = 15\n */\n function truncate(Exp memory exp) internal pure returns (uint256) {\n // Note: We are not using careful math here as we're performing a division that cannot fail\n return exp.mantissa / EXP_SCALE;\n }\n\n /**\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\n */\n // solhint-disable-next-line func-name-mixedcase\n function mul_ScalarTruncate(Exp memory a, uint256 scalar) internal pure returns (uint256) {\n Exp memory product = mul_(a, scalar);\n return truncate(product);\n }\n\n /**\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\n */\n // solhint-disable-next-line func-name-mixedcase\n function mul_ScalarTruncateAddUInt(Exp memory a, uint256 scalar, uint256 addend) internal pure returns (uint256) {\n Exp memory product = mul_(a, scalar);\n return add_(truncate(product), addend);\n }\n\n /**\n * @dev Checks if first Exp is less than second Exp.\n */\n function lessThanExp(Exp memory left, Exp memory right) internal pure returns (bool) {\n return left.mantissa < right.mantissa;\n }\n\n function safe224(uint256 n, string memory errorMessage) internal pure returns (uint224) {\n require(n <= type(uint224).max, errorMessage);\n return uint224(n);\n }\n\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n <= type(uint32).max, errorMessage);\n return uint32(n);\n }\n\n function add_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: add_(a.mantissa, b.mantissa) });\n }\n\n function add_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: add_(a.mantissa, b.mantissa) });\n }\n\n function add_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n function sub_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: sub_(a.mantissa, b.mantissa) });\n }\n\n function sub_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: sub_(a.mantissa, b.mantissa) });\n }\n\n function sub_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n function mul_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: mul_(a.mantissa, b.mantissa) / EXP_SCALE });\n }\n\n function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n return Exp({ mantissa: mul_(a.mantissa, b) });\n }\n\n function mul_(uint256 a, Exp memory b) internal pure returns (uint256) {\n return mul_(a, b.mantissa) / EXP_SCALE;\n }\n\n function mul_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: mul_(a.mantissa, b.mantissa) / DOUBLE_SCALE });\n }\n\n function mul_(Double memory a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: mul_(a.mantissa, b) });\n }\n\n function mul_(uint256 a, Double memory b) internal pure returns (uint256) {\n return mul_(a, b.mantissa) / DOUBLE_SCALE;\n }\n\n function mul_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n function div_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: div_(mul_(a.mantissa, EXP_SCALE), b.mantissa) });\n }\n\n function div_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n return Exp({ mantissa: div_(a.mantissa, b) });\n }\n\n function div_(uint256 a, Exp memory b) internal pure returns (uint256) {\n return div_(mul_(a, EXP_SCALE), b.mantissa);\n }\n\n function div_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(mul_(a.mantissa, DOUBLE_SCALE), b.mantissa) });\n }\n\n function div_(Double memory a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(a.mantissa, b) });\n }\n\n function div_(uint256 a, Double memory b) internal pure returns (uint256) {\n return div_(mul_(a, DOUBLE_SCALE), b.mantissa);\n }\n\n function div_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n function fraction(uint256 a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(mul_(a, DOUBLE_SCALE), b) });\n }\n}\n" + }, + "contracts/InterestRateModel.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title Compound's InterestRateModel Interface\n * @author Compound\n */\nabstract contract InterestRateModel {\n /**\n * @notice Calculates the current borrow interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) external view virtual returns (uint256);\n\n /**\n * @notice Calculates the current supply interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param reserveFactorMantissa The current reserve factor the market has\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate per block (as a percentage, and scaled by 1e18)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) external view virtual returns (uint256);\n\n /**\n * @notice Indicator that this is an InterestRateModel contract (for inspection)\n * @return Always true\n */\n function isInterestRateModel() external pure virtual returns (bool) {\n return true;\n }\n}\n" + }, + "contracts/IPancakeswapV2Router.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface IPancakeswapV2Router {\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n}\n" + }, + "contracts/JumpRateModelV2.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\n\nimport { BaseJumpRateModelV2 } from \"./BaseJumpRateModelV2.sol\";\n\n/**\n * @title Compound's JumpRateModel Contract V2 for V2 vTokens\n * @author Arr00\n * @notice Supports only for V2 vTokens\n */\ncontract JumpRateModelV2 is BaseJumpRateModelV2 {\n constructor(\n uint256 blocksPerYear_,\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n IAccessControlManagerV8 accessControlManager_\n )\n BaseJumpRateModelV2(\n blocksPerYear_,\n baseRatePerYear,\n multiplierPerYear,\n jumpMultiplierPerYear,\n kink_,\n accessControlManager_\n )\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n /**\n * @notice Calculates the current borrow rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) external view override returns (uint256) {\n return _getBorrowRate(cash, borrows, reserves, badDebt);\n }\n}\n" + }, + "contracts/Lens/PoolLens.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { RewardsDistributor } from \"../Rewards/RewardsDistributor.sol\";\n\n/**\n * @title PoolLens\n * @author Venus\n * @notice The `PoolLens` contract is designed to retrieve important information for each registered pool. A list of essential information\n * for all pools within the lending protocol can be acquired through the function `getAllPools()`. Additionally, the following records can be\n * looked up for specific pools and markets:\n- the vToken balance of a given user;\n- the pool data (oracle address, associated vToken, liquidation incentive, etc) of a pool via its associated comptroller address;\n- the vToken address in a pool for a given asset;\n- a list of all pools that support an asset;\n- the underlying asset price of a vToken;\n- the metadata (exchange/borrow/supply rate, total supply, collateral factor, etc) of any vToken.\n */\ncontract PoolLens is ExponentialNoError {\n /**\n * @dev Struct for PoolDetails.\n */\n struct PoolData {\n string name;\n address creator;\n address comptroller;\n uint256 blockPosted;\n uint256 timestampPosted;\n string category;\n string logoURL;\n string description;\n address priceOracle;\n uint256 closeFactor;\n uint256 liquidationIncentive;\n uint256 minLiquidatableCollateral;\n VTokenMetadata[] vTokens;\n }\n\n /**\n * @dev Struct for VToken.\n */\n struct VTokenMetadata {\n address vToken;\n uint256 exchangeRateCurrent;\n uint256 supplyRatePerBlock;\n uint256 borrowRatePerBlock;\n uint256 reserveFactorMantissa;\n uint256 supplyCaps;\n uint256 borrowCaps;\n uint256 totalBorrows;\n uint256 totalReserves;\n uint256 totalSupply;\n uint256 totalCash;\n bool isListed;\n uint256 collateralFactorMantissa;\n address underlyingAssetAddress;\n uint256 vTokenDecimals;\n uint256 underlyingDecimals;\n }\n\n /**\n * @dev Struct for VTokenBalance.\n */\n struct VTokenBalances {\n address vToken;\n uint256 balanceOf;\n uint256 borrowBalanceCurrent;\n uint256 balanceOfUnderlying;\n uint256 tokenBalance;\n uint256 tokenAllowance;\n }\n\n /**\n * @dev Struct for underlyingPrice of VToken.\n */\n struct VTokenUnderlyingPrice {\n address vToken;\n uint256 underlyingPrice;\n }\n\n /**\n * @dev Struct with pending reward info for a market.\n */\n struct PendingReward {\n address vTokenAddress;\n uint256 amount;\n }\n\n /**\n * @dev Struct with reward distribution totals for a single reward token and distributor.\n */\n struct RewardSummary {\n address distributorAddress;\n address rewardTokenAddress;\n uint256 totalRewards;\n PendingReward[] pendingRewards;\n }\n\n /**\n * @dev Struct used in RewardDistributor to save last updated market state.\n */\n struct RewardTokenState {\n // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n uint224 index;\n // The block number the index was last updated at\n uint32 block;\n // The block number at which to stop rewards\n uint32 lastRewardingBlock;\n }\n\n /**\n * @dev Struct with bad debt of a market denominated\n */\n struct BadDebt {\n address vTokenAddress;\n uint256 badDebtUsd;\n }\n\n /**\n * @dev Struct with bad debt total denominated in usd for a pool and an array of BadDebt structs for each market\n */\n struct BadDebtSummary {\n address comptroller;\n uint256 totalBadDebtUsd;\n BadDebt[] badDebts;\n }\n\n /**\n * @notice Queries the user's supply/borrow balances in vTokens\n * @param vTokens The list of vToken addresses\n * @param account The user Account\n * @return A list of structs containing balances data\n */\n function vTokenBalancesAll(VToken[] calldata vTokens, address account) external returns (VTokenBalances[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenBalances[] memory res = new VTokenBalances[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenBalances(vTokens[i], account);\n }\n return res;\n }\n\n /**\n * @notice Queries all pools with addtional details for each of them\n * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @return Arrays of all Venus pools' data\n */\n function getAllPools(address poolRegistryAddress) external view returns (PoolData[] memory) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n PoolRegistry.VenusPool[] memory venusPools = poolRegistryInterface.getAllPools();\n uint256 poolLength = venusPools.length;\n\n PoolData[] memory poolDataItems = new PoolData[](poolLength);\n\n for (uint256 i; i < poolLength; ++i) {\n PoolRegistry.VenusPool memory venusPool = venusPools[i];\n PoolData memory poolData = getPoolDataFromVenusPool(poolRegistryAddress, venusPool);\n poolDataItems[i] = poolData;\n }\n\n return poolDataItems;\n }\n\n /**\n * @notice Queries the details of a pool identified by Comptroller address\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param comptroller The Comptroller implementation address\n * @return PoolData structure containing the details of the pool\n */\n function getPoolByComptroller(\n address poolRegistryAddress,\n address comptroller\n ) external view returns (PoolData memory) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return getPoolDataFromVenusPool(poolRegistryAddress, poolRegistryInterface.getPoolByComptroller(comptroller));\n }\n\n /**\n * @notice Returns vToken holding the specified underlying asset in the specified pool\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param comptroller The pool comptroller\n * @param asset The underlyingAsset of VToken\n * @return Address of the vToken\n */\n function getVTokenForAsset(\n address poolRegistryAddress,\n address comptroller,\n address asset\n ) external view returns (address) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return poolRegistryInterface.getVTokenForAsset(comptroller, asset);\n }\n\n /**\n * @notice Returns all pools that support the specified underlying asset\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param asset The underlying asset of vToken\n * @return A list of Comptroller contracts\n */\n function getPoolsSupportedByAsset(\n address poolRegistryAddress,\n address asset\n ) external view returns (address[] memory) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return poolRegistryInterface.getPoolsSupportedByAsset(asset);\n }\n\n /**\n * @notice Returns the price data for the underlying assets of the specified vTokens\n * @param vTokens The list of vToken addresses\n * @return An array containing the price data for each asset\n */\n function vTokenUnderlyingPriceAll(\n VToken[] calldata vTokens\n ) external view returns (VTokenUnderlyingPrice[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenUnderlyingPrice[] memory res = new VTokenUnderlyingPrice[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenUnderlyingPrice(vTokens[i]);\n }\n return res;\n }\n\n /**\n * @notice Returns the pending rewards for a user for a given pool.\n * @param account The user account.\n * @param comptrollerAddress address\n * @return Pending rewards array\n */\n function getPendingRewards(\n address account,\n address comptrollerAddress\n ) external view returns (RewardSummary[] memory) {\n VToken[] memory markets = ComptrollerInterface(comptrollerAddress).getAllMarkets();\n RewardsDistributor[] memory rewardsDistributors = ComptrollerViewInterface(comptrollerAddress)\n .getRewardDistributors();\n RewardSummary[] memory rewardSummary = new RewardSummary[](rewardsDistributors.length);\n for (uint256 i; i < rewardsDistributors.length; ++i) {\n RewardSummary memory reward;\n reward.distributorAddress = address(rewardsDistributors[i]);\n reward.rewardTokenAddress = address(rewardsDistributors[i].rewardToken());\n reward.totalRewards = rewardsDistributors[i].rewardTokenAccrued(account);\n reward.pendingRewards = _calculateNotDistributedAwards(account, markets, rewardsDistributors[i]);\n rewardSummary[i] = reward;\n }\n return rewardSummary;\n }\n\n /**\n * @notice Returns a summary of a pool's bad debt broken down by market\n *\n * @param comptrollerAddress Address of the comptroller\n *\n * @return badDebtSummary A struct with comptroller address, total bad debut denominated in usd, and\n * a break down of bad debt by market\n */\n function getPoolBadDebt(address comptrollerAddress) external view returns (BadDebtSummary memory) {\n uint256 totalBadDebtUsd;\n\n // Get every market in the pool\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n VToken[] memory markets = comptroller.getAllMarkets();\n ResilientOracleInterface priceOracle = comptroller.oracle();\n\n BadDebt[] memory badDebts = new BadDebt[](markets.length);\n\n BadDebtSummary memory badDebtSummary;\n badDebtSummary.comptroller = comptrollerAddress;\n badDebtSummary.badDebts = badDebts;\n\n // // Calculate the bad debt is USD per market\n for (uint256 i; i < markets.length; ++i) {\n BadDebt memory badDebt;\n badDebt.vTokenAddress = address(markets[i]);\n badDebt.badDebtUsd =\n (VToken(address(markets[i])).badDebt() * priceOracle.getUnderlyingPrice(address(markets[i]))) /\n EXP_SCALE;\n badDebtSummary.badDebts[i] = badDebt;\n totalBadDebtUsd = totalBadDebtUsd + badDebt.badDebtUsd;\n }\n\n badDebtSummary.totalBadDebtUsd = totalBadDebtUsd;\n\n return badDebtSummary;\n }\n\n /**\n * @notice Queries the user's supply/borrow balances in the specified vToken\n * @param vToken vToken address\n * @param account The user Account\n * @return A struct containing the balances data\n */\n function vTokenBalances(VToken vToken, address account) public returns (VTokenBalances memory) {\n uint256 balanceOf = vToken.balanceOf(account);\n uint256 borrowBalanceCurrent = vToken.borrowBalanceCurrent(account);\n uint256 balanceOfUnderlying = vToken.balanceOfUnderlying(account);\n uint256 tokenBalance;\n uint256 tokenAllowance;\n\n IERC20 underlying = IERC20(vToken.underlying());\n tokenBalance = underlying.balanceOf(account);\n tokenAllowance = underlying.allowance(account, address(vToken));\n\n return\n VTokenBalances({\n vToken: address(vToken),\n balanceOf: balanceOf,\n borrowBalanceCurrent: borrowBalanceCurrent,\n balanceOfUnderlying: balanceOfUnderlying,\n tokenBalance: tokenBalance,\n tokenAllowance: tokenAllowance\n });\n }\n\n /**\n * @notice Queries additional information for the pool\n * @param poolRegistryAddress Address of the PoolRegistry\n * @param venusPool The VenusPool Object from PoolRegistry\n * @return Enriched PoolData\n */\n function getPoolDataFromVenusPool(\n address poolRegistryAddress,\n PoolRegistry.VenusPool memory venusPool\n ) public view returns (PoolData memory) {\n // Get tokens in the Pool\n ComptrollerInterface comptrollerInstance = ComptrollerInterface(venusPool.comptroller);\n\n VToken[] memory vTokens = comptrollerInstance.getAllMarkets();\n\n VTokenMetadata[] memory vTokenMetadataItems = vTokenMetadataAll(vTokens);\n\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n\n PoolRegistry.VenusPoolMetaData memory venusPoolMetaData = poolRegistryInterface.getVenusPoolMetadata(\n venusPool.comptroller\n );\n\n ComptrollerViewInterface comptrollerViewInstance = ComptrollerViewInterface(venusPool.comptroller);\n\n PoolData memory poolData = PoolData({\n name: venusPool.name,\n creator: venusPool.creator,\n comptroller: venusPool.comptroller,\n blockPosted: venusPool.blockPosted,\n timestampPosted: venusPool.timestampPosted,\n category: venusPoolMetaData.category,\n logoURL: venusPoolMetaData.logoURL,\n description: venusPoolMetaData.description,\n vTokens: vTokenMetadataItems,\n priceOracle: address(comptrollerViewInstance.oracle()),\n closeFactor: comptrollerViewInstance.closeFactorMantissa(),\n liquidationIncentive: comptrollerViewInstance.liquidationIncentiveMantissa(),\n minLiquidatableCollateral: comptrollerViewInstance.minLiquidatableCollateral()\n });\n\n return poolData;\n }\n\n /**\n * @notice Returns the metadata of VToken\n * @param vToken The address of vToken\n * @return VTokenMetadata struct\n */\n function vTokenMetadata(VToken vToken) public view returns (VTokenMetadata memory) {\n uint256 exchangeRateCurrent = vToken.exchangeRateStored();\n address comptrollerAddress = address(vToken.comptroller());\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n (bool isListed, uint256 collateralFactorMantissa) = comptroller.markets(address(vToken));\n\n address underlyingAssetAddress = vToken.underlying();\n uint256 underlyingDecimals = IERC20Metadata(underlyingAssetAddress).decimals();\n\n return\n VTokenMetadata({\n vToken: address(vToken),\n exchangeRateCurrent: exchangeRateCurrent,\n supplyRatePerBlock: vToken.supplyRatePerBlock(),\n borrowRatePerBlock: vToken.borrowRatePerBlock(),\n reserveFactorMantissa: vToken.reserveFactorMantissa(),\n supplyCaps: comptroller.supplyCaps(address(vToken)),\n borrowCaps: comptroller.borrowCaps(address(vToken)),\n totalBorrows: vToken.totalBorrows(),\n totalReserves: vToken.totalReserves(),\n totalSupply: vToken.totalSupply(),\n totalCash: vToken.getCash(),\n isListed: isListed,\n collateralFactorMantissa: collateralFactorMantissa,\n underlyingAssetAddress: underlyingAssetAddress,\n vTokenDecimals: vToken.decimals(),\n underlyingDecimals: underlyingDecimals\n });\n }\n\n /**\n * @notice Returns the metadata of all VTokens\n * @param vTokens The list of vToken addresses\n * @return An array of VTokenMetadata structs\n */\n function vTokenMetadataAll(VToken[] memory vTokens) public view returns (VTokenMetadata[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenMetadata[] memory res = new VTokenMetadata[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenMetadata(vTokens[i]);\n }\n return res;\n }\n\n /**\n * @notice Returns the price data for the underlying asset of the specified vToken\n * @param vToken vToken address\n * @return The price data for each asset\n */\n function vTokenUnderlyingPrice(VToken vToken) public view returns (VTokenUnderlyingPrice memory) {\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(address(vToken.comptroller()));\n ResilientOracleInterface priceOracle = comptroller.oracle();\n\n return\n VTokenUnderlyingPrice({\n vToken: address(vToken),\n underlyingPrice: priceOracle.getUnderlyingPrice(address(vToken))\n });\n }\n\n function _calculateNotDistributedAwards(\n address account,\n VToken[] memory markets,\n RewardsDistributor rewardsDistributor\n ) internal view returns (PendingReward[] memory) {\n PendingReward[] memory pendingRewards = new PendingReward[](markets.length);\n for (uint256 i; i < markets.length; ++i) {\n // Market borrow and supply state we will modify update in-memory, in order to not modify storage\n RewardTokenState memory borrowState;\n (borrowState.index, borrowState.block, borrowState.lastRewardingBlock) = rewardsDistributor\n .rewardTokenBorrowState(address(markets[i]));\n RewardTokenState memory supplyState;\n (supplyState.index, supplyState.block, supplyState.lastRewardingBlock) = rewardsDistributor\n .rewardTokenSupplyState(address(markets[i]));\n Exp memory marketBorrowIndex = Exp({ mantissa: markets[i].borrowIndex() });\n\n // Update market supply and borrow index in-memory\n updateMarketBorrowIndex(address(markets[i]), rewardsDistributor, borrowState, marketBorrowIndex);\n updateMarketSupplyIndex(address(markets[i]), rewardsDistributor, supplyState);\n\n // Calculate pending rewards\n uint256 borrowReward = calculateBorrowerReward(\n address(markets[i]),\n rewardsDistributor,\n account,\n borrowState,\n marketBorrowIndex\n );\n uint256 supplyReward = calculateSupplierReward(\n address(markets[i]),\n rewardsDistributor,\n account,\n supplyState\n );\n\n PendingReward memory pendingReward;\n pendingReward.vTokenAddress = address(markets[i]);\n pendingReward.amount = borrowReward + supplyReward;\n pendingRewards[i] = pendingReward;\n }\n return pendingRewards;\n }\n\n function updateMarketBorrowIndex(\n address vToken,\n RewardsDistributor rewardsDistributor,\n RewardTokenState memory borrowState,\n Exp memory marketBorrowIndex\n ) internal view {\n uint256 borrowSpeed = rewardsDistributor.rewardTokenBorrowSpeeds(vToken);\n uint256 blockNumber = block.number;\n\n if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n blockNumber = borrowState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n // Remove the total earned interest rate since the opening of the market from total borrows\n uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n uint256 tokensAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0 ? fraction(tokensAccrued, borrowAmount) : Double({ mantissa: 0 });\n Double memory index = add_(Double({ mantissa: borrowState.index }), ratio);\n borrowState.index = safe224(index.mantissa, \"new index overflows\");\n borrowState.block = safe32(blockNumber, \"block number overflows\");\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block number overflows\");\n }\n }\n\n function updateMarketSupplyIndex(\n address vToken,\n RewardsDistributor rewardsDistributor,\n RewardTokenState memory supplyState\n ) internal view {\n uint256 supplySpeed = rewardsDistributor.rewardTokenSupplySpeeds(vToken);\n uint256 blockNumber = block.number;\n\n if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n blockNumber = supplyState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = VToken(vToken).totalSupply();\n uint256 tokensAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(tokensAccrued, supplyTokens) : Double({ mantissa: 0 });\n Double memory index = add_(Double({ mantissa: supplyState.index }), ratio);\n supplyState.index = safe224(index.mantissa, \"new index overflows\");\n supplyState.block = safe32(blockNumber, \"block number overflows\");\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number overflows\");\n }\n }\n\n function calculateBorrowerReward(\n address vToken,\n RewardsDistributor rewardsDistributor,\n address borrower,\n RewardTokenState memory borrowState,\n Exp memory marketBorrowIndex\n ) internal view returns (uint256) {\n Double memory borrowIndex = Double({ mantissa: borrowState.index });\n Double memory borrowerIndex = Double({\n mantissa: rewardsDistributor.rewardTokenBorrowerIndex(vToken, borrower)\n });\n if (borrowerIndex.mantissa == 0 && borrowIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n // Covers the case where users borrowed tokens before the market's borrow state index was set\n borrowerIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n }\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n return borrowerDelta;\n }\n\n function calculateSupplierReward(\n address vToken,\n RewardsDistributor rewardsDistributor,\n address supplier,\n RewardTokenState memory supplyState\n ) internal view returns (uint256) {\n Double memory supplyIndex = Double({ mantissa: supplyState.index });\n Double memory supplierIndex = Double({\n mantissa: rewardsDistributor.rewardTokenSupplierIndex(vToken, supplier)\n });\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n // Covers the case where users supplied tokens before the market's supply state index was set\n supplierIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n }\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n return supplierDelta;\n }\n}\n" + }, + "contracts/lib/ApproveOrRevert.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nlibrary ApproveOrRevert {\n /// @notice Thrown if a contract is unable to approve a transfer\n error ApproveFailed();\n\n /// @notice Approves a transfer, ensuring that it is successful. This function supports non-compliant\n /// tokens like the ones that don't return a boolean value on success. Thus, such approve call supports\n /// three different kinds of tokens:\n /// * Compliant tokens that revert on failure\n /// * Compliant tokens that return false on failure\n /// * Non-compliant tokens that don't return a value\n /// @param token The contract address of the token which will be transferred\n /// @param spender The spender contract address\n /// @param amount The value of the transfer\n function approveOrRevert(IERC20Upgradeable token, address spender, uint256 amount) internal {\n bytes memory callData = abi.encodeCall(token.approve, (spender, amount));\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory result) = address(token).call(callData);\n\n if (!success || (result.length != 0 && !abi.decode(result, (bool)))) {\n revert ApproveFailed();\n }\n }\n}\n" + }, + "contracts/lib/constants.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\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" + }, + "contracts/lib/imports.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n// This file is needed to make hardhat and typechain generate artifacts for\n// contracts we depend on (e.g. in tests or deployments) but not use directly.\n// Another way to do this would be to use hardhat-dependency-compiler, but\n// since we only have a couple of dependencies, installing a separate package\n// seems an overhead.\n\nimport { UpgradeableBeacon } from \"@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol\";\nimport { BeaconProxy } from \"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\";\n" + }, + "contracts/lib/TokenDebtTracker.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n/**\n * @title TokenDebtTracker\n * @author Venus\n * @notice TokenDebtTracker is an abstract contract that handles transfers _out_ of the inheriting contract.\n * If there is an error transferring out (due to any reason, e.g. the token contract restricted the user from\n * receiving incoming transfers), the amount is recorded as a debt that can be claimed later.\n * @dev Note that the inheriting contract keeps some amount of users' tokens on its balance, so be careful when\n * using balanceOf(address(this))!\n */\nabstract contract TokenDebtTracker is Initializable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /**\n * @notice Mapping (IERC20Upgradeable token => (address user => uint256 amount)).\n * Tracks failed transfers: when a token transfer fails, we record the\n * amount of the transfer, so that the user can redeem this debt later.\n */\n mapping(IERC20Upgradeable => mapping(address => uint256)) public tokenDebt;\n\n /**\n * @notice Mapping (IERC20Upgradeable token => uint256 amount) shows how many\n * tokens the contract owes to all users. This is useful for accounting to\n * understand how much of balanceOf(address(this)) is already owed to users.\n */\n mapping(IERC20Upgradeable => uint256) public totalTokenDebt;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[48] private __gap;\n\n /**\n * @notice Emitted when the contract's debt to the user is increased due to a failed transfer\n * @param token Token address\n * @param user User address\n * @param amount The amount of debt added\n */\n event TokenDebtAdded(address indexed token, address indexed user, uint256 amount);\n\n /**\n * @notice Emitted when a user claims tokens that the contract owes them\n * @param token Token address\n * @param user User address\n * @param amount The amount transferred\n */\n event TokenDebtClaimed(address indexed token, address indexed user, uint256 amount);\n\n /**\n * @notice Thrown if the user tries to claim more tokens than they are owed\n * @param token The token the user is trying to claim\n * @param owedAmount The amount of tokens the contract owes to the user\n * @param amount The amount of tokens the user is trying to claim\n */\n error InsufficientDebt(address token, address user, uint256 owedAmount, uint256 amount);\n\n /**\n * @notice Thrown if trying to transfer more tokens than the contract currently has\n * @param token The token the contract is trying to transfer\n * @param recipient The recipient of the transfer\n * @param amount The amount of tokens the contract is trying to transfer\n * @param availableBalance The amount of tokens the contract currently has\n */\n error InsufficientBalance(address token, address recipient, uint256 amount, uint256 availableBalance);\n\n /**\n * @notice Transfers the tokens we owe to msg.sender, if any\n * @param token The token to claim\n * @param amount_ The amount of tokens to claim (or max uint256 to claim all)\n * @custom:error InsufficientDebt The contract doesn't have enough debt to the user\n */\n function claimTokenDebt(IERC20Upgradeable token, uint256 amount_) external {\n uint256 owedAmount = tokenDebt[token][msg.sender];\n uint256 amount = (amount_ == type(uint256).max ? owedAmount : amount_);\n if (amount > owedAmount) {\n revert InsufficientDebt(address(token), msg.sender, owedAmount, amount);\n }\n unchecked {\n // Safe because we revert if amount > owedAmount above\n tokenDebt[token][msg.sender] = owedAmount - amount;\n }\n totalTokenDebt[token] -= amount;\n emit TokenDebtClaimed(address(token), msg.sender, amount);\n token.safeTransfer(msg.sender, amount);\n }\n\n // solhint-disable-next-line func-name-mixedcase\n function __TokenDebtTracker_init() internal onlyInitializing {\n __TokenDebtTracker_init_unchained();\n }\n\n // solhint-disable-next-line func-name-mixedcase, no-empty-blocks\n function __TokenDebtTracker_init_unchained() internal onlyInitializing {}\n\n /**\n * @dev Transfers tokens to the recipient if the contract has enough balance, or\n * records the debt if the transfer fails due to reasons unrelated to the contract's\n * balance (e.g. if the token forbids transfers to the recipient).\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n * @custom:error InsufficientBalance The contract doesn't have enough balance to transfer\n */\n function _transferOutOrTrackDebt(IERC20Upgradeable token, address to, uint256 amount) internal {\n uint256 balance = token.balanceOf(address(this));\n if (balance < amount) {\n revert InsufficientBalance(address(token), address(this), amount, balance);\n }\n _transferOutOrTrackDebtSkippingBalanceCheck(token, to, amount);\n }\n\n /**\n * @dev Transfers tokens to the recipient, or records the debt if the transfer fails\n * due to any reason, including insufficient balance.\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n */\n function _transferOutOrTrackDebtSkippingBalanceCheck(IERC20Upgradeable token, address to, uint256 amount) internal {\n // We can't use safeTransfer here because we can't try-catch internal calls\n bool success = _tryTransferOut(token, to, amount);\n if (!success) {\n tokenDebt[token][to] += amount;\n totalTokenDebt[token] += amount;\n emit TokenDebtAdded(address(token), to, amount);\n }\n }\n\n /**\n * @dev Either transfers tokens to the recepient or returns false. Supports tokens\n * thet revert or return false to indicate failure, and the non-compliant ones\n * that do not return any value.\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n * @return true if the transfer succeeded, false otherwise\n */\n function _tryTransferOut(IERC20Upgradeable token, address to, uint256 amount) private returns (bool) {\n bytes memory callData = abi.encodeCall(token.transfer, (to, amount));\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(callData);\n return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n }\n}\n" + }, + "contracts/lib/validators.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n}\n" + }, + "contracts/MaxLoopsLimitHelper.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title MaxLoopsLimitHelper\n * @author Venus\n * @notice Abstract contract used to avoid collection with too many items that would generate gas errors and DoS.\n */\nabstract contract MaxLoopsLimitHelper {\n // Limit for the loops to avoid the DOS\n uint256 public maxLoopsLimit;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when max loops limit is set\n event MaxLoopsLimitUpdated(uint256 oldMaxLoopsLimit, uint256 newmaxLoopsLimit);\n\n /// @notice Thrown an error on maxLoopsLimit exceeds for any loop\n error MaxLoopsLimitExceeded(uint256 loopsLimit, uint256 requiredLoops);\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function _setMaxLoopsLimit(uint256 limit) internal {\n require(limit > maxLoopsLimit, \"Comptroller: Invalid maxLoopsLimit\");\n\n uint256 oldMaxLoopsLimit = maxLoopsLimit;\n maxLoopsLimit = limit;\n\n emit MaxLoopsLimitUpdated(oldMaxLoopsLimit, limit);\n }\n\n /**\n * @notice Compare the maxLoopsLimit with number of the times loop iterate\n * @param len Length of the loops iterate\n * @custom:error MaxLoopsLimitExceeded error is thrown when loops length exceeds maxLoopsLimit\n */\n function _ensureMaxLoops(uint256 len) internal view {\n if (len > maxLoopsLimit) {\n revert MaxLoopsLimitExceeded(maxLoopsLimit, len);\n }\n }\n}\n" + }, + "contracts/Pool/PoolRegistry.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { PoolRegistryInterface } from \"./PoolRegistryInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\n/**\n * @title PoolRegistry\n * @author Venus\n * @notice The Isolated Pools architecture centers around the `PoolRegistry` contract. The `PoolRegistry` maintains a directory of isolated lending\n * pools and can perform actions like creating and registering new pools, adding new markets to existing pools, setting and updating the pool's required\n * metadata, and providing the getter methods to get information on the pools.\n *\n * Isolated lending has three main components: PoolRegistry, pools, and markets. The PoolRegistry is responsible for managing pools.\n * It can create new pools, update pool metadata and manage markets within pools. PoolRegistry contains getter methods to get the details of\n * any existing pool like `getVTokenForAsset` and `getPoolsSupportedByAsset`. It also contains methods for updating pool metadata (`updatePoolMetadata`)\n * and setting pool name (`setPoolName`).\n *\n * The directory of pools is managed through two mappings: `_poolByComptroller` which is a hashmap with the comptroller address as the key and `VenusPool` as\n * the value and `_poolsByID` which is an array of comptroller addresses. Individual pools can be accessed by calling `getPoolByComptroller` with the pool's\n * comptroller address. `_poolsByID` is used to iterate through all of the pools.\n *\n * PoolRegistry also contains a map of asset addresses called `_supportedPools` that maps to an array of assets suppored by each pool. This array of pools by\n * asset is retrieved by calling `getPoolsSupportedByAsset`.\n *\n * PoolRegistry registers new isolated pools in the directory with the `createRegistryPool` method. Isolated pools are composed of independent markets with\n * specific assets and custom risk management configurations according to their markets.\n */\ncontract PoolRegistry is Ownable2StepUpgradeable, AccessControlledV8, PoolRegistryInterface {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n struct AddMarketInput {\n VToken vToken;\n uint256 collateralFactor;\n uint256 liquidationThreshold;\n uint256 initialSupply;\n address vTokenReceiver;\n uint256 supplyCap;\n uint256 borrowCap;\n }\n\n uint256 internal constant MAX_POOL_NAME_LENGTH = 100;\n\n /**\n * @notice Maps pool's comptroller address to metadata.\n */\n mapping(address => VenusPoolMetaData) public metadata;\n\n /**\n * @dev Maps pool ID to pool's comptroller address\n */\n mapping(uint256 => address) private _poolsByID;\n\n /**\n * @dev Total number of pools created.\n */\n uint256 private _numberOfPools;\n\n /**\n * @dev Maps comptroller address to Venus pool Index.\n */\n mapping(address => VenusPool) private _poolByComptroller;\n\n /**\n * @dev Maps pool's comptroller address to asset to vToken.\n */\n mapping(address => mapping(address => address)) private _vTokens;\n\n /**\n * @dev Maps asset to list of supported pools.\n */\n mapping(address => address[]) private _supportedPools;\n\n /**\n * @notice Emitted when a new Venus pool is added to the directory.\n */\n event PoolRegistered(address indexed comptroller, VenusPool pool);\n\n /**\n * @notice Emitted when a pool name is set.\n */\n event PoolNameSet(address indexed comptroller, string oldName, string newName);\n\n /**\n * @notice Emitted when a pool metadata is updated.\n */\n event PoolMetadataUpdated(\n address indexed comptroller,\n VenusPoolMetaData oldMetadata,\n VenusPoolMetaData newMetadata\n );\n\n /**\n * @notice Emitted when a Market is added to the pool.\n */\n event MarketAdded(address indexed comptroller, address indexed vTokenAddress);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner\n * @param accessControlManager_ AccessControlManager contract address\n */\n function initialize(address accessControlManager_) external initializer {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n /**\n * @notice Adds a new Venus pool to the directory\n * @dev Price oracle must be configured before adding a pool\n * @param name The name of the pool\n * @param comptroller Pool's Comptroller contract\n * @param closeFactor The pool's close factor (scaled by 1e18)\n * @param liquidationIncentive The pool's liquidation incentive (scaled by 1e18)\n * @param minLiquidatableCollateral Minimal collateral for regular (non-batch) liquidations flow\n * @return index The index of the registered Venus pool\n * @custom:error ZeroAddressNotAllowed is thrown when Comptroller address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when price oracle address is zero\n */\n function addPool(\n string calldata name,\n Comptroller comptroller,\n uint256 closeFactor,\n uint256 liquidationIncentive,\n uint256 minLiquidatableCollateral\n ) external virtual returns (uint256 index) {\n _checkAccessAllowed(\"addPool(string,address,uint256,uint256,uint256)\");\n // Input validation\n ensureNonzeroAddress(address(comptroller));\n ensureNonzeroAddress(address(comptroller.oracle()));\n\n uint256 poolId = _registerPool(name, address(comptroller));\n\n // Set Venus pool parameters\n comptroller.setCloseFactor(closeFactor);\n comptroller.setLiquidationIncentive(liquidationIncentive);\n comptroller.setMinLiquidatableCollateral(minLiquidatableCollateral);\n\n return poolId;\n }\n\n /**\n * @notice Add a market to an existing pool and then mint to provide initial supply\n * @param input The structure describing the parameters for adding a market to a pool\n * @custom:error ZeroAddressNotAllowed is thrown when vToken address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when vTokenReceiver address is zero\n */\n function addMarket(AddMarketInput memory input) external {\n _checkAccessAllowed(\"addMarket(AddMarketInput)\");\n ensureNonzeroAddress(address(input.vToken));\n ensureNonzeroAddress(input.vTokenReceiver);\n require(input.initialSupply > 0, \"PoolRegistry: initialSupply is zero\");\n\n VToken vToken = input.vToken;\n address vTokenAddress = address(vToken);\n address comptrollerAddress = address(vToken.comptroller());\n Comptroller comptroller = Comptroller(comptrollerAddress);\n address underlyingAddress = vToken.underlying();\n IERC20Upgradeable underlying = IERC20Upgradeable(underlyingAddress);\n\n require(_poolByComptroller[comptrollerAddress].creator != address(0), \"PoolRegistry: Pool not registered\");\n // solhint-disable-next-line reason-string\n require(\n _vTokens[comptrollerAddress][underlyingAddress] == address(0),\n \"PoolRegistry: Market already added for asset comptroller combination\"\n );\n\n comptroller.supportMarket(vToken);\n comptroller.setCollateralFactor(vToken, input.collateralFactor, input.liquidationThreshold);\n\n uint256[] memory newSupplyCaps = new uint256[](1);\n uint256[] memory newBorrowCaps = new uint256[](1);\n VToken[] memory vTokens = new VToken[](1);\n\n newSupplyCaps[0] = input.supplyCap;\n newBorrowCaps[0] = input.borrowCap;\n vTokens[0] = vToken;\n\n comptroller.setMarketSupplyCaps(vTokens, newSupplyCaps);\n comptroller.setMarketBorrowCaps(vTokens, newBorrowCaps);\n\n _vTokens[comptrollerAddress][underlyingAddress] = vTokenAddress;\n _supportedPools[underlyingAddress].push(comptrollerAddress);\n\n uint256 amountToSupply = _transferIn(underlying, msg.sender, input.initialSupply);\n underlying.approve(vTokenAddress, 0);\n underlying.approve(vTokenAddress, amountToSupply);\n vToken.mintBehalf(input.vTokenReceiver, amountToSupply);\n\n emit MarketAdded(comptrollerAddress, vTokenAddress);\n }\n\n /**\n * @notice Modify existing Venus pool name\n * @param comptroller Pool's Comptroller\n * @param name New pool name\n */\n function setPoolName(address comptroller, string calldata name) external {\n _checkAccessAllowed(\"setPoolName(address,string)\");\n _ensureValidName(name);\n VenusPool storage pool = _poolByComptroller[comptroller];\n string memory oldName = pool.name;\n pool.name = name;\n emit PoolNameSet(comptroller, oldName, name);\n }\n\n /**\n * @notice Update metadata of an existing pool\n * @param comptroller Pool's Comptroller\n * @param metadata_ New pool metadata\n */\n function updatePoolMetadata(address comptroller, VenusPoolMetaData calldata metadata_) external {\n _checkAccessAllowed(\"updatePoolMetadata(address,VenusPoolMetaData)\");\n VenusPoolMetaData memory oldMetadata = metadata[comptroller];\n metadata[comptroller] = metadata_;\n emit PoolMetadataUpdated(comptroller, oldMetadata, metadata_);\n }\n\n /**\n * @notice Returns arrays of all Venus pools' data\n * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n * @return A list of all pools within PoolRegistry, with details for each pool\n */\n function getAllPools() external view override returns (VenusPool[] memory) {\n uint256 numberOfPools_ = _numberOfPools; // storage load to save gas\n VenusPool[] memory _pools = new VenusPool[](numberOfPools_);\n for (uint256 i = 1; i <= numberOfPools_; ++i) {\n address comptroller = _poolsByID[i];\n _pools[i - 1] = (_poolByComptroller[comptroller]);\n }\n return _pools;\n }\n\n /**\n * @param comptroller The comptroller proxy address associated to the pool\n * @return Returns Venus pool\n */\n function getPoolByComptroller(address comptroller) external view override returns (VenusPool memory) {\n return _poolByComptroller[comptroller];\n }\n\n /**\n * @param comptroller comptroller of Venus pool\n * @return Returns Metadata of Venus pool\n */\n function getVenusPoolMetadata(address comptroller) external view override returns (VenusPoolMetaData memory) {\n return metadata[comptroller];\n }\n\n function getVTokenForAsset(address comptroller, address asset) external view override returns (address) {\n return _vTokens[comptroller][asset];\n }\n\n function getPoolsSupportedByAsset(address asset) external view override returns (address[] memory) {\n return _supportedPools[asset];\n }\n\n /**\n * @dev Adds a new Venus pool to the directory (without checking msg.sender).\n * @param name The name of the pool\n * @param comptroller The pool's Comptroller proxy contract address\n * @return The index of the registered Venus pool\n */\n function _registerPool(string calldata name, address comptroller) internal returns (uint256) {\n VenusPool storage storedPool = _poolByComptroller[comptroller];\n\n require(storedPool.creator == address(0), \"PoolRegistry: Pool already exists in the directory.\");\n _ensureValidName(name);\n\n ++_numberOfPools;\n uint256 numberOfPools_ = _numberOfPools; // cache on stack to save storage read gas\n\n VenusPool memory pool = VenusPool(name, msg.sender, comptroller, block.number, block.timestamp);\n\n _poolsByID[numberOfPools_] = comptroller;\n _poolByComptroller[comptroller] = pool;\n\n emit PoolRegistered(comptroller, pool);\n return numberOfPools_;\n }\n\n function _transferIn(IERC20Upgradeable token, address from, uint256 amount) internal returns (uint256) {\n uint256 balanceBefore = token.balanceOf(address(this));\n token.safeTransferFrom(from, address(this), amount);\n uint256 balanceAfter = token.balanceOf(address(this));\n return balanceAfter - balanceBefore;\n }\n\n function _ensureValidName(string calldata name) internal pure {\n require(bytes(name).length <= MAX_POOL_NAME_LENGTH, \"Pool's name is too large\");\n }\n}\n" + }, + "contracts/Pool/PoolRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title PoolRegistryInterface\n * @author Venus\n * @notice Interface implemented by `PoolRegistry`.\n */\ninterface PoolRegistryInterface {\n /**\n * @notice Struct for a Venus interest rate pool.\n */\n struct VenusPool {\n string name;\n address creator;\n address comptroller;\n uint256 blockPosted;\n uint256 timestampPosted;\n }\n\n /**\n * @notice Struct for a Venus interest rate pool metadata.\n */\n struct VenusPoolMetaData {\n string category;\n string logoURL;\n string description;\n }\n\n /// @notice Get all pools in PoolRegistry\n function getAllPools() external view returns (VenusPool[] memory);\n\n /// @notice Get a pool by comptroller address\n function getPoolByComptroller(address comptroller) external view returns (VenusPool memory);\n\n /// @notice Get the address of the VToken contract in the Pool where the underlying token is the provided 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 /// @notice Get the metadata of a Pool by comptroller address\n function getVenusPoolMetadata(address comptroller) external view returns (VenusPoolMetaData memory);\n}\n" + }, + "contracts/Rewards/RewardsDistributor.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\n\n/**\n * @title `RewardsDistributor`\n * @author Venus\n * @notice Contract used to configure, track and distribute rewards to users based on their actions (borrows and supplies) in the protocol.\n * Users can receive additional rewards through a `RewardsDistributor`. Each `RewardsDistributor` proxy is initialized with a specific reward\n * token and `Comptroller`, which can then distribute the reward token to users that supply or borrow in the associated pool.\n * Authorized users can set the reward token borrow and supply speeds for each market in the pool. This sets a fixed amount of reward\n * token to be released each block for borrowers and suppliers, which is distributed based on a user’s percentage of the borrows or supplies\n * respectively. The owner can also set up reward distributions to contributor addresses (distinct from suppliers and borrowers) by setting\n * their contributor reward token speed, which similarly allocates a fixed amount of reward token per block.\n *\n * The owner has the ability to transfer any amount of reward tokens held by the contract to any other address. Rewards are not distributed\n * automatically and must be claimed by a user calling `claimRewardToken()`. Users should be aware that it is up to the owner and other centralized\n * entities to ensure that the `RewardsDistributor` holds enough tokens to distribute the accumulated rewards of users and contributors.\n */\ncontract RewardsDistributor is ExponentialNoError, Ownable2StepUpgradeable, AccessControlledV8, MaxLoopsLimitHelper {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n struct RewardToken {\n // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n uint224 index;\n // The block number the index was last updated at\n uint32 block;\n // The block number at which to stop rewards\n uint32 lastRewardingBlock;\n }\n\n /// @notice The initial REWARD TOKEN index for a market\n uint224 public constant INITIAL_INDEX = 1e36;\n\n /// @notice The REWARD TOKEN market supply state for each market\n mapping(address => RewardToken) public rewardTokenSupplyState;\n\n /// @notice The REWARD TOKEN borrow index for each market for each supplier as of the last time they accrued REWARD TOKEN\n mapping(address => mapping(address => uint256)) public rewardTokenSupplierIndex;\n\n /// @notice The REWARD TOKEN accrued but not yet transferred to each user\n mapping(address => uint256) public rewardTokenAccrued;\n\n /// @notice The rate at which rewardToken is distributed to the corresponding borrow market (per block)\n mapping(address => uint256) public rewardTokenBorrowSpeeds;\n\n /// @notice The rate at which rewardToken is distributed to the corresponding supply market (per block)\n mapping(address => uint256) public rewardTokenSupplySpeeds;\n\n /// @notice The REWARD TOKEN market borrow state for each market\n mapping(address => RewardToken) public rewardTokenBorrowState;\n\n /// @notice The portion of REWARD TOKEN that each contributor receives per block\n mapping(address => uint256) public rewardTokenContributorSpeeds;\n\n /// @notice Last block at which a contributor's REWARD TOKEN rewards have been allocated\n mapping(address => uint256) public lastContributorBlock;\n\n /// @notice The REWARD TOKEN borrow index for each market for each borrower as of the last time they accrued REWARD TOKEN\n mapping(address => mapping(address => uint256)) public rewardTokenBorrowerIndex;\n\n Comptroller private comptroller;\n\n IERC20Upgradeable public rewardToken;\n\n /// @notice Emitted when REWARD TOKEN is distributed to a supplier\n event DistributedSupplierRewardToken(\n VToken indexed vToken,\n address indexed supplier,\n uint256 rewardTokenDelta,\n uint256 rewardTokenTotal,\n uint256 rewardTokenSupplyIndex\n );\n\n /// @notice Emitted when REWARD TOKEN is distributed to a borrower\n event DistributedBorrowerRewardToken(\n VToken indexed vToken,\n address indexed borrower,\n uint256 rewardTokenDelta,\n uint256 rewardTokenTotal,\n uint256 rewardTokenBorrowIndex\n );\n\n /// @notice Emitted when a new supply-side REWARD TOKEN speed is calculated for a market\n event RewardTokenSupplySpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n /// @notice Emitted when a new borrow-side REWARD TOKEN speed is calculated for a market\n event RewardTokenBorrowSpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n /// @notice Emitted when REWARD TOKEN is granted by admin\n event RewardTokenGranted(address indexed recipient, uint256 amount);\n\n /// @notice Emitted when a new REWARD TOKEN speed is set for a contributor\n event ContributorRewardTokenSpeedUpdated(address indexed contributor, uint256 newSpeed);\n\n /// @notice Emitted when a market is initialized\n event MarketInitialized(address indexed vToken);\n\n /// @notice Emitted when a reward token supply index is updated\n event RewardTokenSupplyIndexUpdated(address indexed vToken);\n\n /// @notice Emitted when a reward token borrow index is updated\n event RewardTokenBorrowIndexUpdated(address indexed vToken, Exp marketBorrowIndex);\n\n /// @notice Emitted when a reward for contributor is updated\n event ContributorRewardsUpdated(address indexed contributor, uint256 rewardAccrued);\n\n /// @notice Emitted when a reward token last rewarding block for supply is updated\n event SupplyLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n /// @notice Emitted when a reward token last rewarding block for borrow is updated\n event BorrowLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n modifier onlyComptroller() {\n require(address(comptroller) == msg.sender, \"Only comptroller can call this function\");\n _;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice RewardsDistributor initializer\n * @dev Initializes the deployer to owner\n * @param comptroller_ Comptroller to attach the reward distributor to\n * @param rewardToken_ Reward token to distribute\n * @param loopsLimit_ Maximum number of iterations for the loops in this contract\n * @param accessControlManager_ AccessControlManager contract address\n */\n function initialize(\n Comptroller comptroller_,\n IERC20Upgradeable rewardToken_,\n uint256 loopsLimit_,\n address accessControlManager_\n ) external initializer {\n comptroller = comptroller_;\n rewardToken = rewardToken_;\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n\n _setMaxLoopsLimit(loopsLimit_);\n }\n\n function initializeMarket(address vToken) external onlyComptroller {\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n\n /*\n * Update market state indices\n */\n if (supplyState.index == 0) {\n // Initialize supply state index with default value\n supplyState.index = INITIAL_INDEX;\n }\n\n if (borrowState.index == 0) {\n // Initialize borrow state index with default value\n borrowState.index = INITIAL_INDEX;\n }\n\n /*\n * Update market state block numbers\n */\n supplyState.block = borrowState.block = blockNumber;\n\n emit MarketInitialized(vToken);\n }\n\n /*** Reward Token Distribution ***/\n\n /**\n * @notice Calculate reward token accrued by a borrower and possibly transfer it to them\n * Borrowers will begin to accrue after the first interaction with the protocol.\n * @dev This function should only be called when the user has a borrow position in the market\n * (e.g. Comptroller.preBorrowHook, and Comptroller.preRepayHook)\n * We avoid an external call to check if they are in the market to save gas because this function is called in many places\n * @param vToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute REWARD TOKEN to\n * @param marketBorrowIndex The current global borrow index of vToken\n */\n function distributeBorrowerRewardToken(\n address vToken,\n address borrower,\n Exp memory marketBorrowIndex\n ) external onlyComptroller {\n _distributeBorrowerRewardToken(vToken, borrower, marketBorrowIndex);\n }\n\n function updateRewardTokenSupplyIndex(address vToken) external onlyComptroller {\n _updateRewardTokenSupplyIndex(vToken);\n }\n\n /**\n * @notice Transfer REWARD TOKEN to the recipient\n * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all\n * @param recipient The address of the recipient to transfer REWARD TOKEN to\n * @param amount The amount of REWARD TOKEN to (possibly) transfer\n */\n function grantRewardToken(address recipient, uint256 amount) external onlyOwner {\n uint256 amountLeft = _grantRewardToken(recipient, amount);\n require(amountLeft == 0, \"insufficient rewardToken for grant\");\n emit RewardTokenGranted(recipient, amount);\n }\n\n function updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) external onlyComptroller {\n _updateRewardTokenBorrowIndex(vToken, marketBorrowIndex);\n }\n\n /**\n * @notice Set REWARD TOKEN borrow and supply speeds for the specified markets\n * @param vTokens The markets whose REWARD TOKEN speed to update\n * @param supplySpeeds New supply-side REWARD TOKEN speed for the corresponding market\n * @param borrowSpeeds New borrow-side REWARD TOKEN speed for the corresponding market\n */\n function setRewardTokenSpeeds(\n VToken[] memory vTokens,\n uint256[] memory supplySpeeds,\n uint256[] memory borrowSpeeds\n ) external {\n _checkAccessAllowed(\"setRewardTokenSpeeds(address[],uint256[],uint256[])\");\n uint256 numTokens = vTokens.length;\n require(numTokens == supplySpeeds.length && numTokens == borrowSpeeds.length, \"invalid setRewardTokenSpeeds\");\n\n for (uint256 i; i < numTokens; ++i) {\n _setRewardTokenSpeed(vTokens[i], supplySpeeds[i], borrowSpeeds[i]);\n }\n }\n\n /**\n * @notice Set REWARD TOKEN last rewarding block for the specified markets\n * @param vTokens The markets whose REWARD TOKEN last rewarding block to update\n * @param supplyLastRewardingBlocks New supply-side REWARD TOKEN last rewarding block for the corresponding market\n * @param borrowLastRewardingBlocks New borrow-side REWARD TOKEN last rewarding block for the corresponding market\n */\n function setLastRewardingBlocks(\n VToken[] calldata vTokens,\n uint32[] calldata supplyLastRewardingBlocks,\n uint32[] calldata borrowLastRewardingBlocks\n ) external {\n _checkAccessAllowed(\"setLastRewardingBlock(address[],uint32[],uint32[])\");\n uint256 numTokens = vTokens.length;\n require(\n numTokens == supplyLastRewardingBlocks.length && numTokens == borrowLastRewardingBlocks.length,\n \"RewardsDistributor::setLastRewardingBlocks invalid input\"\n );\n\n for (uint256 i; i < numTokens; ) {\n _setLastRewardingBlock(vTokens[i], supplyLastRewardingBlocks[i], borrowLastRewardingBlocks[i]);\n unchecked {\n ++i;\n }\n }\n }\n\n /**\n * @notice Set REWARD TOKEN speed for a single contributor\n * @param contributor The contributor whose REWARD TOKEN speed to update\n * @param rewardTokenSpeed New REWARD TOKEN speed for contributor\n */\n function setContributorRewardTokenSpeed(address contributor, uint256 rewardTokenSpeed) external onlyOwner {\n // note that REWARD TOKEN speed could be set to 0 to halt liquidity rewards for a contributor\n updateContributorRewards(contributor);\n if (rewardTokenSpeed == 0) {\n // release storage\n delete lastContributorBlock[contributor];\n } else {\n lastContributorBlock[contributor] = getBlockNumber();\n }\n rewardTokenContributorSpeeds[contributor] = rewardTokenSpeed;\n\n emit ContributorRewardTokenSpeedUpdated(contributor, rewardTokenSpeed);\n }\n\n function distributeSupplierRewardToken(address vToken, address supplier) external onlyComptroller {\n _distributeSupplierRewardToken(vToken, supplier);\n }\n\n /**\n * @notice Claim all the rewardToken accrued by holder in all markets\n * @param holder The address to claim REWARD TOKEN for\n */\n function claimRewardToken(address holder) external {\n return claimRewardToken(holder, comptroller.getAllMarkets());\n }\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Calculate additional accrued REWARD TOKEN for a contributor since last accrual\n * @param contributor The address to calculate contributor rewards for\n */\n function updateContributorRewards(address contributor) public {\n uint256 rewardTokenSpeed = rewardTokenContributorSpeeds[contributor];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, lastContributorBlock[contributor]);\n if (deltaBlocks > 0 && rewardTokenSpeed > 0) {\n uint256 newAccrued = mul_(deltaBlocks, rewardTokenSpeed);\n uint256 contributorAccrued = add_(rewardTokenAccrued[contributor], newAccrued);\n\n rewardTokenAccrued[contributor] = contributorAccrued;\n lastContributorBlock[contributor] = blockNumber;\n\n emit ContributorRewardsUpdated(contributor, rewardTokenAccrued[contributor]);\n }\n }\n\n /**\n * @notice Claim all the rewardToken accrued by holder in the specified markets\n * @param holder The address to claim REWARD TOKEN for\n * @param vTokens The list of markets to claim REWARD TOKEN in\n */\n function claimRewardToken(address holder, VToken[] memory vTokens) public {\n uint256 vTokensCount = vTokens.length;\n\n _ensureMaxLoops(vTokensCount);\n\n for (uint256 i; i < vTokensCount; ++i) {\n VToken vToken = vTokens[i];\n require(comptroller.isMarketListed(vToken), \"market must be listed\");\n Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n _distributeBorrowerRewardToken(address(vToken), holder, borrowIndex);\n _updateRewardTokenSupplyIndex(address(vToken));\n _distributeSupplierRewardToken(address(vToken), holder);\n }\n rewardTokenAccrued[holder] = _grantRewardToken(holder, rewardTokenAccrued[holder]);\n }\n\n function getBlockNumber() public view virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Set REWARD TOKEN last rewarding block for a single market.\n * @param vToken market's whose reward token last rewarding block to be updated\n * @param supplyLastRewardingBlock New supply-side REWARD TOKEN last rewarding block for market\n * @param borrowLastRewardingBlock New borrow-side REWARD TOKEN last rewarding block for market\n */\n function _setLastRewardingBlock(\n VToken vToken,\n uint32 supplyLastRewardingBlock,\n uint32 borrowLastRewardingBlock\n ) internal {\n require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n uint256 blockNumber = getBlockNumber();\n\n require(supplyLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n require(borrowLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n\n uint32 currentSupplyLastRewardingBlock = rewardTokenSupplyState[address(vToken)].lastRewardingBlock;\n uint32 currentBorrowLastRewardingBlock = rewardTokenBorrowState[address(vToken)].lastRewardingBlock;\n\n require(\n currentSupplyLastRewardingBlock == 0 || currentSupplyLastRewardingBlock > blockNumber,\n \"this RewardsDistributor is already locked\"\n );\n require(\n currentBorrowLastRewardingBlock == 0 || currentBorrowLastRewardingBlock > blockNumber,\n \"this RewardsDistributor is already locked\"\n );\n\n if (currentSupplyLastRewardingBlock != supplyLastRewardingBlock) {\n rewardTokenSupplyState[address(vToken)].lastRewardingBlock = supplyLastRewardingBlock;\n emit SupplyLastRewardingBlockUpdated(address(vToken), supplyLastRewardingBlock);\n }\n\n if (currentBorrowLastRewardingBlock != borrowLastRewardingBlock) {\n rewardTokenBorrowState[address(vToken)].lastRewardingBlock = borrowLastRewardingBlock;\n emit BorrowLastRewardingBlockUpdated(address(vToken), borrowLastRewardingBlock);\n }\n }\n\n /**\n * @notice Set REWARD TOKEN speed for a single market.\n * @param vToken market's whose reward token rate to be updated\n * @param supplySpeed New supply-side REWARD TOKEN speed for market\n * @param borrowSpeed New borrow-side REWARD TOKEN speed for market\n */\n function _setRewardTokenSpeed(VToken vToken, uint256 supplySpeed, uint256 borrowSpeed) internal {\n require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n if (rewardTokenSupplySpeeds[address(vToken)] != supplySpeed) {\n // Supply speed updated so let's update supply state to ensure that\n // 1. REWARD TOKEN accrued properly for the old speed, and\n // 2. REWARD TOKEN accrued at the new speed starts after this block.\n _updateRewardTokenSupplyIndex(address(vToken));\n\n // Update speed and emit event\n rewardTokenSupplySpeeds[address(vToken)] = supplySpeed;\n emit RewardTokenSupplySpeedUpdated(vToken, supplySpeed);\n }\n\n if (rewardTokenBorrowSpeeds[address(vToken)] != borrowSpeed) {\n // Borrow speed updated so let's update borrow state to ensure that\n // 1. REWARD TOKEN accrued properly for the old speed, and\n // 2. REWARD TOKEN accrued at the new speed starts after this block.\n Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n\n // Update speed and emit event\n rewardTokenBorrowSpeeds[address(vToken)] = borrowSpeed;\n emit RewardTokenBorrowSpeedUpdated(vToken, borrowSpeed);\n }\n }\n\n /**\n * @notice Calculate REWARD TOKEN accrued by a supplier and possibly transfer it to them.\n * @param vToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute REWARD TOKEN to\n */\n function _distributeSupplierRewardToken(address vToken, address supplier) internal {\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n uint256 supplyIndex = supplyState.index;\n uint256 supplierIndex = rewardTokenSupplierIndex[vToken][supplier];\n\n // Update supplier's index to the current index since we are distributing accrued REWARD TOKEN\n rewardTokenSupplierIndex[vToken][supplier] = supplyIndex;\n\n if (supplierIndex == 0 && supplyIndex >= INITIAL_INDEX) {\n // Covers the case where users supplied tokens before the market's supply state index was set.\n // Rewards the user with REWARD TOKEN accrued from the start of when supplier rewards were first\n // set for the market.\n supplierIndex = INITIAL_INDEX;\n }\n\n // Calculate change in the cumulative sum of the REWARD TOKEN per vToken accrued\n Double memory deltaIndex = Double({ mantissa: sub_(supplyIndex, supplierIndex) });\n\n uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n\n // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerVToken\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n\n uint256 supplierAccrued = add_(rewardTokenAccrued[supplier], supplierDelta);\n rewardTokenAccrued[supplier] = supplierAccrued;\n\n emit DistributedSupplierRewardToken(VToken(vToken), supplier, supplierDelta, supplierAccrued, supplyIndex);\n }\n\n /**\n * @notice Calculate reward token accrued by a borrower and possibly transfer it to them.\n * @param vToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute REWARD TOKEN to\n * @param marketBorrowIndex The current global borrow index of vToken\n */\n function _distributeBorrowerRewardToken(address vToken, address borrower, Exp memory marketBorrowIndex) internal {\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n uint256 borrowIndex = borrowState.index;\n uint256 borrowerIndex = rewardTokenBorrowerIndex[vToken][borrower];\n\n // Update borrowers's index to the current index since we are distributing accrued REWARD TOKEN\n rewardTokenBorrowerIndex[vToken][borrower] = borrowIndex;\n\n if (borrowerIndex == 0 && borrowIndex >= INITIAL_INDEX) {\n // Covers the case where users borrowed tokens before the market's borrow state index was set.\n // Rewards the user with REWARD TOKEN accrued from the start of when borrower rewards were first\n // set for the market.\n borrowerIndex = INITIAL_INDEX;\n }\n\n // Calculate change in the cumulative sum of the REWARD TOKEN per borrowed unit accrued\n Double memory deltaIndex = Double({ mantissa: sub_(borrowIndex, borrowerIndex) });\n\n uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n\n // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerBorrowedUnit\n if (borrowerAmount != 0) {\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n\n uint256 borrowerAccrued = add_(rewardTokenAccrued[borrower], borrowerDelta);\n rewardTokenAccrued[borrower] = borrowerAccrued;\n\n emit DistributedBorrowerRewardToken(VToken(vToken), borrower, borrowerDelta, borrowerAccrued, borrowIndex);\n }\n }\n\n /**\n * @notice Transfer REWARD TOKEN to the user.\n * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all.\n * @param user The address of the user to transfer REWARD TOKEN to\n * @param amount The amount of REWARD TOKEN to (possibly) transfer\n * @return The amount of REWARD TOKEN which was NOT transferred to the user\n */\n function _grantRewardToken(address user, uint256 amount) internal returns (uint256) {\n uint256 rewardTokenRemaining = rewardToken.balanceOf(address(this));\n if (amount > 0 && amount <= rewardTokenRemaining) {\n rewardToken.safeTransfer(user, amount);\n return 0;\n }\n return amount;\n }\n\n /**\n * @notice Accrue REWARD TOKEN to the market by updating the supply index\n * @param vToken The market whose supply index to update\n * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n */\n function _updateRewardTokenSupplyIndex(address vToken) internal {\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n uint256 supplySpeed = rewardTokenSupplySpeeds[vToken];\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n blockNumber = supplyState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(uint256(blockNumber), uint256(supplyState.block));\n\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = VToken(vToken).totalSupply();\n uint256 accruedSinceUpdate = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(accruedSinceUpdate, supplyTokens)\n : Double({ mantissa: 0 });\n supplyState.index = safe224(\n add_(Double({ mantissa: supplyState.index }), ratio).mantissa,\n \"new index exceeds 224 bits\"\n );\n supplyState.block = blockNumber;\n } else if (deltaBlocks > 0) {\n supplyState.block = blockNumber;\n }\n\n emit RewardTokenSupplyIndexUpdated(vToken);\n }\n\n /**\n * @notice Accrue REWARD TOKEN to the market by updating the borrow index\n * @param vToken The market whose borrow index to update\n * @param marketBorrowIndex The current global borrow index of vToken\n * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n */\n function _updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) internal {\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n uint256 borrowSpeed = rewardTokenBorrowSpeeds[vToken];\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n blockNumber = borrowState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(uint256(blockNumber), uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n uint256 accruedSinceUpdate = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(accruedSinceUpdate, borrowAmount)\n : Double({ mantissa: 0 });\n borrowState.index = safe224(\n add_(Double({ mantissa: borrowState.index }), ratio).mantissa,\n \"new index exceeds 224 bits\"\n );\n borrowState.block = blockNumber;\n } else if (deltaBlocks > 0) {\n borrowState.block = blockNumber;\n }\n\n emit RewardTokenBorrowIndexUpdated(vToken, marketBorrowIndex);\n }\n}\n" + }, + "contracts/RiskFund/IProtocolShareReserve.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IProtocolShareReserve\n * @author Venus\n * @notice Interface implemented by `ProtocolShareReserve`.\n */\ninterface IProtocolShareReserve {\n function updateAssetsState(address comptroller, address asset) external;\n}\n" + }, + "contracts/RiskFund/IRiskFund.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IRiskFund\n * @author Venus\n * @notice Interface implemented by `RiskFund`.\n */\ninterface IRiskFund {\n function swapPoolsAssets(\n address[] calldata markets,\n uint256[] calldata amountsOutMin,\n address[][] calldata paths,\n uint256 deadline\n ) external returns (uint256);\n\n function transferReserveForAuction(address comptroller, uint256 amount) external returns (uint256);\n\n function updateAssetsState(address comptroller, address asset) external;\n\n function convertibleBaseAsset() external view returns (address);\n\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256);\n}\n" + }, + "contracts/RiskFund/ProtocolShareReserve.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { IProtocolShareReserve } from \"./IProtocolShareReserve.sol\";\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\ncontract ProtocolShareReserve is ExponentialNoError, ReserveHelpers, IProtocolShareReserve {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n address public protocolIncome;\n address public riskFund;\n // Percentage of funds not sent to the RiskFund contract when the funds are released, following the project Tokenomics\n uint256 private constant PROTOCOL_SHARE_PERCENTAGE = 50;\n uint256 private constant BASE_UNIT = 100;\n\n /// @notice Emitted when funds are released\n event FundsReleased(address indexed comptroller, address indexed asset, uint256 amount);\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner.\n * @param protocolIncome_ The address protocol income will be sent to\n * @param riskFund_ Risk fund address\n * @custom:error ZeroAddressNotAllowed is thrown when protocol income address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n */\n function initialize(address protocolIncome_, address riskFund_) external initializer {\n ensureNonzeroAddress(protocolIncome_);\n ensureNonzeroAddress(riskFund_);\n\n __Ownable2Step_init();\n\n protocolIncome = protocolIncome_;\n riskFund = riskFund_;\n }\n\n /**\n * @notice Pool registry setter.\n * @param poolRegistry_ Address of the pool registry\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function setPoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Release funds\n * @param comptroller Pool's Comptroller\n * @param asset Asset to be released\n * @param amount Amount to release\n * @return Number of total released tokens\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function releaseFunds(address comptroller, address asset, uint256 amount) external nonReentrant returns (uint256) {\n ensureNonzeroAddress(asset);\n require(amount <= _poolsAssetsReserves[comptroller][asset], \"ProtocolShareReserve: Insufficient pool balance\");\n\n assetsReserves[asset] -= amount;\n _poolsAssetsReserves[comptroller][asset] -= amount;\n uint256 protocolIncomeAmount = mul_(\n Exp({ mantissa: amount }),\n div_(Exp({ mantissa: PROTOCOL_SHARE_PERCENTAGE * EXP_SCALE }), BASE_UNIT)\n ).mantissa;\n\n address riskFund_ = riskFund;\n\n emit FundsReleased(comptroller, asset, amount);\n\n IERC20Upgradeable(asset).safeTransfer(protocolIncome, protocolIncomeAmount);\n IERC20Upgradeable(asset).safeTransfer(riskFund_, amount - protocolIncomeAmount);\n\n // Update the pool asset's state in the risk fund for the above transfer.\n IRiskFund(riskFund_).updateAssetsState(comptroller, asset);\n\n return amount;\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to the protocol share reserve.\n * @param comptroller Comptroller address(pool)\n * @param asset Asset address.\n */\n function updateAssetsState(\n address comptroller,\n address asset\n ) public override(IProtocolShareReserve, ReserveHelpers) {\n super.updateAssetsState(comptroller, asset);\n }\n}\n" + }, + "contracts/RiskFund/ReserveHelpers.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\n\ncontract ReserveHelpers is Ownable2StepUpgradeable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n uint256 private constant NOT_ENTERED = 1;\n\n uint256 private constant ENTERED = 2;\n\n // Store the previous state for the asset transferred to ProtocolShareReserve combined(for all pools).\n mapping(address => uint256) public assetsReserves;\n\n // Store the asset's reserve per pool in the ProtocolShareReserve.\n // Comptroller(pool) -> Asset -> amount\n mapping(address => mapping(address => uint256)) internal _poolsAssetsReserves;\n\n // Address of pool registry contract\n address public poolRegistry;\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n uint256 internal status;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n */\n uint256[46] private __gap;\n\n /// @notice Event emitted after the update of the assets reserves.\n /// @param comptroller Pool's Comptroller address\n /// @param asset Token address\n /// @param amount An amount by which the reserves have increased\n event AssetsReservesUpdated(address indexed comptroller, address indexed asset, uint256 amount);\n\n /// @notice event emitted on sweep token success\n event SweepToken(address indexed token, address indexed to, uint256 amount);\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(status != ENTERED, \"re-entered\");\n status = ENTERED;\n _;\n status = NOT_ENTERED;\n }\n\n /**\n * @notice A public function to sweep accidental BEP-20 transfers to this contract. Tokens are sent to the address `to`, provided in input\n * @param _token The address of the BEP-20 token to sweep\n * @param _to Recipient of the output tokens.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n * @custom:access Only Owner\n */\n function sweepToken(address _token, address _to) external onlyOwner nonReentrant {\n ensureNonzeroAddress(_to);\n uint256 balanceDfference_;\n uint256 balance_ = IERC20Upgradeable(_token).balanceOf(address(this));\n\n require(balance_ > assetsReserves[_token], \"ReserveHelpers: Zero surplus tokens\");\n unchecked {\n balanceDfference_ = balance_ - assetsReserves[_token];\n }\n\n emit SweepToken(_token, _to, balanceDfference_);\n IERC20Upgradeable(_token).safeTransfer(_to, balanceDfference_);\n }\n\n /**\n * @notice Get the Amount of the asset in the risk fund for the specific pool.\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n * @return Asset's reserve in risk fund.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function getPoolAssetReserve(address comptroller, address asset) external view returns (uint256) {\n ensureNonzeroAddress(asset);\n require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n return _poolsAssetsReserves[comptroller][asset];\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to risk fund\n * and transferring funds to the protocol share reserve\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function updateAssetsState(address comptroller, address asset) public virtual {\n ensureNonzeroAddress(asset);\n require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n address poolRegistry_ = poolRegistry;\n require(poolRegistry_ != address(0), \"ReserveHelpers: Pool Registry address is not set\");\n require(\n PoolRegistryInterface(poolRegistry_).getVTokenForAsset(comptroller, asset) != address(0),\n \"ReserveHelpers: The pool doesn't support the asset\"\n );\n\n uint256 currentBalance = IERC20Upgradeable(asset).balanceOf(address(this));\n uint256 assetReserve = assetsReserves[asset];\n if (currentBalance > assetReserve) {\n uint256 balanceDifference;\n unchecked {\n balanceDifference = currentBalance - assetReserve;\n }\n assetsReserves[asset] += balanceDifference;\n _poolsAssetsReserves[comptroller][asset] += balanceDifference;\n emit AssetsReservesUpdated(comptroller, asset, balanceDifference);\n }\n }\n}\n" + }, + "contracts/RiskFund/RiskFund.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { IPancakeswapV2Router } from \"../IPancakeswapV2Router.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { ApproveOrRevert } from \"../lib/ApproveOrRevert.sol\";\n\n/**\n * @title RiskFund\n * @author Venus\n * @notice Contract with basic features to track/hold different assets for different Comptrollers.\n * @dev This contract does not support BNB.\n */\ncontract RiskFund is AccessControlledV8, ExponentialNoError, ReserveHelpers, MaxLoopsLimitHelper, IRiskFund {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using ApproveOrRevert for IERC20Upgradeable;\n\n address public convertibleBaseAsset;\n address public shortfall;\n address public pancakeSwapRouter;\n uint256 public minAmountToConvert;\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @notice Emitted when shortfall contract address is updated\n event ShortfallContractUpdated(address indexed oldShortfallContract, address indexed newShortfallContract);\n\n /// @notice Emitted when convertible base asset is updated\n event ConvertibleBaseAssetUpdated(address indexed oldConvertibleBaseAsset, address indexed newConvertibleBaseAsset);\n\n /// @notice Emitted when PancakeSwap router contract address is updated\n event PancakeSwapRouterUpdated(address indexed oldPancakeSwapRouter, address indexed newPancakeSwapRouter);\n\n /// @notice Emitted when minimum amount to convert is updated\n event MinAmountToConvertUpdated(uint256 oldMinAmountToConvert, uint256 newMinAmountToConvert);\n\n /// @notice Emitted when pools assets are swapped\n event SwappedPoolsAssets(address[] markets, uint256[] amountsOutMin, uint256 totalAmount);\n\n /// @notice Emitted when reserves are transferred for auction\n event TransferredReserveForAuction(address indexed comptroller, uint256 amount);\n\n /// @dev Note that the contract is upgradeable. Use initialize() or reinitializers\n /// to set the state variables.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner.\n * @param pancakeSwapRouter_ Address of the PancakeSwap router\n * @param minAmountToConvert_ Minimum amount assets must be worth to convert into base asset\n * @param convertibleBaseAsset_ Address of the base asset\n * @param accessControlManager_ Address of the access control contract\n * @param loopsLimit_ Limit for the loops in the contract to avoid DOS\n * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n */\n function initialize(\n address pancakeSwapRouter_,\n uint256 minAmountToConvert_,\n address convertibleBaseAsset_,\n address accessControlManager_,\n uint256 loopsLimit_\n ) external initializer {\n ensureNonzeroAddress(pancakeSwapRouter_);\n ensureNonzeroAddress(convertibleBaseAsset_);\n require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n require(loopsLimit_ > 0, \"Risk Fund: Loops limit can not be zero\");\n\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n\n pancakeSwapRouter = pancakeSwapRouter_;\n minAmountToConvert = minAmountToConvert_;\n convertibleBaseAsset = convertibleBaseAsset_;\n\n _setMaxLoopsLimit(loopsLimit_);\n }\n\n /**\n * @notice Pool registry setter\n * @param poolRegistry_ Address of the pool registry\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function setPoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Shortfall contract address setter\n * @param shortfallContractAddress_ Address of the auction contract\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n */\n function setShortfallContractAddress(address shortfallContractAddress_) external onlyOwner {\n ensureNonzeroAddress(shortfallContractAddress_);\n\n address oldShortfallContractAddress = shortfall;\n shortfall = shortfallContractAddress_;\n emit ShortfallContractUpdated(oldShortfallContractAddress, shortfallContractAddress_);\n }\n\n /**\n * @notice PancakeSwap router address setter\n * @param pancakeSwapRouter_ Address of the PancakeSwap router\n * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n */\n function setPancakeSwapRouter(address pancakeSwapRouter_) external onlyOwner {\n ensureNonzeroAddress(pancakeSwapRouter_);\n address oldPancakeSwapRouter = pancakeSwapRouter;\n pancakeSwapRouter = pancakeSwapRouter_;\n emit PancakeSwapRouterUpdated(oldPancakeSwapRouter, pancakeSwapRouter_);\n }\n\n /**\n * @notice Min amount to convert setter\n * @param minAmountToConvert_ Min amount to convert.\n */\n function setMinAmountToConvert(uint256 minAmountToConvert_) external {\n _checkAccessAllowed(\"setMinAmountToConvert(uint256)\");\n require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n uint256 oldMinAmountToConvert = minAmountToConvert;\n minAmountToConvert = minAmountToConvert_;\n emit MinAmountToConvertUpdated(oldMinAmountToConvert, minAmountToConvert_);\n }\n\n /**\n * @notice Sets a new convertible base asset\n * @param _convertibleBaseAsset Address for new convertible base asset.\n */\n function setConvertibleBaseAsset(address _convertibleBaseAsset) external {\n _checkAccessAllowed(\"setConvertibleBaseAsset(address)\");\n require(_convertibleBaseAsset != address(0), \"Risk Fund: new convertible base asset address invalid\");\n\n address oldConvertibleBaseAsset = convertibleBaseAsset;\n convertibleBaseAsset = _convertibleBaseAsset;\n\n emit ConvertibleBaseAssetUpdated(oldConvertibleBaseAsset, _convertibleBaseAsset);\n }\n\n /**\n * @notice Swap array of pool assets into base asset's tokens of at least a minimum amount\n * @param markets Array of vTokens whose assets to swap for base asset\n * @param amountsOutMin Minimum amount to receive for swap\n * @param paths A path consisting of PCS token pairs for each swap\n * @param deadline Deadline for the swap\n * @return Number of swapped tokens\n * @custom:error ZeroAddressNotAllowed is thrown if PoolRegistry contract address is not configured\n */\n function swapPoolsAssets(\n address[] calldata markets,\n uint256[] calldata amountsOutMin,\n address[][] calldata paths,\n uint256 deadline\n ) external override nonReentrant returns (uint256) {\n _checkAccessAllowed(\"swapPoolsAssets(address[],uint256[],address[][],uint256)\");\n require(deadline >= block.timestamp, \"Risk fund: deadline passed\");\n address poolRegistry_ = poolRegistry;\n ensureNonzeroAddress(poolRegistry_);\n require(markets.length == amountsOutMin.length, \"Risk fund: markets and amountsOutMin are unequal lengths\");\n require(markets.length == paths.length, \"Risk fund: markets and paths are unequal lengths\");\n\n uint256 totalAmount;\n uint256 marketsCount = markets.length;\n\n _ensureMaxLoops(marketsCount);\n\n for (uint256 i; i < marketsCount; ++i) {\n address comptroller = address(VToken(markets[i]).comptroller());\n\n PoolRegistry.VenusPool memory pool = PoolRegistry(poolRegistry_).getPoolByComptroller(comptroller);\n require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n require(Comptroller(comptroller).isMarketListed(VToken(markets[i])), \"market is not listed\");\n\n uint256 swappedTokens = _swapAsset(VToken(markets[i]), comptroller, amountsOutMin[i], paths[i]);\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] += swappedTokens;\n assetsReserves[convertibleBaseAsset] += swappedTokens;\n totalAmount = totalAmount + swappedTokens;\n }\n\n emit SwappedPoolsAssets(markets, amountsOutMin, totalAmount);\n\n return totalAmount;\n }\n\n /**\n * @notice Transfer tokens for auction.\n * @param comptroller Comptroller of the pool.\n * @param amount Amount to be transferred to auction contract.\n * @return Number reserved tokens.\n */\n function transferReserveForAuction(\n address comptroller,\n uint256 amount\n ) external override nonReentrant returns (uint256) {\n address shortfall_ = shortfall;\n require(msg.sender == shortfall_, \"Risk fund: Only callable by Shortfall contract\");\n require(\n amount <= _poolsAssetsReserves[comptroller][convertibleBaseAsset],\n \"Risk Fund: Insufficient pool reserve.\"\n );\n unchecked {\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] =\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] -\n amount;\n }\n unchecked {\n assetsReserves[convertibleBaseAsset] = assetsReserves[convertibleBaseAsset] - amount;\n }\n\n emit TransferredReserveForAuction(comptroller, amount);\n IERC20Upgradeable(convertibleBaseAsset).safeTransfer(shortfall_, amount);\n\n return amount;\n }\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Get the Amount of the Base asset in the risk fund for the specific pool.\n * @param comptroller Comptroller address(pool).\n * @return Base Asset's reserve in risk fund.\n */\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256) {\n require(ComptrollerInterface(comptroller).isComptroller(), \"Risk Fund: Comptroller address invalid\");\n return _poolsAssetsReserves[comptroller][convertibleBaseAsset];\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to risk fund.\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n */\n function updateAssetsState(address comptroller, address asset) public override(IRiskFund, ReserveHelpers) {\n super.updateAssetsState(comptroller, asset);\n }\n\n /**\n * @dev Swap single asset to base asset.\n * @param vToken VToken\n * @param comptroller Comptroller address\n * @param amountOutMin Minimum amount to receive for swap\n * @param path A path for the swap consisting of PCS token pairs\n * @return Number of swapped tokens.\n */\n function _swapAsset(\n VToken vToken,\n address comptroller,\n uint256 amountOutMin,\n address[] calldata path\n ) internal returns (uint256) {\n require(amountOutMin != 0, \"RiskFund: amountOutMin must be greater than 0 to swap vToken\");\n uint256 totalAmount;\n\n address underlyingAsset = vToken.underlying();\n address convertibleBaseAsset_ = convertibleBaseAsset;\n uint256 balanceOfUnderlyingAsset = _poolsAssetsReserves[comptroller][underlyingAsset];\n\n if (balanceOfUnderlyingAsset == 0) {\n return 0;\n }\n\n ResilientOracleInterface oracle = ComptrollerViewInterface(comptroller).oracle();\n oracle.updateAssetPrice(convertibleBaseAsset_);\n Exp memory baseAssetPrice = Exp({ mantissa: oracle.getPrice(convertibleBaseAsset_) });\n uint256 amountOutMinInUsd = mul_ScalarTruncate(baseAssetPrice, amountOutMin);\n\n require(amountOutMinInUsd >= minAmountToConvert, \"RiskFund: minAmountToConvert violated\");\n\n assetsReserves[underlyingAsset] -= balanceOfUnderlyingAsset;\n _poolsAssetsReserves[comptroller][underlyingAsset] -= balanceOfUnderlyingAsset;\n\n if (underlyingAsset != convertibleBaseAsset_) {\n require(path[0] == underlyingAsset, \"RiskFund: swap path must start with the underlying asset\");\n require(\n path[path.length - 1] == convertibleBaseAsset_,\n \"RiskFund: finally path must be convertible base asset\"\n );\n address pancakeSwapRouter_ = pancakeSwapRouter;\n IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, 0);\n IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, balanceOfUnderlyingAsset);\n uint256[] memory amounts = IPancakeswapV2Router(pancakeSwapRouter_).swapExactTokensForTokens(\n balanceOfUnderlyingAsset,\n amountOutMin,\n path,\n address(this),\n block.timestamp\n );\n totalAmount = amounts[path.length - 1];\n } else {\n totalAmount = balanceOfUnderlyingAsset;\n }\n\n return totalAmount;\n }\n}\n" + }, + "contracts/Shortfall/Shortfall.sol": { + "content": "/// @notice SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"../RiskFund/IRiskFund.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { TokenDebtTracker } from \"../lib/TokenDebtTracker.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { EXP_SCALE } from \"../lib/constants.sol\";\n\n/**\n * @title Shortfall\n * @author Venus\n * @notice Shortfall is an auction contract designed to auction off the `convertibleBaseAsset` accumulated in `RiskFund`. The `convertibleBaseAsset`\n * is auctioned in exchange for users paying off the pool's bad debt. An auction can be started by anyone once a pool's bad debt has reached a minimum value.\n * This value is set and can be changed by the authorized accounts. If the pool’s bad debt exceeds the risk fund plus a 10% incentive, then the auction winner\n * is determined by who will pay off the largest percentage of the pool's bad debt. The auction winner then exchanges for the entire risk fund. Otherwise,\n * if the risk fund covers the pool's bad debt plus the 10% incentive, then the auction winner is determined by who will take the smallest percentage of the\n * risk fund in exchange for paying off all the pool's bad debt.\n */\ncontract Shortfall is Ownable2StepUpgradeable, AccessControlledV8, ReentrancyGuardUpgradeable, TokenDebtTracker {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /// @notice Type of auction\n enum AuctionType {\n LARGE_POOL_DEBT,\n LARGE_RISK_FUND\n }\n\n /// @notice Status of auction\n enum AuctionStatus {\n NOT_STARTED,\n STARTED,\n ENDED\n }\n\n /// @notice Auction metadata\n struct Auction {\n uint256 startBlock;\n AuctionType auctionType;\n AuctionStatus status;\n VToken[] markets;\n uint256 seizedRiskFund;\n address highestBidder;\n uint256 highestBidBps;\n uint256 highestBidBlock;\n uint256 startBidBps;\n mapping(VToken => uint256) marketDebt;\n mapping(VToken => uint256) bidAmount;\n }\n\n /// @dev Max basis points i.e., 100%\n uint256 private constant MAX_BPS = 10000;\n\n uint256 private constant DEFAULT_NEXT_BIDDER_BLOCK_LIMIT = 100;\n\n uint256 private constant DEFAULT_WAIT_FOR_FIRST_BIDDER = 100;\n\n uint256 private constant DEFAULT_INCENTIVE_BPS = 1000; // 10%\n\n /// @notice Pool registry address\n address public poolRegistry;\n\n /// @notice Risk fund address\n IRiskFund public riskFund;\n\n /// @notice Minimum USD debt in pool for shortfall to trigger\n uint256 public minimumPoolBadDebt;\n\n /// @notice Incentive to auction participants, initial value set to 1000 or 10%\n uint256 public incentiveBps;\n\n /// @notice Time to wait for next bidder. Initially waits for 100 blocks\n uint256 public nextBidderBlockLimit;\n\n /// @notice Boolean of if auctions are paused\n bool public auctionsPaused;\n\n /// @notice Time to wait for first bidder. Initially waits for 100 blocks\n uint256 public waitForFirstBidder;\n\n /// @notice Auctions for each pool\n mapping(address => Auction) public auctions;\n\n /// @notice Emitted when a auction starts\n event AuctionStarted(\n address indexed comptroller,\n uint256 auctionStartBlock,\n AuctionType auctionType,\n VToken[] markets,\n uint256[] marketsDebt,\n uint256 seizedRiskFund,\n uint256 startBidBps\n );\n\n /// @notice Emitted when a bid is placed\n event BidPlaced(address indexed comptroller, uint256 auctionStartBlock, uint256 bidBps, address indexed bidder);\n\n /// @notice Emitted when a auction is completed\n event AuctionClosed(\n address indexed comptroller,\n uint256 auctionStartBlock,\n address indexed highestBidder,\n uint256 highestBidBps,\n uint256 seizedRiskFind,\n VToken[] markets,\n uint256[] marketDebt\n );\n\n /// @notice Emitted when a auction is restarted\n event AuctionRestarted(address indexed comptroller, uint256 auctionStartBlock);\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @notice Emitted when minimum pool bad debt is updated\n event MinimumPoolBadDebtUpdated(uint256 oldMinimumPoolBadDebt, uint256 newMinimumPoolBadDebt);\n\n /// @notice Emitted when wait for first bidder block count is updated\n event WaitForFirstBidderUpdated(uint256 oldWaitForFirstBidder, uint256 newWaitForFirstBidder);\n\n /// @notice Emitted when next bidder block limit is updated\n event NextBidderBlockLimitUpdated(uint256 oldNextBidderBlockLimit, uint256 newNextBidderBlockLimit);\n\n /// @notice Emitted when incentiveBps is updated\n event IncentiveBpsUpdated(uint256 oldIncentiveBps, uint256 newIncentiveBps);\n\n /// @notice Emitted when auctions are paused\n event AuctionsPaused(address sender);\n\n /// @notice Emitted when auctions are unpaused\n event AuctionsResumed(address sender);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initialize the shortfall contract\n * @param riskFund_ RiskFund contract address\n * @param minimumPoolBadDebt_ Minimum bad debt in base asset for a pool to start auction\n * @param accessControlManager_ AccessControlManager contract address\n * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n */\n function initialize(\n IRiskFund riskFund_,\n uint256 minimumPoolBadDebt_,\n address accessControlManager_\n ) external initializer {\n ensureNonzeroAddress(address(riskFund_));\n require(minimumPoolBadDebt_ != 0, \"invalid minimum pool bad debt\");\n\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n __ReentrancyGuard_init();\n __TokenDebtTracker_init();\n minimumPoolBadDebt = minimumPoolBadDebt_;\n riskFund = riskFund_;\n waitForFirstBidder = DEFAULT_WAIT_FOR_FIRST_BIDDER;\n nextBidderBlockLimit = DEFAULT_NEXT_BIDDER_BLOCK_LIMIT;\n incentiveBps = DEFAULT_INCENTIVE_BPS;\n auctionsPaused = false;\n }\n\n /**\n * @notice Place a bid greater than the previous in an ongoing auction\n * @param comptroller Comptroller address of the pool\n * @param bidBps The bid percent of the risk fund or bad debt depending on auction type\n * @param auctionStartBlock The block number when auction started\n * @custom:event Emits BidPlaced event on success\n */\n function placeBid(address comptroller, uint256 bidBps, uint256 auctionStartBlock) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(auction.startBlock == auctionStartBlock, \"auction has been restarted\");\n require(_isStarted(auction), \"no on-going auction\");\n require(!_isStale(auction), \"auction is stale, restart it\");\n require(bidBps > 0, \"basis points cannot be zero\");\n require(bidBps <= MAX_BPS, \"basis points cannot be more than 10000\");\n require(\n (auction.auctionType == AuctionType.LARGE_POOL_DEBT &&\n ((auction.highestBidder != address(0) && bidBps > auction.highestBidBps) ||\n (auction.highestBidder == address(0) && bidBps >= auction.startBidBps))) ||\n (auction.auctionType == AuctionType.LARGE_RISK_FUND &&\n ((auction.highestBidder != address(0) && bidBps < auction.highestBidBps) ||\n (auction.highestBidder == address(0) && bidBps <= auction.startBidBps))),\n \"your bid is not the highest\"\n );\n\n uint256 marketsCount = auction.markets.length;\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = VToken(address(auction.markets[i]));\n IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n if (auction.highestBidder != address(0)) {\n _transferOutOrTrackDebt(erc20, auction.highestBidder, auction.bidAmount[auction.markets[i]]);\n }\n uint256 balanceBefore = erc20.balanceOf(address(this));\n\n if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n uint256 currentBidAmount = ((auction.marketDebt[auction.markets[i]] * bidBps) / MAX_BPS);\n erc20.safeTransferFrom(msg.sender, address(this), currentBidAmount);\n } else {\n erc20.safeTransferFrom(msg.sender, address(this), auction.marketDebt[auction.markets[i]]);\n }\n\n uint256 balanceAfter = erc20.balanceOf(address(this));\n auction.bidAmount[auction.markets[i]] = balanceAfter - balanceBefore;\n }\n\n auction.highestBidder = msg.sender;\n auction.highestBidBps = bidBps;\n auction.highestBidBlock = block.number;\n\n emit BidPlaced(comptroller, auction.startBlock, bidBps, msg.sender);\n }\n\n /**\n * @notice Close an auction\n * @param comptroller Comptroller address of the pool\n * @custom:event Emits AuctionClosed event on successful close\n */\n function closeAuction(address comptroller) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(_isStarted(auction), \"no on-going auction\");\n require(\n block.number > auction.highestBidBlock + nextBidderBlockLimit && auction.highestBidder != address(0),\n \"waiting for next bidder. cannot close auction\"\n );\n\n uint256 marketsCount = auction.markets.length;\n uint256[] memory marketsDebt = new uint256[](marketsCount);\n\n auction.status = AuctionStatus.ENDED;\n\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = VToken(address(auction.markets[i]));\n IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n uint256 balanceBefore = erc20.balanceOf(address(auction.markets[i]));\n erc20.safeTransfer(address(auction.markets[i]), auction.bidAmount[auction.markets[i]]);\n uint256 balanceAfter = erc20.balanceOf(address(auction.markets[i]));\n marketsDebt[i] = balanceAfter - balanceBefore;\n\n auction.markets[i].badDebtRecovered(marketsDebt[i]);\n }\n\n uint256 riskFundBidAmount;\n\n if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n riskFundBidAmount = auction.seizedRiskFund;\n } else {\n riskFundBidAmount = (auction.seizedRiskFund * auction.highestBidBps) / MAX_BPS;\n }\n\n address convertibleBaseAsset = riskFund.convertibleBaseAsset();\n\n uint256 transferredAmount = riskFund.transferReserveForAuction(comptroller, riskFundBidAmount);\n _transferOutOrTrackDebt(IERC20Upgradeable(convertibleBaseAsset), auction.highestBidder, riskFundBidAmount);\n\n emit AuctionClosed(\n comptroller,\n auction.startBlock,\n auction.highestBidder,\n auction.highestBidBps,\n transferredAmount,\n auction.markets,\n marketsDebt\n );\n }\n\n /**\n * @notice Start a auction when there is not currently one active\n * @param comptroller Comptroller address of the pool\n * @custom:event Emits AuctionStarted event on success\n * @custom:event Errors if auctions are paused\n */\n function startAuction(address comptroller) external nonReentrant {\n require(!auctionsPaused, \"Auctions are paused\");\n _startAuction(comptroller);\n }\n\n /**\n * @notice Restart an auction\n * @param comptroller Address of the pool\n * @custom:event Emits AuctionRestarted event on successful restart\n */\n function restartAuction(address comptroller) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(!auctionsPaused, \"auctions are paused\");\n require(_isStarted(auction), \"no on-going auction\");\n require(_isStale(auction), \"you need to wait for more time for first bidder\");\n\n auction.status = AuctionStatus.ENDED;\n\n emit AuctionRestarted(comptroller, auction.startBlock);\n _startAuction(comptroller);\n }\n\n /**\n * @notice Update next bidder block limit which is used determine when an auction can be closed\n * @param _nextBidderBlockLimit New next bidder block limit\n * @custom:event Emits NextBidderBlockLimitUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateNextBidderBlockLimit(uint256 _nextBidderBlockLimit) external {\n _checkAccessAllowed(\"updateNextBidderBlockLimit(uint256)\");\n require(_nextBidderBlockLimit != 0, \"_nextBidderBlockLimit must not be 0\");\n uint256 oldNextBidderBlockLimit = nextBidderBlockLimit;\n nextBidderBlockLimit = _nextBidderBlockLimit;\n emit NextBidderBlockLimitUpdated(oldNextBidderBlockLimit, _nextBidderBlockLimit);\n }\n\n /**\n * @notice Updates the incentive BPS\n * @param _incentiveBps New incentive BPS\n * @custom:event Emits IncentiveBpsUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateIncentiveBps(uint256 _incentiveBps) external {\n _checkAccessAllowed(\"updateIncentiveBps(uint256)\");\n require(_incentiveBps != 0, \"incentiveBps must not be 0\");\n uint256 oldIncentiveBps = incentiveBps;\n incentiveBps = _incentiveBps;\n emit IncentiveBpsUpdated(oldIncentiveBps, _incentiveBps);\n }\n\n /**\n * @notice Update minimum pool bad debt to start auction\n * @param _minimumPoolBadDebt Minimum bad debt in the base asset for a pool to start auction\n * @custom:event Emits MinimumPoolBadDebtUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateMinimumPoolBadDebt(uint256 _minimumPoolBadDebt) external {\n _checkAccessAllowed(\"updateMinimumPoolBadDebt(uint256)\");\n uint256 oldMinimumPoolBadDebt = minimumPoolBadDebt;\n minimumPoolBadDebt = _minimumPoolBadDebt;\n emit MinimumPoolBadDebtUpdated(oldMinimumPoolBadDebt, _minimumPoolBadDebt);\n }\n\n /**\n * @notice Update wait for first bidder block count. If the first bid is not made within this limit, the auction is closed and needs to be restarted\n * @param _waitForFirstBidder New wait for first bidder block count\n * @custom:event Emits WaitForFirstBidderUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateWaitForFirstBidder(uint256 _waitForFirstBidder) external {\n _checkAccessAllowed(\"updateWaitForFirstBidder(uint256)\");\n uint256 oldWaitForFirstBidder = waitForFirstBidder;\n waitForFirstBidder = _waitForFirstBidder;\n emit WaitForFirstBidderUpdated(oldWaitForFirstBidder, _waitForFirstBidder);\n }\n\n /**\n * @notice Update the pool registry this shortfall supports\n * @dev After Pool Registry is deployed we need to set the pool registry address\n * @param poolRegistry_ Address of pool registry contract\n * @custom:event Emits PoolRegistryUpdated on success\n * @custom:access Restricted to owner\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function updatePoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Pause auctions. This disables starting new auctions but lets the current auction finishes\n * @custom:event Emits AuctionsPaused on success\n * @custom:error Errors is auctions are paused\n * @custom:access Restricted by ACM\n */\n function pauseAuctions() external {\n _checkAccessAllowed(\"pauseAuctions()\");\n require(!auctionsPaused, \"Auctions are already paused\");\n auctionsPaused = true;\n emit AuctionsPaused(msg.sender);\n }\n\n /**\n * @notice Resume paused auctions.\n * @custom:event Emits AuctionsResumed on success\n * @custom:error Errors is auctions are active\n * @custom:access Restricted by ACM\n */\n function resumeAuctions() external {\n _checkAccessAllowed(\"resumeAuctions()\");\n require(auctionsPaused, \"Auctions are not paused\");\n auctionsPaused = false;\n emit AuctionsResumed(msg.sender);\n }\n\n /**\n * @notice Start a auction when there is not currently one active\n * @param comptroller Comptroller address of the pool\n */\n function _startAuction(address comptroller) internal {\n PoolRegistryInterface.VenusPool memory pool = PoolRegistry(poolRegistry).getPoolByComptroller(comptroller);\n require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n\n Auction storage auction = auctions[comptroller];\n require(\n auction.status == AuctionStatus.NOT_STARTED || auction.status == AuctionStatus.ENDED,\n \"auction is on-going\"\n );\n\n auction.highestBidBps = 0;\n auction.highestBidBlock = 0;\n\n uint256 marketsCount = auction.markets.length;\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = auction.markets[i];\n auction.marketDebt[vToken] = 0;\n }\n\n delete auction.markets;\n\n VToken[] memory vTokens = _getAllMarkets(comptroller);\n marketsCount = vTokens.length;\n ResilientOracleInterface priceOracle = _getPriceOracle(comptroller);\n uint256 poolBadDebt;\n\n uint256[] memory marketsDebt = new uint256[](marketsCount);\n auction.markets = new VToken[](marketsCount);\n\n for (uint256 i; i < marketsCount; ++i) {\n uint256 marketBadDebt = vTokens[i].badDebt();\n\n priceOracle.updatePrice(address(vTokens[i]));\n uint256 usdValue = (priceOracle.getUnderlyingPrice(address(vTokens[i])) * marketBadDebt) / EXP_SCALE;\n\n poolBadDebt = poolBadDebt + usdValue;\n auction.markets[i] = vTokens[i];\n auction.marketDebt[vTokens[i]] = marketBadDebt;\n marketsDebt[i] = marketBadDebt;\n }\n\n require(poolBadDebt >= minimumPoolBadDebt, \"pool bad debt is too low\");\n\n priceOracle.updateAssetPrice(riskFund.convertibleBaseAsset());\n uint256 riskFundBalance = (priceOracle.getPrice(riskFund.convertibleBaseAsset()) *\n riskFund.getPoolsBaseAssetReserves(comptroller)) / EXP_SCALE;\n uint256 remainingRiskFundBalance = riskFundBalance;\n uint256 badDebtPlusIncentive = poolBadDebt + ((poolBadDebt * incentiveBps) / MAX_BPS);\n if (badDebtPlusIncentive >= riskFundBalance) {\n auction.startBidBps =\n (MAX_BPS * MAX_BPS * remainingRiskFundBalance) /\n (poolBadDebt * (MAX_BPS + incentiveBps));\n remainingRiskFundBalance = 0;\n auction.auctionType = AuctionType.LARGE_POOL_DEBT;\n } else {\n uint256 maxSeizeableRiskFundBalance = badDebtPlusIncentive;\n\n remainingRiskFundBalance = remainingRiskFundBalance - maxSeizeableRiskFundBalance;\n auction.auctionType = AuctionType.LARGE_RISK_FUND;\n auction.startBidBps = MAX_BPS;\n }\n\n auction.seizedRiskFund = riskFundBalance - remainingRiskFundBalance;\n auction.startBlock = block.number;\n auction.status = AuctionStatus.STARTED;\n auction.highestBidder = address(0);\n\n emit AuctionStarted(\n comptroller,\n auction.startBlock,\n auction.auctionType,\n auction.markets,\n marketsDebt,\n auction.seizedRiskFund,\n auction.startBidBps\n );\n }\n\n /**\n * @dev Returns the price oracle of the pool\n * @param comptroller Address of the pool's comptroller\n * @return oracle The pool's price oracle\n */\n function _getPriceOracle(address comptroller) internal view returns (ResilientOracleInterface) {\n return ResilientOracleInterface(ComptrollerViewInterface(comptroller).oracle());\n }\n\n /**\n * @dev Returns all markets of the pool\n * @param comptroller Address of the pool's comptroller\n * @return markets The pool's markets as VToken array\n */\n function _getAllMarkets(address comptroller) internal view returns (VToken[] memory) {\n return ComptrollerInterface(comptroller).getAllMarkets();\n }\n\n /**\n * @dev Checks if the auction has started\n * @param auction The auction to query the status for\n * @return True if the auction has started\n */\n function _isStarted(Auction storage auction) internal view returns (bool) {\n return auction.status == AuctionStatus.STARTED;\n }\n\n /**\n * @dev Checks if the auction is stale, i.e. there's no bidder and the auction\n * was started more than waitForFirstBidder blocks ago.\n * @param auction The auction to query the status for\n * @return True if the auction is stale\n */\n function _isStale(Auction storage auction) internal view returns (bool) {\n bool noBidder = auction.highestBidder == address(0);\n return noBidder && (block.number > auction.startBlock + waitForFirstBidder);\n }\n}\n" + }, + "contracts/test/ComptrollerHarness.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { Comptroller } from \"../Comptroller.sol\";\n\ncontract ComptrollerHarness is Comptroller {\n uint256 public blockNumber;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n function harnessFastForward(uint256 blocks) public returns (uint256) {\n blockNumber += blocks;\n return blockNumber;\n }\n\n function setBlockNumber(uint256 number) public {\n blockNumber = number;\n }\n}\n\ncontract EchoTypesComptroller {\n function stringy(string memory s) public pure returns (string memory) {\n return s;\n }\n\n function addresses(address a) public pure returns (address) {\n return a;\n }\n\n function booly(bool b) public pure returns (bool) {\n return b;\n }\n\n function listOInts(uint256[] memory u) public pure returns (uint256[] memory) {\n return u;\n }\n\n function reverty() public pure {\n require(false, \"gotcha sucka\");\n }\n}\n" + }, + "contracts/test/ComptrollerScenario.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\n\ncontract ComptrollerScenario is Comptroller {\n uint256 public blockNumber;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n function fastForward(uint256 blocks) public returns (uint256) {\n blockNumber += blocks;\n return blockNumber;\n }\n\n function setBlockNumber(uint256 number) public {\n blockNumber = number;\n }\n\n function unlist(VToken vToken) public {\n markets[address(vToken)].isListed = false;\n }\n\n function membershipLength(VToken vToken) public view returns (uint256) {\n return accountAssets[address(vToken)].length;\n }\n}\n" + }, + "contracts/test/ERC20.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { SafeMath } from \"./SafeMath.sol\";\n\ninterface ERC20Base {\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function totalSupply() external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function balanceOf(address who) external view returns (uint256);\n}\n\nabstract contract ERC20 is ERC20Base {\n function transfer(address to, uint256 value) external virtual returns (bool);\n\n function transferFrom(address from, address to, uint256 value) external virtual returns (bool);\n}\n\nabstract contract ERC20NS is ERC20Base {\n function transfer(address to, uint256 value) external virtual;\n\n function transferFrom(address from, address to, uint256 value) external virtual;\n}\n\n/**\n * @title Standard ERC20 token\n * @dev Implementation of the basic standard token.\n * See https://github.com/ethereum/EIPs/issues/20\n */\ncontract StandardToken is ERC20 {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external virtual override returns (bool) {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) external virtual override returns (bool) {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function approve(address _spender, uint256 amount) external virtual override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\n/**\n * @title Non-Standard ERC20 token\n * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`\n * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\ncontract NonStandardToken is ERC20NS {\n using SafeMath for uint256;\n\n string public name;\n uint8 public decimals;\n string public symbol;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external override {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n }\n\n function transferFrom(address src, address dst, uint256 amount) external override {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n }\n\n function approve(address _spender, uint256 amount) external override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\ncontract ERC20Harness is StandardToken {\n using SafeMath for uint256;\n // To support testing, we can specify addresses for which transferFrom should fail and return false\n mapping(address => bool) public failTransferFromAddresses;\n\n // To support testing, we allow the contract to always fail `transfer`.\n mapping(address => bool) public failTransferToAddresses;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferToAddresses[dst]) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferFromAddresses[src]) {\n return false;\n }\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\n failTransferFromAddresses[src] = _fail;\n }\n\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\n failTransferToAddresses[dst] = _fail;\n }\n\n function harnessSetBalance(address _account, uint256 _amount) public {\n balanceOf[_account] = _amount;\n }\n}\n" + }, + "contracts/test/EvilToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { FaucetToken } from \"./FaucetToken.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title The Compound Evil Test Token\n * @author Compound\n * @notice A simple test token that fails certain operations\n */\ncontract EvilToken is FaucetToken {\n using SafeMath for uint256;\n\n bool public fail;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) FaucetToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {\n fail = true;\n }\n\n function setFail(bool _fail) external {\n fail = _fail;\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool) {\n if (fail) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(amount);\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) external override returns (bool) {\n if (fail) {\n return false;\n }\n balanceOf[src] = balanceOf[src].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(amount);\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" + }, + "contracts/test/FaucetToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { StandardToken, NonStandardToken } from \"./ERC20.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title The Compound Faucet Test Token\n * @author Compound\n * @notice A simple test token that lets anyone get more of it.\n */\ncontract FaucetToken is StandardToken {\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf[_owner] += value;\n totalSupply += value;\n emit Transfer(address(this), _owner, value);\n }\n}\n\n/**\n * @title The Compound Faucet Test Token (non-standard)\n * @author Compound\n * @notice A simple test token that lets anyone get more of it.\n */\ncontract FaucetNonStandardToken is NonStandardToken {\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n NonStandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf[_owner] += value;\n totalSupply += value;\n emit Transfer(address(this), _owner, value);\n }\n}\n\n/**\n * @title The Compound Faucet Re-Entrant Test Token\n * @author Compound\n * @notice A test token that is malicious and tries to re-enter callers\n */\ncontract FaucetTokenReEntrantHarness {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 private totalSupply_;\n mapping(address => mapping(address => uint256)) private allowance_;\n mapping(address => uint256) private balanceOf_;\n\n bytes public reEntryCallData;\n string public reEntryFun;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n modifier reEnter(string memory funName) {\n string memory _reEntryFun = reEntryFun;\n if (compareStrings(_reEntryFun, funName)) {\n reEntryFun = \"\"; // Clear re-entry fun\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = msg.sender.call(reEntryCallData);\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 0) {\n revert(add(returndata, 0x20), returndatasize())\n }\n }\n }\n\n _;\n }\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol,\n bytes memory _reEntryCallData,\n string memory _reEntryFun\n ) {\n totalSupply_ = _initialAmount;\n balanceOf_[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n reEntryCallData = _reEntryCallData;\n reEntryFun = _reEntryFun;\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf_[_owner] += value;\n totalSupply_ += value;\n emit Transfer(address(this), _owner, value);\n }\n\n function totalSupply() public reEnter(\"totalSupply\") returns (uint256) {\n return totalSupply_;\n }\n\n function allowance(address owner, address spender) public reEnter(\"allowance\") returns (uint256 remaining) {\n return allowance_[owner][spender];\n }\n\n function approve(address spender, uint256 amount) public reEnter(\"approve\") returns (bool success) {\n _approve(msg.sender, spender, amount);\n return true;\n }\n\n function balanceOf(address owner) public reEnter(\"balanceOf\") returns (uint256 balance) {\n return balanceOf_[owner];\n }\n\n function transfer(address dst, uint256 amount) public reEnter(\"transfer\") returns (bool success) {\n _transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) public reEnter(\"transferFrom\") returns (bool success) {\n _transfer(src, dst, amount);\n _approve(src, msg.sender, allowance_[src][msg.sender].sub(amount));\n return true;\n }\n\n function _approve(address owner, address spender, uint256 amount) internal {\n require(spender != address(0), \"FaucetToken: approve to the zero address\");\n require(owner != address(0), \"FaucetToken: approve from the zero address\");\n allowance_[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n function _transfer(address src, address dst, uint256 amount) internal {\n require(dst != address(0), \"FaucetToken: transfer to the zero address\");\n balanceOf_[src] = balanceOf_[src].sub(amount);\n balanceOf_[dst] = balanceOf_[dst].add(amount);\n emit Transfer(src, dst, amount);\n }\n\n function compareStrings(string memory a, string memory b) internal pure returns (bool) {\n return keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)));\n }\n}\n" + }, + "contracts/test/FeeToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { FaucetToken } from \"./FaucetToken.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title Fee Token\n * @author Compound\n * @notice A simple test token that charges fees on transfer. Used to mock USDT.\n */\ncontract FeeToken is FaucetToken {\n using SafeMath for uint256;\n\n uint256 public basisPointFee;\n address public owner;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol,\n uint256 _basisPointFee,\n address _owner\n ) FaucetToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {\n basisPointFee = _basisPointFee;\n owner = _owner;\n }\n\n function transfer(address dst, uint256 amount) public override returns (bool) {\n uint256 fee = amount.mul(basisPointFee).div(10000);\n uint256 net = amount.sub(fee);\n balanceOf[owner] = balanceOf[owner].add(fee);\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(net);\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(address src, address dst, uint256 amount) public override returns (bool) {\n uint256 fee = amount.mul(basisPointFee).div(10000);\n uint256 net = amount.sub(fee);\n balanceOf[owner] = balanceOf[owner].add(fee);\n balanceOf[src] = balanceOf[src].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(net);\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" + }, + "contracts/test/HarnessMaxLoopsLimitHelper.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\n\ncontract HarnessMaxLoopsLimitHelper is MaxLoopsLimitHelper {\n function setMaxLoopsLimit(uint256 limit) external {\n _setMaxLoopsLimit(limit);\n }\n\n function ensureMaxLoops(uint256 limit) external view {\n _ensureMaxLoops(limit);\n }\n}\n" + }, + "contracts/test/lib/ApproveOrRevertHarness.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ApproveOrRevert } from \"../../lib/ApproveOrRevert.sol\";\n\ncontract ApproveOrRevertHarness {\n using ApproveOrRevert for IERC20Upgradeable;\n\n function approve(IERC20Upgradeable token, address spender, uint256 amount) external {\n token.approveOrRevert(spender, amount);\n }\n}\n" + }, + "contracts/test/lib/TokenDebtTrackerHarness.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { TokenDebtTracker } from \"../../lib/TokenDebtTracker.sol\";\n\ncontract TokenDebtTrackerHarness is TokenDebtTracker {\n function initialize() external initializer {\n __TokenDebtTracker_init();\n }\n\n function addTokenDebt(IERC20Upgradeable token, address user, uint256 amount) external {\n tokenDebt[token][user] += amount;\n totalTokenDebt[token] += amount;\n }\n\n function transferOutOrTrackDebt(IERC20Upgradeable token, address user, uint256 amount) external {\n _transferOutOrTrackDebt(token, user, amount);\n }\n\n function transferOutOrTrackDebtSkippingBalanceCheck(\n IERC20Upgradeable token,\n address user,\n uint256 amount\n ) external {\n _transferOutOrTrackDebtSkippingBalanceCheck(token, user, amount);\n }\n}\n" + }, + "contracts/test/MockDeflationaryToken.sol": { + "content": "pragma solidity 0.8.13;\n\ncontract MockDeflatingToken {\n string public constant NAME = \"Deflating Test Token\";\n string public constant SYMBOL = \"DTT\";\n uint8 public constant DECIMALS = 18;\n uint256 public totalSupply;\n mapping(address => uint256) public balanceOf;\n mapping(address => mapping(address => uint256)) public allowance;\n\n bytes32 public DOMAIN_SEPARATOR;\n // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n mapping(address => uint256) public nonces;\n\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n constructor(uint256 _totalSupply) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n DOMAIN_SEPARATOR = keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string NAME,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(NAME)),\n keccak256(bytes(\"1\")),\n chainId,\n address(this)\n )\n );\n _mint(msg.sender, _totalSupply);\n }\n\n function approve(address spender, uint256 value) external returns (bool) {\n _approve(msg.sender, spender, value);\n return true;\n }\n\n function transfer(address to, uint256 value) external returns (bool) {\n _transfer(msg.sender, to, value);\n return true;\n }\n\n function transferFrom(address from, address to, uint256 value) external returns (bool) {\n if (allowance[from][msg.sender] != type(uint256).max) {\n allowance[from][msg.sender] = allowance[from][msg.sender] - value;\n }\n _transfer(from, to, value);\n return true;\n }\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n require(deadline >= block.timestamp, \"EXPIRED\");\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR,\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))\n )\n );\n address recoveredAddress = ecrecover(digest, v, r, s);\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNATURE\");\n _approve(owner, spender, value);\n }\n\n function _mint(address to, uint256 value) internal {\n totalSupply = totalSupply + value;\n balanceOf[to] = balanceOf[to] + value;\n emit Transfer(address(0), to, value);\n }\n\n function _burn(address from, uint256 value) internal {\n balanceOf[from] = balanceOf[from] - value;\n totalSupply = totalSupply - value;\n emit Transfer(from, address(0), value);\n }\n\n function _approve(address owner, address spender, uint256 value) private {\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n function _transfer(address from, address to, uint256 value) private {\n uint256 burnAmount = value / 100;\n _burn(from, burnAmount);\n uint256 transferAmount = value - burnAmount;\n balanceOf[from] = balanceOf[from] - transferAmount;\n balanceOf[to] = balanceOf[to] + transferAmount;\n emit Transfer(from, to, transferAmount);\n }\n}\n" + }, + "contracts/test/Mocks/MockPriceOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { BinanceOracle } from \"@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol\";\nimport { ChainlinkOracle } from \"@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol\";\n\nimport { VToken } from \"../../VToken.sol\";\n\ncontract MockPriceOracle is ResilientOracleInterface {\n mapping(address => uint256) public assetPrices;\n\n //set price in 6 decimal precision\n // solhint-disable-next-line no-empty-blocks\n constructor() {}\n\n function setPrice(address asset, uint256 price) external {\n assetPrices[asset] = price;\n }\n\n // solhint-disable-next-line no-empty-blocks\n function updatePrice(address vToken) external override {}\n\n // solhint-disable-next-line no-empty-blocks\n function updateAssetPrice(address asset) external override {}\n\n function getPrice(address asset) external view returns (uint256) {\n return assetPrices[asset];\n }\n\n //https://compound.finance/docs/prices\n function getUnderlyingPrice(address vToken) public view override returns (uint256) {\n return assetPrices[VToken(vToken).underlying()];\n }\n}\n" + }, + "contracts/test/Mocks/MockToken.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockToken is ERC20 {\n uint8 private immutable _decimals;\n\n constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) {\n _decimals = decimals_;\n }\n\n function faucet(uint256 amount) external {\n _mint(msg.sender, amount);\n }\n\n function decimals() public view virtual override returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/test/SafeMath.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol\n// Subject to the MIT license.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction underflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts with custom message on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n" + }, + "contracts/test/UpgradedVToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\n/**\n * @title Venus's VToken Contract\n * @notice VTokens which wrap an EIP-20 underlying and are immutable\n * @author Venus\n */\ncontract UpgradedVToken is VToken {\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param riskManagement Addresses of risk fund contracts\n */\n\n /// @notice We added this new function to test contract upgrade\n function version() external pure returns (uint256) {\n return 2;\n }\n\n function initializeV2(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) public reinitializer(2) {\n super._initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_,\n admin_,\n accessControlManager_,\n riskManagement,\n reserveFactorMantissa_\n );\n }\n\n function getTokenUnderlying() public view returns (address) {\n return underlying;\n }\n}\n" + }, + "contracts/test/VTokenHarness.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\ncontract VTokenHarness is VToken {\n uint256 public blockNumber;\n uint256 public harnessExchangeRate;\n bool public harnessExchangeRateStored;\n\n mapping(address => bool) public failTransferToAddresses;\n\n function harnessSetAccrualBlockNumber(uint256 accrualBlockNumber_) external {\n accrualBlockNumber = accrualBlockNumber_;\n }\n\n function harnessSetBlockNumber(uint256 newBlockNumber) external {\n blockNumber = newBlockNumber;\n }\n\n function harnessFastForward(uint256 blocks) external {\n blockNumber += blocks;\n }\n\n function harnessSetBalance(address account, uint256 amount) external {\n accountTokens[account] = amount;\n }\n\n function harnessSetTotalSupply(uint256 totalSupply_) external {\n totalSupply = totalSupply_;\n }\n\n function harnessSetTotalBorrows(uint256 totalBorrows_) external {\n totalBorrows = totalBorrows_;\n }\n\n function harnessSetTotalReserves(uint256 totalReserves_) external {\n totalReserves = totalReserves_;\n }\n\n function harnessExchangeRateDetails(uint256 totalSupply_, uint256 totalBorrows_, uint256 totalReserves_) external {\n totalSupply = totalSupply_;\n totalBorrows = totalBorrows_;\n totalReserves = totalReserves_;\n }\n\n function harnessSetExchangeRate(uint256 exchangeRate) external {\n harnessExchangeRate = exchangeRate;\n harnessExchangeRateStored = true;\n }\n\n function harnessSetFailTransferToAddress(address to_, bool fail_) external {\n failTransferToAddresses[to_] = fail_;\n }\n\n function harnessMintFresh(address account, uint256 mintAmount) external {\n super._mintFresh(account, account, mintAmount);\n }\n\n function harnessRedeemFresh(address payable account, uint256 vTokenAmount, uint256 underlyingAmount) external {\n super._redeemFresh(account, vTokenAmount, underlyingAmount);\n }\n\n function harnessSetAccountBorrows(address account, uint256 principal, uint256 interestIndex) external {\n accountBorrows[account] = BorrowSnapshot({ principal: principal, interestIndex: interestIndex });\n }\n\n function harnessSetBorrowIndex(uint256 borrowIndex_) external {\n borrowIndex = borrowIndex_;\n }\n\n function harnessBorrowFresh(address payable account, uint256 borrowAmount) external {\n _borrowFresh(account, borrowAmount);\n }\n\n function harnessRepayBorrowFresh(address payer, address account, uint256 repayAmount) external {\n _repayBorrowFresh(payer, account, repayAmount);\n }\n\n function harnessLiquidateBorrowFresh(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VToken vTokenCollateral,\n bool skipLiquidityCheck\n ) external {\n _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n function harnessReduceReservesFresh(uint256 amount) external {\n return _reduceReservesFresh(amount);\n }\n\n function harnessSetReserveFactorFresh(uint256 newReserveFactorMantissa) external {\n _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n function harnessSetInterestRateModelFresh(InterestRateModel newInterestRateModel) external {\n _setInterestRateModelFresh(newInterestRateModel);\n }\n\n function harnessAccountBorrows(address account) external view returns (uint256 principal, uint256 interestIndex) {\n BorrowSnapshot memory snapshot = accountBorrows[account];\n return (snapshot.principal, snapshot.interestIndex);\n }\n\n function getBorrowRateMaxMantissa() external pure returns (uint256) {\n return MAX_BORROW_RATE_MANTISSA;\n }\n\n function harnessSetInterestRateModel(address newInterestRateModelAddress) public {\n interestRateModel = InterestRateModel(newInterestRateModelAddress);\n }\n\n function harnessCallPreBorrowHook(uint256 amount) public {\n comptroller.preBorrowHook(address(this), msg.sender, amount);\n }\n\n function _doTransferOut(address to, uint256 amount) internal override {\n require(failTransferToAddresses[to] == false, \"HARNESS_TOKEN_TRANSFER_OUT_FAILED\");\n return super._doTransferOut(to, amount);\n }\n\n function _exchangeRateStored() internal view override returns (uint256) {\n if (harnessExchangeRateStored) {\n return harnessExchangeRate;\n }\n return super._exchangeRateStored();\n }\n\n function _getBlockNumber() internal view override returns (uint256) {\n return blockNumber;\n }\n}\n" + }, + "contracts/VToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { VTokenInterface } from \"./VTokenInterfaces.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"./ComptrollerInterface.sol\";\nimport { TokenErrorReporter } from \"./ErrorReporter.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { IProtocolShareReserve } from \"./RiskFund/IProtocolShareReserve.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title VToken\n * @author Venus\n * @notice Each asset that is supported by a pool is integrated through an instance of the `VToken` contract. As outlined in the protocol overview,\n * each isolated pool creates its own `vToken` corresponding to an asset. Within a given pool, each included `vToken` is referred to as a market of\n * the pool. The main actions a user regularly interacts with in a market are:\n\n- mint/redeem of vTokens;\n- transfer of vTokens;\n- borrow/repay a loan on an underlying asset;\n- liquidate a borrow or liquidate/heal an account.\n\n * A user supplies the underlying asset to a pool by minting `vTokens`, where the corresponding `vToken` amount is determined by the `exchangeRate`.\n * The `exchangeRate` will change over time, dependent on a number of factors, some of which accrue interest. Additionally, once users have minted\n * `vToken` in a pool, they can borrow any asset in the isolated pool by using their `vToken` as collateral. In order to borrow an asset or use a `vToken`\n * as collateral, the user must be entered into each corresponding market (else, the `vToken` will not be considered collateral for a borrow). Note that\n * a user may borrow up to a portion of their collateral determined by the market’s collateral factor. However, if their borrowed amount exceeds an amount\n * calculated using the market’s corresponding liquidation threshold, the borrow is eligible for liquidation. When a user repays a borrow, they must also\n * pay off interest accrued on the borrow.\n * \n * The Venus protocol includes unique mechanisms for healing an account and liquidating an account. These actions are performed in the `Comptroller`\n * and consider all borrows and collateral for which a given account is entered within a market. These functions may only be called on an account with a\n * total collateral amount that is no larger than a universal `minLiquidatableCollateral` value, which is used for all markets within a `Comptroller`.\n * Both functions settle all of an account’s borrows, but `healAccount()` may add `badDebt` to a vToken. For more detail, see the description of\n * `healAccount()` and `liquidateAccount()` in the `Comptroller` summary section below.\n */\ncontract VToken is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n VTokenInterface,\n ExponentialNoError,\n TokenErrorReporter\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n uint256 internal constant DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA = 5e16; // 5%\n\n /*** Reentrancy Guard ***/\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(_notEntered, \"re-entered\");\n _notEntered = false;\n _;\n _notEntered = true; // get a gas-refund post-Istanbul\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param accessControlManager_ AccessControlManager contract address\n * @param riskManagement Addresses of risk & income related contracts\n * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n * @custom:error ZeroAddressNotAllowed is thrown when admin address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n */\n function initialize(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) external initializer {\n ensureNonzeroAddress(admin_);\n\n // Initialize the market\n _initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_,\n admin_,\n accessControlManager_,\n riskManagement,\n reserveFactorMantissa_\n );\n }\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return success True if the transfer succeeded, reverts otherwise\n * @custom:event Emits Transfer event on success\n * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n * @custom:access Not restricted\n */\n function transfer(address dst, uint256 amount) external override nonReentrant returns (bool) {\n _transferTokens(msg.sender, msg.sender, dst, amount);\n return true;\n }\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return success True if the transfer succeeded, reverts otherwise\n * @custom:event Emits Transfer event on success\n * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n * @custom:access Not restricted\n */\n function transferFrom(address src, address dst, uint256 amount) external override nonReentrant returns (bool) {\n _transferTokens(msg.sender, src, dst, amount);\n return true;\n }\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param amount The number of tokens that are approved (uint256.max means infinite)\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function approve(address spender, uint256 amount) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n transferAllowances[src][spender] = amount;\n emit Approval(src, spender, amount);\n return true;\n }\n\n /**\n * @notice Increase approval for `spender`\n * @param spender The address of the account which may transfer tokens\n * @param addedValue The number of additional tokens spender can transfer\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function increaseAllowance(address spender, uint256 addedValue) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n uint256 newAllowance = transferAllowances[src][spender];\n newAllowance += addedValue;\n transferAllowances[src][spender] = newAllowance;\n\n emit Approval(src, spender, newAllowance);\n return true;\n }\n\n /**\n * @notice Decreases approval for `spender`\n * @param spender The address of the account which may transfer tokens\n * @param subtractedValue The number of tokens to remove from total approval\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n uint256 currentAllowance = transferAllowances[src][spender];\n require(currentAllowance >= subtractedValue, \"decreased allowance below zero\");\n unchecked {\n currentAllowance -= subtractedValue;\n }\n\n transferAllowances[src][spender] = currentAllowance;\n\n emit Approval(src, spender, currentAllowance);\n return true;\n }\n\n /**\n * @notice Get the underlying balance of the `owner`\n * @dev This also accrues interest in a transaction\n * @param owner The address of the account to query\n * @return amount The amount of underlying owned by `owner`\n */\n function balanceOfUnderlying(address owner) external override returns (uint256) {\n Exp memory exchangeRate = Exp({ mantissa: exchangeRateCurrent() });\n return mul_ScalarTruncate(exchangeRate, accountTokens[owner]);\n }\n\n /**\n * @notice Returns the current total borrows plus accrued interest\n * @return totalBorrows The total borrows with interest\n */\n function totalBorrowsCurrent() external override nonReentrant returns (uint256) {\n accrueInterest();\n return totalBorrows;\n }\n\n /**\n * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex\n * @param account The address whose balance should be calculated after updating borrowIndex\n * @return borrowBalance The calculated balance\n */\n function borrowBalanceCurrent(address account) external override nonReentrant returns (uint256) {\n accrueInterest();\n return _borrowBalanceStored(account);\n }\n\n /**\n * @notice Sender supplies assets into the market and receives vTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param mintAmount The amount of the underlying asset to supply\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function mint(uint256 mintAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n _mintFresh(msg.sender, msg.sender, mintAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender calls on-behalf of minter. minter supplies assets into the market and receives vTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param minter User whom the supply will be attributed to\n * @param mintAmount The amount of the underlying asset to supply\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when minter address is zero\n */\n function mintBehalf(address minter, uint256 mintAmount) external override nonReentrant returns (uint256) {\n ensureNonzeroAddress(minter);\n\n accrueInterest();\n // _mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n _mintFresh(msg.sender, minter, mintAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender redeems vTokens in exchange for the underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemTokens The number of vTokens to redeem into underlying\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Redeem and Transfer events; may emit AccrueInterest\n * @custom:error RedeemTransferOutNotPossible is thrown when the protocol has insufficient cash\n * @custom:access Not restricted\n */\n function redeem(uint256 redeemTokens) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _redeemFresh emits redeem-specific logs on errors, so we don't need to\n _redeemFresh(msg.sender, redeemTokens, 0);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender redeems vTokens in exchange for a specified amount of underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemAmount The amount of underlying to receive from redeeming vTokens\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n */\n function redeemUnderlying(uint256 redeemAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _redeemFresh emits redeem-specific logs on errors, so we don't need to\n _redeemFresh(msg.sender, 0, redeemAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender borrows assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Borrow event; may emit AccrueInterest\n * @custom:error BorrowCashNotAvailable is thrown when the protocol has insufficient cash\n * @custom:access Not restricted\n */\n function borrow(uint256 borrowAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // borrowFresh emits borrow-specific logs on errors, so we don't need to\n _borrowFresh(msg.sender, borrowAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender repays their own borrow\n * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function repayBorrow(uint256 repayAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n _repayBorrowFresh(msg.sender, msg.sender, repayAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender repays a borrow belonging to borrower\n * @param borrower the account with the debt being payed off\n * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n _repayBorrowFresh(msg.sender, borrower, repayAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param borrower The borrower of this vToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n * @custom:access Not restricted\n */\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral\n ) external override returns (uint256) {\n _liquidateBorrow(msg.sender, borrower, repayAmount, vTokenCollateral, false);\n return NO_ERROR;\n }\n\n /**\n * @notice sets protocol share accumulated from liquidations\n * @dev must be equal or less than liquidation incentive - 1\n * @param newProtocolSeizeShareMantissa_ new protocol share mantissa\n * @custom:event Emits NewProtocolSeizeShare event on success\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:error ProtocolSeizeShareTooBig is thrown when the new seize share is too high\n * @custom:access Controlled by AccessControlManager\n */\n function setProtocolSeizeShare(uint256 newProtocolSeizeShareMantissa_) external {\n _checkAccessAllowed(\"setProtocolSeizeShare(uint256)\");\n uint256 liquidationIncentive = ComptrollerViewInterface(address(comptroller)).liquidationIncentiveMantissa();\n if (newProtocolSeizeShareMantissa_ + MANTISSA_ONE > liquidationIncentive) {\n revert ProtocolSeizeShareTooBig();\n }\n\n uint256 oldProtocolSeizeShareMantissa = protocolSeizeShareMantissa;\n protocolSeizeShareMantissa = newProtocolSeizeShareMantissa_;\n emit NewProtocolSeizeShare(oldProtocolSeizeShareMantissa, newProtocolSeizeShareMantissa_);\n }\n\n /**\n * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh\n * @dev Admin function to accrue interest and set a new reserve factor\n * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n * @custom:event Emits NewReserveFactor event; may emit AccrueInterest\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:error SetReserveFactorBoundsCheck is thrown when the new reserve factor is too high\n * @custom:access Controlled by AccessControlManager\n */\n function setReserveFactor(uint256 newReserveFactorMantissa) external override nonReentrant {\n _checkAccessAllowed(\"setReserveFactor(uint256)\");\n\n accrueInterest();\n _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n /**\n * @notice Accrues interest and reduces reserves by transferring to the protocol reserve contract\n * @param reduceAmount Amount of reduction to reserves\n * @custom:event Emits ReservesReduced event; may emit AccrueInterest\n * @custom:error ReduceReservesCashNotAvailable is thrown when the vToken does not have sufficient cash\n * @custom:error ReduceReservesCashValidation is thrown when trying to withdraw more cash than the reserves have\n * @custom:access Not restricted\n */\n function reduceReserves(uint256 reduceAmount) external override nonReentrant {\n accrueInterest();\n _reduceReservesFresh(reduceAmount);\n }\n\n /**\n * @notice The sender adds to reserves.\n * @param addAmount The amount of underlying token to add as reserves\n * @custom:event Emits ReservesAdded event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function addReserves(uint256 addAmount) external override nonReentrant {\n accrueInterest();\n _addReservesFresh(addAmount);\n }\n\n /**\n * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh\n * @dev Admin function to accrue interest and update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n * @custom:event Emits NewMarketInterestRateModel event; may emit AccrueInterest\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:access Controlled by AccessControlManager\n */\n function setInterestRateModel(InterestRateModel newInterestRateModel) external override {\n _checkAccessAllowed(\"setInterestRateModel(address)\");\n\n accrueInterest();\n _setInterestRateModelFresh(newInterestRateModel);\n }\n\n /**\n * @notice Repays a certain amount of debt, treats the rest of the borrow as bad debt, essentially\n * \"forgiving\" the borrower. Healing is a situation that should rarely happen. However, some pools\n * may list risky assets or be configured improperly – we want to still handle such cases gracefully.\n * We assume that Comptroller does the seizing, so this function is only available to Comptroller.\n * @dev This function does not call any Comptroller hooks (like \"healAllowed\"), because we assume\n * the Comptroller does all the necessary checks before calling this function.\n * @param payer account who repays the debt\n * @param borrower account to heal\n * @param repayAmount amount to repay\n * @custom:event Emits RepayBorrow, BadDebtIncreased events; may emit AccrueInterest\n * @custom:error HealBorrowUnauthorized is thrown when the request does not come from Comptroller\n * @custom:access Only Comptroller\n */\n function healBorrow(address payer, address borrower, uint256 repayAmount) external override nonReentrant {\n if (repayAmount != 0) {\n comptroller.preRepayHook(address(this), borrower);\n }\n\n if (msg.sender != address(comptroller)) {\n revert HealBorrowUnauthorized();\n }\n\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n uint256 totalBorrowsNew = totalBorrows;\n\n uint256 actualRepayAmount;\n if (repayAmount != 0) {\n // _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n // We violate checks-effects-interactions here to account for tokens that take transfer fees\n actualRepayAmount = _doTransferIn(payer, repayAmount);\n totalBorrowsNew = totalBorrowsNew - actualRepayAmount;\n emit RepayBorrow(\n payer,\n borrower,\n actualRepayAmount,\n accountBorrowsPrev - actualRepayAmount,\n totalBorrowsNew\n );\n }\n\n // The transaction will fail if trying to repay too much\n uint256 badDebtDelta = accountBorrowsPrev - actualRepayAmount;\n if (badDebtDelta != 0) {\n uint256 badDebtOld = badDebt;\n uint256 badDebtNew = badDebtOld + badDebtDelta;\n totalBorrowsNew = totalBorrowsNew - badDebtDelta;\n badDebt = badDebtNew;\n\n // We treat healing as \"repayment\", where vToken is the payer\n emit RepayBorrow(address(this), borrower, badDebtDelta, 0, totalBorrowsNew);\n emit BadDebtIncreased(borrower, badDebtDelta, badDebtOld, badDebtNew);\n }\n\n accountBorrows[borrower].principal = 0;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n emit HealBorrow(payer, borrower, repayAmount);\n }\n\n /**\n * @notice The extended version of liquidations, callable only by Comptroller. May skip\n * the close factor check. The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n * @custom:error ForceLiquidateBorrowUnauthorized is thrown when the request does not come from Comptroller\n * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n * @custom:access Only Comptroller\n */\n function forceLiquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) external override {\n if (msg.sender != address(comptroller)) {\n revert ForceLiquidateBorrowUnauthorized();\n }\n _liquidateBorrow(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Will fail unless called by another vToken during the process of liquidation.\n * It's absolutely critical to use msg.sender as the borrowed vToken and not a parameter.\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of vTokens to seize\n * @custom:event Emits Transfer, ReservesAdded events\n * @custom:error LiquidateSeizeLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:access Not restricted\n */\n function seize(address liquidator, address borrower, uint256 seizeTokens) external override nonReentrant {\n _seize(msg.sender, liquidator, borrower, seizeTokens);\n }\n\n /**\n * @notice Updates bad debt\n * @dev Called only when bad debt is recovered from auction\n * @param recoveredAmount_ The amount of bad debt recovered\n * @custom:event Emits BadDebtRecovered event\n * @custom:access Only Shortfall contract\n */\n function badDebtRecovered(uint256 recoveredAmount_) external {\n require(msg.sender == shortfall, \"only shortfall contract can update bad debt\");\n require(recoveredAmount_ <= badDebt, \"more than bad debt recovered from auction\");\n\n uint256 badDebtOld = badDebt;\n uint256 badDebtNew = badDebtOld - recoveredAmount_;\n badDebt = badDebtNew;\n\n emit BadDebtRecovered(badDebtOld, badDebtNew);\n }\n\n /**\n * @notice Sets protocol share reserve contract address\n * @param protocolShareReserve_ The address of the protocol share reserve contract\n * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n * @custom:access Only Governance\n */\n function setProtocolShareReserve(address payable protocolShareReserve_) external onlyOwner {\n _setProtocolShareReserve(protocolShareReserve_);\n }\n\n /**\n * @notice Sets shortfall contract address\n * @param shortfall_ The address of the shortfall contract\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n * @custom:access Only Governance\n */\n function setShortfallContract(address shortfall_) external onlyOwner {\n _setShortfallContract(shortfall_);\n }\n\n /**\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\n * @param token The address of the ERC-20 token to sweep\n * @custom:access Only Governance\n */\n function sweepToken(IERC20Upgradeable token) external override {\n require(msg.sender == owner(), \"VToken::sweepToken: only admin can sweep tokens\");\n require(address(token) != underlying, \"VToken::sweepToken: can not sweep underlying token\");\n uint256 balance = token.balanceOf(address(this));\n token.safeTransfer(owner(), balance);\n\n emit SweepToken(address(token));\n }\n\n /**\n * @notice Get the current allowance from `owner` for `spender`\n * @param owner The address of the account which owns the tokens to be spent\n * @param spender The address of the account which may transfer tokens\n * @return amount The number of tokens allowed to be spent (type(uint256).max means infinite)\n */\n function allowance(address owner, address spender) external view override returns (uint256) {\n return transferAllowances[owner][spender];\n }\n\n /**\n * @notice Get the token balance of the `owner`\n * @param owner The address of the account to query\n * @return amount The number of tokens owned by `owner`\n */\n function balanceOf(address owner) external view override returns (uint256) {\n return accountTokens[owner];\n }\n\n /**\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\n * @param account Address of the account to snapshot\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return vTokenBalance User's balance of vTokens\n * @return borrowBalance Amount owed in terms of underlying\n * @return exchangeRate Stored exchange rate\n */\n function getAccountSnapshot(\n address account\n )\n external\n view\n override\n returns (uint256 error, uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRate)\n {\n return (NO_ERROR, accountTokens[account], _borrowBalanceStored(account), _exchangeRateStored());\n }\n\n /**\n * @notice Get cash balance of this vToken in the underlying asset\n * @return cash The quantity of underlying asset owned by this contract\n */\n function getCash() external view override returns (uint256) {\n return _getCashPrior();\n }\n\n /**\n * @notice Returns the current per-block borrow interest rate for this vToken\n * @return rate The borrow interest rate per block, scaled by 1e18\n */\n function borrowRatePerBlock() external view override returns (uint256) {\n return interestRateModel.getBorrowRate(_getCashPrior(), totalBorrows, totalReserves, badDebt);\n }\n\n /**\n * @notice Returns the current per-block supply interest rate for this v\n * @return rate The supply interest rate per block, scaled by 1e18\n */\n function supplyRatePerBlock() external view override returns (uint256) {\n return\n interestRateModel.getSupplyRate(\n _getCashPrior(),\n totalBorrows,\n totalReserves,\n reserveFactorMantissa,\n badDebt\n );\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return borrowBalance The calculated balance\n */\n function borrowBalanceStored(address account) external view override returns (uint256) {\n return _borrowBalanceStored(account);\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the VToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() external view override returns (uint256) {\n return _exchangeRateStored();\n }\n\n /**\n * @notice Accrue interest then return the up-to-date exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function exchangeRateCurrent() public override nonReentrant returns (uint256) {\n accrueInterest();\n return _exchangeRateStored();\n }\n\n /**\n * @notice Applies accrued interest to total borrows and reserves\n * @dev This calculates interest accrued from the last checkpointed block\n * up to the current block and writes new checkpoint to storage.\n * @return Always NO_ERROR\n * @custom:event Emits AccrueInterest event on success\n * @custom:access Not restricted\n */\n function accrueInterest() public virtual override returns (uint256) {\n /* Remember the initial block number */\n uint256 currentBlockNumber = _getBlockNumber();\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\n\n /* Short-circuit accumulating 0 interest */\n if (accrualBlockNumberPrior == currentBlockNumber) {\n return NO_ERROR;\n }\n\n /* Read the previous values out of storage */\n uint256 cashPrior = _getCashPrior();\n uint256 borrowsPrior = totalBorrows;\n uint256 reservesPrior = totalReserves;\n uint256 borrowIndexPrior = borrowIndex;\n\n /* Calculate the current borrow interest rate */\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior, badDebt);\n require(borrowRateMantissa <= MAX_BORROW_RATE_MANTISSA, \"borrow rate is absurdly high\");\n\n /* Calculate the number of blocks elapsed since the last accrual */\n uint256 blockDelta = currentBlockNumber - accrualBlockNumberPrior;\n\n /*\n * Calculate the interest accumulated into borrows and reserves and the new index:\n * simpleInterestFactor = borrowRate * blockDelta\n * interestAccumulated = simpleInterestFactor * totalBorrows\n * totalBorrowsNew = interestAccumulated + totalBorrows\n * totalReservesNew = interestAccumulated * reserveFactor + totalReserves\n * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex\n */\n\n Exp memory simpleInterestFactor = mul_(Exp({ mantissa: borrowRateMantissa }), blockDelta);\n uint256 interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior);\n uint256 totalBorrowsNew = interestAccumulated + borrowsPrior;\n uint256 totalReservesNew = mul_ScalarTruncateAddUInt(\n Exp({ mantissa: reserveFactorMantissa }),\n interestAccumulated,\n reservesPrior\n );\n uint256 borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the previously calculated values into storage */\n accrualBlockNumber = currentBlockNumber;\n borrowIndex = borrowIndexNew;\n totalBorrows = totalBorrowsNew;\n totalReserves = totalReservesNew;\n\n /* We emit an AccrueInterest event */\n emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);\n\n return NO_ERROR;\n }\n\n /**\n * @notice User supplies assets into the market and receives vTokens in exchange\n * @dev Assumes interest has already been accrued up to the current block\n * @param payer The address of the account which is sending the assets for supply\n * @param minter The address of the account which is supplying the assets\n * @param mintAmount The amount of the underlying asset to supply\n */\n function _mintFresh(address payer, address minter, uint256 mintAmount) internal {\n /* Fail if mint not allowed */\n comptroller.preMintHook(address(this), minter, mintAmount);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert MintFreshnessCheck();\n }\n\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call `_doTransferIn` for the minter and the mintAmount.\n * `_doTransferIn` reverts if anything goes wrong, since we can't be sure if\n * side-effects occurred. The function returns the amount actually transferred,\n * in case of a fee. On success, the vToken holds an additional `actualMintAmount`\n * of cash.\n */\n uint256 actualMintAmount = _doTransferIn(payer, mintAmount);\n\n /*\n * We get the current exchange rate and calculate the number of vTokens to be minted:\n * mintTokens = actualMintAmount / exchangeRate\n */\n\n uint256 mintTokens = div_(actualMintAmount, exchangeRate);\n\n /*\n * We calculate the new total supply of vTokens and minter token balance, checking for overflow:\n * totalSupplyNew = totalSupply + mintTokens\n * accountTokensNew = accountTokens[minter] + mintTokens\n * And write them into storage\n */\n totalSupply = totalSupply + mintTokens;\n uint256 balanceAfter = accountTokens[minter] + mintTokens;\n accountTokens[minter] = balanceAfter;\n\n /* We emit a Mint event, and a Transfer event */\n emit Mint(minter, actualMintAmount, mintTokens, balanceAfter);\n emit Transfer(address(0), minter, mintTokens);\n }\n\n /**\n * @notice User redeems vTokens in exchange for the underlying asset\n * @dev Assumes interest has already been accrued up to the current block\n * @param redeemer The address of the account which is redeeming the tokens\n * @param redeemTokensIn The number of vTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n * @param redeemAmountIn The number of underlying tokens to receive from redeeming vTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n */\n function _redeemFresh(address redeemer, uint256 redeemTokensIn, uint256 redeemAmountIn) internal {\n require(redeemTokensIn == 0 || redeemAmountIn == 0, \"one of redeemTokensIn or redeemAmountIn must be zero\");\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert RedeemFreshnessCheck();\n }\n\n /* exchangeRate = invoke Exchange Rate Stored() */\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n uint256 redeemTokens;\n uint256 redeemAmount;\n\n /* If redeemTokensIn > 0: */\n if (redeemTokensIn > 0) {\n /*\n * We calculate the exchange rate and the amount of underlying to be redeemed:\n * redeemTokens = redeemTokensIn\n */\n redeemTokens = redeemTokensIn;\n } else {\n /*\n * We get the current exchange rate and calculate the amount to be redeemed:\n * redeemTokens = redeemAmountIn / exchangeRate\n */\n redeemTokens = div_(redeemAmountIn, exchangeRate);\n\n uint256 _redeemAmount = mul_(redeemTokens, exchangeRate);\n if (_redeemAmount != 0 && _redeemAmount != redeemAmountIn) redeemTokens++; // round up\n }\n\n // redeemAmount = exchangeRate * redeemTokens\n redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokens);\n\n // Revert if amount is zero\n if (redeemAmount == 0) {\n revert(\"redeemAmount is zero\");\n }\n\n /* Fail if redeem not allowed */\n comptroller.preRedeemHook(address(this), redeemer, redeemTokens);\n\n /* Fail gracefully if protocol has insufficient cash */\n if (_getCashPrior() - totalReserves < redeemAmount) {\n revert RedeemTransferOutNotPossible();\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We write the previously calculated values into storage.\n * Note: Avoid token reentrancy attacks by writing reduced supply before external transfer.\n */\n totalSupply = totalSupply - redeemTokens;\n uint256 balanceAfter = accountTokens[redeemer] - redeemTokens;\n accountTokens[redeemer] = balanceAfter;\n\n /*\n * We invoke _doTransferOut for the redeemer and the redeemAmount.\n * On success, the vToken has redeemAmount less of cash.\n * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n _doTransferOut(redeemer, redeemAmount);\n\n /* We emit a Transfer event, and a Redeem event */\n emit Transfer(redeemer, address(this), redeemTokens);\n emit Redeem(redeemer, redeemAmount, redeemTokens, balanceAfter);\n }\n\n /**\n * @notice Users borrow assets from the protocol to their own address\n * @param borrower User who borrows the assets\n * @param borrowAmount The amount of the underlying asset to borrow\n */\n function _borrowFresh(address borrower, uint256 borrowAmount) internal {\n /* Fail if borrow not allowed */\n comptroller.preBorrowHook(address(this), borrower, borrowAmount);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert BorrowFreshnessCheck();\n }\n\n /* Fail gracefully if protocol has insufficient underlying cash */\n if (_getCashPrior() - totalReserves < borrowAmount) {\n revert BorrowCashNotAvailable();\n }\n\n /*\n * We calculate the new borrower and total borrow balances, failing on overflow:\n * accountBorrowNew = accountBorrow + borrowAmount\n * totalBorrowsNew = totalBorrows + borrowAmount\n */\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n uint256 accountBorrowsNew = accountBorrowsPrev + borrowAmount;\n uint256 totalBorrowsNew = totalBorrows + borrowAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We write the previously calculated values into storage.\n * Note: Avoid token reentrancy attacks by writing increased borrow before external transfer.\n `*/\n accountBorrows[borrower].principal = accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n /*\n * We invoke _doTransferOut for the borrower and the borrowAmount.\n * On success, the vToken borrowAmount less of cash.\n * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n _doTransferOut(borrower, borrowAmount);\n\n /* We emit a Borrow event */\n emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);\n }\n\n /**\n * @notice Borrows are repaid by another user (possibly the borrower).\n * @param payer the account paying off the borrow\n * @param borrower the account with the debt being payed off\n * @param repayAmount the amount of underlying tokens being returned, or type(uint256).max for the full outstanding amount\n * @return (uint) the actual repayment amount.\n */\n function _repayBorrowFresh(address payer, address borrower, uint256 repayAmount) internal returns (uint256) {\n /* Fail if repayBorrow not allowed */\n comptroller.preRepayHook(address(this), borrower);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert RepayBorrowFreshnessCheck();\n }\n\n /* We fetch the amount the borrower owes, with accumulated interest */\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n\n uint256 repayAmountFinal = repayAmount >= accountBorrowsPrev ? accountBorrowsPrev : repayAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call _doTransferIn for the payer and the repayAmount\n * On success, the vToken holds an additional repayAmount of cash.\n * _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n * it returns the amount actually transferred, in case of a fee.\n */\n uint256 actualRepayAmount = _doTransferIn(payer, repayAmountFinal);\n\n /*\n * We calculate the new borrower and total borrow balances, failing on underflow:\n * accountBorrowsNew = accountBorrows - actualRepayAmount\n * totalBorrowsNew = totalBorrows - actualRepayAmount\n */\n uint256 accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;\n uint256 totalBorrowsNew = totalBorrows - actualRepayAmount;\n\n /* We write the previously calculated values into storage */\n accountBorrows[borrower].principal = accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n /* We emit a RepayBorrow event */\n emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew);\n\n return actualRepayAmount;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n */\n function _liquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) internal nonReentrant {\n accrueInterest();\n\n uint256 error = vTokenCollateral.accrueInterest();\n if (error != NO_ERROR) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed\n revert LiquidateAccrueCollateralInterestFailed(error);\n }\n\n // _liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\n _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n /**\n * @notice The liquidator liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n */\n function _liquidateBorrowFresh(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) internal {\n /* Fail if liquidate not allowed */\n comptroller.preLiquidateHook(\n address(this),\n address(vTokenCollateral),\n borrower,\n repayAmount,\n skipLiquidityCheck\n );\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert LiquidateFreshnessCheck();\n }\n\n /* Verify vTokenCollateral market's block number equals current block number */\n if (vTokenCollateral.accrualBlockNumber() != _getBlockNumber()) {\n revert LiquidateCollateralFreshnessCheck();\n }\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n revert LiquidateLiquidatorIsBorrower();\n }\n\n /* Fail if repayAmount = 0 */\n if (repayAmount == 0) {\n revert LiquidateCloseAmountIsZero();\n }\n\n /* Fail if repayAmount = type(uint256).max */\n if (repayAmount == type(uint256).max) {\n revert LiquidateCloseAmountIsUintMax();\n }\n\n /* Fail if repayBorrow fails */\n uint256 actualRepayAmount = _repayBorrowFresh(liquidator, borrower, repayAmount);\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We calculate the number of collateral tokens that will be seized */\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller.liquidateCalculateSeizeTokens(\n address(this),\n address(vTokenCollateral),\n actualRepayAmount\n );\n require(amountSeizeError == NO_ERROR, \"LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED\");\n\n /* Revert if borrower collateral token balance < seizeTokens */\n require(vTokenCollateral.balanceOf(borrower) >= seizeTokens, \"LIQUIDATE_SEIZE_TOO_MUCH\");\n\n // If this is also the collateral, call _seize internally to avoid re-entrancy, otherwise make an external call\n if (address(vTokenCollateral) == address(this)) {\n _seize(address(this), liquidator, borrower, seizeTokens);\n } else {\n vTokenCollateral.seize(liquidator, borrower, seizeTokens);\n }\n\n /* We emit a LiquidateBorrow event */\n emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(vTokenCollateral), seizeTokens);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another VToken.\n * It's absolutely critical to use msg.sender as the seizer vToken and not a parameter.\n * @param seizerContract The contract seizing the collateral (either borrowed vToken or Comptroller)\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of vTokens to seize\n */\n function _seize(address seizerContract, address liquidator, address borrower, uint256 seizeTokens) internal {\n /* Fail if seize not allowed */\n comptroller.preSeizeHook(address(this), seizerContract, liquidator, borrower);\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n revert LiquidateSeizeLiquidatorIsBorrower();\n }\n\n /*\n * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\n * borrowerTokensNew = accountTokens[borrower] - seizeTokens\n * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\n */\n uint256 liquidationIncentiveMantissa = ComptrollerViewInterface(address(comptroller))\n .liquidationIncentiveMantissa();\n uint256 numerator = mul_(seizeTokens, Exp({ mantissa: protocolSeizeShareMantissa }));\n uint256 protocolSeizeTokens = div_(numerator, Exp({ mantissa: liquidationIncentiveMantissa }));\n uint256 liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n uint256 protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens);\n uint256 totalReservesNew = totalReserves + protocolSeizeAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the calculated values into storage */\n totalReserves = totalReservesNew;\n totalSupply = totalSupply - protocolSeizeTokens;\n accountTokens[borrower] = accountTokens[borrower] - seizeTokens;\n accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens;\n\n /* Emit a Transfer event */\n emit Transfer(borrower, liquidator, liquidatorSeizeTokens);\n emit Transfer(borrower, address(this), protocolSeizeTokens);\n emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew);\n }\n\n function _setComptroller(ComptrollerInterface newComptroller) internal {\n ComptrollerInterface oldComptroller = comptroller;\n // Ensure invoke comptroller.isComptroller() returns true\n require(newComptroller.isComptroller(), \"marker method returned false\");\n\n // Set market's comptroller to newComptroller\n comptroller = newComptroller;\n\n // Emit NewComptroller(oldComptroller, newComptroller)\n emit NewComptroller(oldComptroller, newComptroller);\n }\n\n /**\n * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)\n * @dev Admin function to set a new reserve factor\n * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n */\n function _setReserveFactorFresh(uint256 newReserveFactorMantissa) internal {\n // Verify market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert SetReserveFactorFreshCheck();\n }\n\n // Check newReserveFactor ≤ maxReserveFactor\n if (newReserveFactorMantissa > MAX_RESERVE_FACTOR_MANTISSA) {\n revert SetReserveFactorBoundsCheck();\n }\n\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\n reserveFactorMantissa = newReserveFactorMantissa;\n\n emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);\n }\n\n /**\n * @notice Add reserves by transferring from caller\n * @dev Requires fresh interest accrual\n * @param addAmount Amount of addition to reserves\n * @return actualAddAmount The actual amount added, excluding the potential token fees\n */\n function _addReservesFresh(uint256 addAmount) internal returns (uint256) {\n // totalReserves + actualAddAmount\n uint256 totalReservesNew;\n uint256 actualAddAmount;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert AddReservesFactorFreshCheck(actualAddAmount);\n }\n\n actualAddAmount = _doTransferIn(msg.sender, addAmount);\n totalReservesNew = totalReserves + actualAddAmount;\n totalReserves = totalReservesNew;\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\n\n return actualAddAmount;\n }\n\n /**\n * @notice Reduces reserves by transferring to the protocol reserve contract\n * @dev Requires fresh interest accrual\n * @param reduceAmount Amount of reduction to reserves\n */\n function _reduceReservesFresh(uint256 reduceAmount) internal {\n // totalReserves - reduceAmount\n uint256 totalReservesNew;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert ReduceReservesFreshCheck();\n }\n\n // Fail gracefully if protocol has insufficient underlying cash\n if (_getCashPrior() < reduceAmount) {\n revert ReduceReservesCashNotAvailable();\n }\n\n // Check reduceAmount ≤ reserves[n] (totalReserves)\n if (reduceAmount > totalReserves) {\n revert ReduceReservesCashValidation();\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n totalReservesNew = totalReserves - reduceAmount;\n\n // Store reserves[n+1] = reserves[n] - reduceAmount\n totalReserves = totalReservesNew;\n\n // _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n // Transferring an underlying asset to the protocolShareReserve contract to channel the funds for different use.\n _doTransferOut(protocolShareReserve, reduceAmount);\n\n // Update the pool asset's state in the protocol share reserve for the above transfer.\n IProtocolShareReserve(protocolShareReserve).updateAssetsState(address(comptroller), underlying);\n\n emit ReservesReduced(protocolShareReserve, reduceAmount, totalReservesNew);\n }\n\n /**\n * @notice updates the interest rate model (*requires fresh interest accrual)\n * @dev Admin function to update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n */\n function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal {\n // Used to store old model for use in the event that is emitted on success\n InterestRateModel oldInterestRateModel;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert SetInterestRateModelFreshCheck();\n }\n\n // Track the market's current interest rate model\n oldInterestRateModel = interestRateModel;\n\n // Ensure invoke newInterestRateModel.isInterestRateModel() returns true\n require(newInterestRateModel.isInterestRateModel(), \"marker method returned false\");\n\n // Set the interest rate model to newInterestRateModel\n interestRateModel = newInterestRateModel;\n\n // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)\n emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);\n }\n\n /*** Safe Token ***/\n\n /**\n * @dev Similar to ERC-20 transfer, but handles tokens that have transfer fees.\n * This function returns the actual amount received,\n * which may be less than `amount` if there is a fee attached to the transfer.\n * @param from Sender of the underlying tokens\n * @param amount Amount of underlying to transfer\n * @return Actual amount received\n */\n function _doTransferIn(address from, uint256 amount) internal virtual returns (uint256) {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n uint256 balanceBefore = token.balanceOf(address(this));\n token.safeTransferFrom(from, address(this), amount);\n uint256 balanceAfter = token.balanceOf(address(this));\n // Return the amount that was *actually* transferred\n return balanceAfter - balanceBefore;\n }\n\n /**\n * @dev Just a regular ERC-20 transfer, reverts on failure\n * @param to Receiver of the underlying tokens\n * @param amount Amount of underlying to transfer\n */\n function _doTransferOut(address to, uint256 amount) internal virtual {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n token.safeTransfer(to, amount);\n }\n\n /**\n * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`\n * @dev Called by both `transfer` and `transferFrom` internally\n * @param spender The address of the account performing the transfer\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param tokens The number of tokens to transfer\n */\n function _transferTokens(address spender, address src, address dst, uint256 tokens) internal {\n /* Fail if transfer not allowed */\n comptroller.preTransferHook(address(this), src, dst, tokens);\n\n /* Do not allow self-transfers */\n if (src == dst) {\n revert TransferNotAllowed();\n }\n\n /* Get the allowance, infinite for the account owner */\n uint256 startingAllowance;\n if (spender == src) {\n startingAllowance = type(uint256).max;\n } else {\n startingAllowance = transferAllowances[src][spender];\n }\n\n /* Do the calculations, checking for {under,over}flow */\n uint256 allowanceNew = startingAllowance - tokens;\n uint256 srcTokensNew = accountTokens[src] - tokens;\n uint256 dstTokensNew = accountTokens[dst] + tokens;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n\n accountTokens[src] = srcTokensNew;\n accountTokens[dst] = dstTokensNew;\n\n /* Eat some of the allowance (if necessary) */\n if (startingAllowance != type(uint256).max) {\n transferAllowances[src][spender] = allowanceNew;\n }\n\n /* We emit a Transfer event */\n emit Transfer(src, dst, tokens);\n }\n\n /**\n * @notice Initialize the money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param accessControlManager_ AccessControlManager contract address\n * @param riskManagement Addresses of risk & income related contracts\n * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n */\n function _initialize(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n require(accrualBlockNumber == 0 && borrowIndex == 0, \"market may only be initialized once\");\n\n // Set initial exchange rate\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\n require(initialExchangeRateMantissa > 0, \"initial exchange rate must be greater than zero.\");\n\n _setComptroller(comptroller_);\n\n // Initialize block number and borrow index (block number mocks depend on comptroller being set)\n accrualBlockNumber = _getBlockNumber();\n borrowIndex = MANTISSA_ONE;\n\n // Set the interest rate model (depends on block number / borrow index)\n _setInterestRateModelFresh(interestRateModel_);\n\n _setReserveFactorFresh(reserveFactorMantissa_);\n\n name = name_;\n symbol = symbol_;\n decimals = decimals_;\n _setShortfallContract(riskManagement.shortfall);\n _setProtocolShareReserve(riskManagement.protocolShareReserve);\n protocolSeizeShareMantissa = DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA;\n\n // Set underlying and sanity check it\n underlying = underlying_;\n IERC20Upgradeable(underlying).totalSupply();\n\n // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\n _notEntered = true;\n _transferOwnership(admin_);\n }\n\n function _setShortfallContract(address shortfall_) internal {\n ensureNonzeroAddress(shortfall_);\n address oldShortfall = shortfall;\n shortfall = shortfall_;\n emit NewShortfallContract(oldShortfall, shortfall_);\n }\n\n function _setProtocolShareReserve(address payable protocolShareReserve_) internal {\n ensureNonzeroAddress(protocolShareReserve_);\n address oldProtocolShareReserve = address(protocolShareReserve);\n protocolShareReserve = protocolShareReserve_;\n emit NewProtocolShareReserve(oldProtocolShareReserve, address(protocolShareReserve_));\n }\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying tokens owned by this contract\n */\n function _getCashPrior() internal view virtual returns (uint256) {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n return token.balanceOf(address(this));\n }\n\n /**\n * @dev Function to simply retrieve block number\n * This exists mainly for inheriting test contracts to stub this result.\n * @return Current block number\n */\n function _getBlockNumber() internal view virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return borrowBalance the calculated balance\n */\n function _borrowBalanceStored(address account) internal view returns (uint256) {\n /* Get borrowBalance and borrowIndex */\n BorrowSnapshot memory borrowSnapshot = accountBorrows[account];\n\n /* If borrowBalance = 0 then borrowIndex is likely also 0.\n * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.\n */\n if (borrowSnapshot.principal == 0) {\n return 0;\n }\n\n /* Calculate new borrow balance using the interest index:\n * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex\n */\n uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex;\n\n return principalTimesIndex / borrowSnapshot.interestIndex;\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the VToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function _exchangeRateStored() internal view virtual returns (uint256) {\n uint256 _totalSupply = totalSupply;\n if (_totalSupply == 0) {\n /*\n * If there are no tokens minted:\n * exchangeRate = initialExchangeRate\n */\n return initialExchangeRateMantissa;\n }\n /*\n * Otherwise:\n * exchangeRate = (totalCash + totalBorrows + badDebt - totalReserves) / totalSupply\n */\n uint256 totalCash = _getCashPrior();\n uint256 cashPlusBorrowsMinusReserves = totalCash + totalBorrows + badDebt - totalReserves;\n uint256 exchangeRate = (cashPlusBorrowsMinusReserves * EXP_SCALE) / _totalSupply;\n\n return exchangeRate;\n }\n}\n" + }, + "contracts/VTokenInterfaces.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\n\n/**\n * @title VTokenStorage\n * @author Venus\n * @notice Storage layout used by the `VToken` contract\n */\n// solhint-disable-next-line max-states-count\ncontract VTokenStorage {\n /**\n * @notice Container for borrow balance information\n * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action\n * @member interestIndex Global borrowIndex as of the most recent balance-changing action\n */\n struct BorrowSnapshot {\n uint256 principal;\n uint256 interestIndex;\n }\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n bool internal _notEntered;\n\n /**\n * @notice Underlying asset for this VToken\n */\n address public underlying;\n\n /**\n * @notice EIP-20 token name for this token\n */\n string public name;\n\n /**\n * @notice EIP-20 token symbol for this token\n */\n string public symbol;\n\n /**\n * @notice EIP-20 token decimals for this token\n */\n uint8 public decimals;\n\n /**\n * @notice Protocol share Reserve contract address\n */\n address payable public protocolShareReserve;\n\n // Maximum borrow rate that can ever be applied (.0005% / block)\n uint256 internal constant MAX_BORROW_RATE_MANTISSA = 0.0005e16;\n\n // Maximum fraction of interest that can be set aside for reserves\n uint256 internal constant MAX_RESERVE_FACTOR_MANTISSA = 1e18;\n\n /**\n * @notice Contract which oversees inter-vToken operations\n */\n ComptrollerInterface public comptroller;\n\n /**\n * @notice Model which tells what the current interest rate should be\n */\n InterestRateModel public interestRateModel;\n\n // Initial exchange rate used when minting the first VTokens (used when totalSupply = 0)\n uint256 internal initialExchangeRateMantissa;\n\n /**\n * @notice Fraction of interest currently set aside for reserves\n */\n uint256 public reserveFactorMantissa;\n\n /**\n * @notice Block number that interest was last accrued at\n */\n uint256 public accrualBlockNumber;\n\n /**\n * @notice Accumulator of the total earned interest rate since the opening of the market\n */\n uint256 public borrowIndex;\n\n /**\n * @notice Total amount of outstanding borrows of the underlying in this market\n */\n uint256 public totalBorrows;\n\n /**\n * @notice Total amount of reserves of the underlying held in this market\n */\n uint256 public totalReserves;\n\n /**\n * @notice Total number of tokens in circulation\n */\n uint256 public totalSupply;\n\n /**\n * @notice Total bad debt of the market\n */\n uint256 public badDebt;\n\n // Official record of token balances for each account\n mapping(address => uint256) internal accountTokens;\n\n // Approved token transfer amounts on behalf of others\n mapping(address => mapping(address => uint256)) internal transferAllowances;\n\n // Mapping of account addresses to outstanding borrow balances\n mapping(address => BorrowSnapshot) internal accountBorrows;\n\n /**\n * @notice Share of seized collateral that is added to reserves\n */\n uint256 public protocolSeizeShareMantissa;\n\n /**\n * @notice Storage of Shortfall contract address\n */\n address public shortfall;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n\n/**\n * @title VTokenInterface\n * @author Venus\n * @notice Interface implemented by the `VToken` contract\n */\nabstract contract VTokenInterface is VTokenStorage {\n struct RiskManagementInit {\n address shortfall;\n address payable protocolShareReserve;\n }\n\n /*** Market Events ***/\n\n /**\n * @notice Event emitted when interest is accrued\n */\n event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when tokens are minted\n */\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens, uint256 accountBalance);\n\n /**\n * @notice Event emitted when tokens are redeemed\n */\n event Redeem(address indexed redeemer, uint256 redeemAmount, uint256 redeemTokens, uint256 accountBalance);\n\n /**\n * @notice Event emitted when underlying is borrowed\n */\n event Borrow(address indexed borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when a borrow is repaid\n */\n event RepayBorrow(\n address indexed payer,\n address indexed borrower,\n uint256 repayAmount,\n uint256 accountBorrows,\n uint256 totalBorrows\n );\n\n /**\n * @notice Event emitted when bad debt is accumulated on a market\n * @param borrower borrower to \"forgive\"\n * @param badDebtDelta amount of new bad debt recorded\n * @param badDebtOld previous bad debt value\n * @param badDebtNew new bad debt value\n */\n event BadDebtIncreased(address indexed borrower, uint256 badDebtDelta, uint256 badDebtOld, uint256 badDebtNew);\n\n /**\n * @notice Event emitted when bad debt is recovered via an auction\n * @param badDebtOld previous bad debt value\n * @param badDebtNew new bad debt value\n */\n event BadDebtRecovered(uint256 badDebtOld, uint256 badDebtNew);\n\n /**\n * @notice Event emitted when a borrow is liquidated\n */\n event LiquidateBorrow(\n address indexed liquidator,\n address indexed borrower,\n uint256 repayAmount,\n address indexed vTokenCollateral,\n uint256 seizeTokens\n );\n\n /*** Admin Events ***/\n\n /**\n * @notice Event emitted when comptroller is changed\n */\n event NewComptroller(ComptrollerInterface indexed oldComptroller, ComptrollerInterface indexed newComptroller);\n\n /**\n * @notice Event emitted when shortfall contract address is changed\n */\n event NewShortfallContract(address indexed oldShortfall, address indexed newShortfall);\n\n /**\n * @notice Event emitted when protocol share reserve contract address is changed\n */\n event NewProtocolShareReserve(address indexed oldProtocolShareReserve, address indexed newProtocolShareReserve);\n\n /**\n * @notice Event emitted when interestRateModel is changed\n */\n event NewMarketInterestRateModel(\n InterestRateModel indexed oldInterestRateModel,\n InterestRateModel indexed newInterestRateModel\n );\n\n /**\n * @notice Event emitted when protocol seize share is changed\n */\n event NewProtocolSeizeShare(uint256 oldProtocolSeizeShareMantissa, uint256 newProtocolSeizeShareMantissa);\n\n /**\n * @notice Event emitted when the reserve factor is changed\n */\n event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa);\n\n /**\n * @notice Event emitted when the reserves are added\n */\n event ReservesAdded(address indexed benefactor, uint256 addAmount, uint256 newTotalReserves);\n\n /**\n * @notice Event emitted when the reserves are reduced\n */\n event ReservesReduced(address indexed admin, uint256 reduceAmount, uint256 newTotalReserves);\n\n /**\n * @notice EIP20 Transfer event\n */\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n /**\n * @notice EIP20 Approval event\n */\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /**\n * @notice Event emitted when healing the borrow\n */\n event HealBorrow(address indexed payer, address indexed borrower, uint256 repayAmount);\n\n /**\n * @notice Event emitted when tokens are swept\n */\n event SweepToken(address indexed token);\n\n /*** User Interface ***/\n\n function mint(uint256 mintAmount) external virtual returns (uint256);\n\n function mintBehalf(address minter, uint256 mintAllowed) external virtual returns (uint256);\n\n function redeem(uint256 redeemTokens) external virtual returns (uint256);\n\n function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256);\n\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\n\n function repayBorrow(uint256 repayAmount) external virtual returns (uint256);\n\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256);\n\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral\n ) external virtual returns (uint256);\n\n function healBorrow(address payer, address borrower, uint256 repayAmount) external virtual;\n\n function forceLiquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipCloseFactorCheck\n ) external virtual;\n\n function seize(address liquidator, address borrower, uint256 seizeTokens) external virtual;\n\n function transfer(address dst, uint256 amount) external virtual returns (bool);\n\n function transferFrom(address src, address dst, uint256 amount) external virtual returns (bool);\n\n function accrueInterest() external virtual returns (uint256);\n\n function sweepToken(IERC20Upgradeable token) external virtual;\n\n /*** Admin Functions ***/\n\n function setReserveFactor(uint256 newReserveFactorMantissa) external virtual;\n\n function reduceReserves(uint256 reduceAmount) external virtual;\n\n function exchangeRateCurrent() external virtual returns (uint256);\n\n function borrowBalanceCurrent(address account) external virtual returns (uint256);\n\n function setInterestRateModel(InterestRateModel newInterestRateModel) external virtual;\n\n function addReserves(uint256 addAmount) external virtual;\n\n function totalBorrowsCurrent() external virtual returns (uint256);\n\n function balanceOfUnderlying(address owner) external virtual returns (uint256);\n\n function approve(address spender, uint256 amount) external virtual returns (bool);\n\n function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool);\n\n function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool);\n\n function allowance(address owner, address spender) external view virtual returns (uint256);\n\n function balanceOf(address owner) external view virtual returns (uint256);\n\n function getAccountSnapshot(address account) external view virtual returns (uint256, uint256, uint256, uint256);\n\n function borrowRatePerBlock() external view virtual returns (uint256);\n\n function supplyRatePerBlock() external view virtual returns (uint256);\n\n function borrowBalanceStored(address account) external view virtual returns (uint256);\n\n function exchangeRateStored() external view virtual returns (uint256);\n\n function getCash() external view virtual returns (uint256);\n\n /**\n * @notice Indicator that this is a VToken contract (for inspection)\n * @return Always true\n */\n function isVToken() external pure virtual returns (bool) {\n return true;\n }\n}\n" + }, + "contracts/WhitePaperInterestRateModel.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { EXP_SCALE, MANTISSA_ONE } from \"./lib/constants.sol\";\n\n/**\n * @title Compound's WhitePaperInterestRateModel Contract\n * @author Compound\n * @notice The parameterized model described in section 2.4 of the original Compound Protocol whitepaper\n */\ncontract WhitePaperInterestRateModel is InterestRateModel {\n /**\n * @notice The approximate number of blocks per year that is assumed by the interest rate model\n */\n uint256 public immutable blocksPerYear;\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public immutable multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public immutable baseRatePerBlock;\n\n event NewInterestParams(uint256 baseRatePerBlock, uint256 multiplierPerBlock);\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n */\n constructor(\n uint256 blocksPerYear_,\n uint256 baseRatePerYear,\n uint256 multiplierPerYear\n ) {\n require(blocksPerYear_ != 0, \"Invalid blocks per year\");\n baseRatePerBlock = baseRatePerYear / blocksPerYear_;\n multiplierPerBlock = multiplierPerYear / blocksPerYear_;\n blocksPerYear = blocksPerYear_;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock);\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public view override returns (uint256) {\n uint256 ur = utilizationRate(cash, borrows, reserves, badDebt);\n return ((ur * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) public view override returns (uint256) {\n uint256 oneMinusReserveFactor = MANTISSA_ONE - reserveFactorMantissa;\n uint256 borrowRate = getBorrowRate(cash, borrows, reserves, badDebt);\n uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / EXP_SCALE;\n uint256 incomeToDistribute = borrows * rateToPool;\n uint256 supply = cash + borrows + badDebt - reserves;\n return incomeToDistribute / supply;\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `(borrows + badDebt) / (cash + borrows + badDebt - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @param badDebt The amount of badDebt in the market\n * @return The utilization rate as a mantissa between [0, MANTISSA_ONE]\n */\n function utilizationRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public pure returns (uint256) {\n // Utilization rate is 0 when there are no borrows and badDebt\n if ((borrows + badDebt) == 0) {\n return 0;\n }\n\n uint256 rate = ((borrows + badDebt) * EXP_SCALE) / (cash + borrows + badDebt - reserves);\n\n if (rate > EXP_SCALE) {\n rate = EXP_SCALE;\n }\n\n return rate;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200, + "details": { + "yul": true + } + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/bsctestnet/solcInputs/fe42e787f43c7b3c0c64f0274853de01.json b/deployments/bsctestnet/solcInputs/fe42e787f43c7b3c0c64f0274853de01.json new file mode 100644 index 000000000..35f1ab4d2 --- /dev/null +++ b/deployments/bsctestnet/solcInputs/fe42e787f43c7b3c0c64f0274853de01.json @@ -0,0 +1,288 @@ +{ + "language": "Solidity", + "sources": { + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n function decimals() external view returns (uint8);\n\n function description() external view returns (string memory);\n\n function version() external view returns (uint256);\n\n function getRoundData(uint80 _roundId)\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./OwnableUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides 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} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n function __Ownable2Step_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.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/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {\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 function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\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 /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized != type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n function __ReentrancyGuard_init() internal onlyInitializing {\n __ReentrancyGuard_init_unchained();\n }\n\n function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n return _status == _ENTERED;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n using AddressUpgradeable for address;\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to\n * 0 before setting it to a non-zero value.\n */\n function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n * Revert on invalid signature.\n */\n function safePermit(\n IERC20PermitUpgradeable token,\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n uint256 nonceBefore = token.nonces(owner);\n token.permit(owner, spender, value, deadline, v, r, s);\n uint256 nonceAfter = token.nonces(owner);\n require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return\n success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\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 ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\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 /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n /**\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n * address.\n *\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n * function revert if invoked through a proxy.\n */\n function proxiableUUID() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC1967.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\n *\n * _Available since v4.8.3._\n */\ninterface IERC1967 {\n /**\n * @dev Emitted when the implementation is upgraded.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Emitted when the admin account has changed.\n */\n event AdminChanged(address previousAdmin, address newAdmin);\n\n /**\n * @dev Emitted when the beacon is changed.\n */\n event BeaconUpgraded(address indexed beacon);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../Proxy.sol\";\nimport \"../ERC1967/ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.\n *\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\n * conflict with the storage layout of the implementation behind the proxy.\n *\n * _Available since v3.4._\n */\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\n /**\n * @dev Initializes the proxy with `beacon`.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\n * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity\n * constructor.\n *\n * Requirements:\n *\n * - `beacon` must be a contract with the interface {IBeacon}.\n */\n constructor(address beacon, bytes memory data) payable {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n\n /**\n * @dev Returns the current beacon address.\n */\n function _beacon() internal view virtual returns (address) {\n return _getBeacon();\n }\n\n /**\n * @dev Returns the current implementation address of the associated beacon.\n */\n function _implementation() internal view virtual override returns (address) {\n return IBeacon(_getBeacon()).implementation();\n }\n\n /**\n * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\n *\n * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\n *\n * Requirements:\n *\n * - `beacon` must be a contract.\n * - The implementation returned by `beacon` must be a contract.\n */\n function _setBeacon(address beacon, bytes memory data) internal virtual {\n _upgradeBeaconToAndCall(beacon, data, false);\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n /**\n * @dev Must return an address that can be used as a delegate call target.\n *\n * {BeaconProxy} will check that this address is a contract.\n */\n function implementation() external view returns (address);\n}\n" + }, + "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../../access/Ownable.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their\n * implementation contract, which is where they will delegate all function calls.\n *\n * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.\n */\ncontract UpgradeableBeacon is IBeacon, Ownable {\n address private _implementation;\n\n /**\n * @dev Emitted when the implementation returned by the beacon is changed.\n */\n event Upgraded(address indexed implementation);\n\n /**\n * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the\n * beacon.\n */\n constructor(address implementation_) {\n _setImplementation(implementation_);\n }\n\n /**\n * @dev Returns the current implementation address.\n */\n function implementation() public view virtual override returns (address) {\n return _implementation;\n }\n\n /**\n * @dev Upgrades the beacon to a new implementation.\n *\n * Emits an {Upgraded} event.\n *\n * Requirements:\n *\n * - msg.sender must be the owner of the contract.\n * - `newImplementation` must be a contract.\n */\n function upgradeTo(address newImplementation) public virtual onlyOwner {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Sets the implementation contract address for this beacon\n *\n * Requirements:\n *\n * - `newImplementation` must be a contract.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"UpgradeableBeacon: implementation is not a contract\");\n _implementation = newImplementation;\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/IERC1967.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n */\nabstract contract ERC1967Upgrade is IERC1967 {\n // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n /**\n * @dev Storage slot with the address of the current implementation.\n * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n /**\n * @dev Returns the current implementation address.\n */\n function _getImplementation() internal view returns (address) {\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 implementation slot.\n */\n function _setImplementation(address newImplementation) private {\n require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n }\n\n /**\n * @dev Perform implementation upgrade\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeTo(address newImplementation) internal {\n _setImplementation(newImplementation);\n emit Upgraded(newImplementation);\n }\n\n /**\n * @dev Perform implementation upgrade with additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {\n _upgradeTo(newImplementation);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(newImplementation, data);\n }\n }\n\n /**\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n *\n * Emits an {Upgraded} event.\n */\n function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {\n // Upgrades from old implementations will perform a rollback test. This test requires the new\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n // this special case will break upgrade paths from old UUPS implementation to new ones.\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n _setImplementation(newImplementation);\n } else {\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n } catch {\n revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n }\n _upgradeToAndCall(newImplementation, data, forceCall);\n }\n }\n\n /**\n * @dev Storage slot with the admin of the contract.\n * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n * validated in the constructor.\n */\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n /**\n * @dev Returns the current admin.\n */\n function _getAdmin() internal view returns (address) {\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n }\n\n /**\n * @dev Stores a new address in the EIP1967 admin slot.\n */\n function _setAdmin(address newAdmin) private {\n require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n }\n\n /**\n * @dev Changes the admin of the proxy.\n *\n * Emits an {AdminChanged} event.\n */\n function _changeAdmin(address newAdmin) internal {\n emit AdminChanged(_getAdmin(), newAdmin);\n _setAdmin(newAdmin);\n }\n\n /**\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n */\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n /**\n * @dev Returns the current beacon.\n */\n function _getBeacon() internal view returns (address) {\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n }\n\n /**\n * @dev Stores a new beacon in the EIP1967 beacon slot.\n */\n function _setBeacon(address newBeacon) private {\n require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n require(\n Address.isContract(IBeacon(newBeacon).implementation()),\n \"ERC1967: beacon implementation is not a contract\"\n );\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n }\n\n /**\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n *\n * Emits a {BeaconUpgraded} event.\n */\n function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {\n _setBeacon(newBeacon);\n emit BeaconUpgraded(newBeacon);\n if (data.length > 0 || forceCall) {\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Proxy.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n /**\n * @dev Delegates the current call to `implementation`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _delegate(address implementation) internal virtual {\n assembly {\n // Copy msg.data. We take full control of memory in this inline assembly\n // block because it will not return to Solidity code. We overwrite the\n // Solidity scratch pad at memory position 0.\n calldatacopy(0, 0, calldatasize())\n\n // Call the implementation.\n // out and outsize are 0 because we don't know the size yet.\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n // Copy the returned data.\n returndatacopy(0, 0, returndatasize())\n\n switch result\n // delegatecall returns 0 on error.\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n\n /**\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n * and {_fallback} should delegate.\n */\n function _implementation() internal view virtual returns (address);\n\n /**\n * @dev Delegates the current call to the address returned by `_implementation()`.\n *\n * This function does not return to its internal call site, it will return directly to the external caller.\n */\n function _fallback() internal virtual {\n _beforeFallback();\n _delegate(_implementation());\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n * function in the contract matches the call data.\n */\n fallback() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n * is empty.\n */\n receive() external payable virtual {\n _fallback();\n }\n\n /**\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n * call, or as part of the Solidity `fallback` or `receive` functions.\n *\n * If overridden should call `super._beforeFallback()`.\n */\n function _beforeFallback() internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n */\n function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, amount);\n _transfer(from, to, amount);\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, allowance(owner, spender) + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n address owner = _msgSender();\n uint256 currentAllowance = allowance(owner, spender);\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(owner, spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `from` must have a balance of at least `amount`.\n */\n function _transfer(address from, address to, uint256 amount) internal virtual {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, amount);\n\n uint256 fromBalance = _balances[from];\n require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[from] = fromBalance - amount;\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n // decrementing then incrementing.\n _balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n _afterTokenTransfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n unchecked {\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n _balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n // Overflow not possible: amount <= accountBalance <= totalSupply.\n _totalSupply -= amount;\n }\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(address owner, address spender, uint256 amount) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n unchecked {\n _approve(owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n *\n * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1, \"Math: mulDiv overflow\");\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/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" + }, + "@openzeppelin/contracts/utils/StorageSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._\n * _Available since v4.9 for `string`, `bytes`._\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n /// @solidity memory-safe-assembly\n assembly {\n r.slot := store.slot\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toString(int256 value) internal pure returns (string memory) {\n return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return keccak256(bytes(a)) == keccak256(bytes(b));\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title Venus Access Control Contract.\n * @dev The AccessControlledV8 contract is a wrapper around the OpenZeppelin AccessControl contract\n * It provides a standardized way to control access to methods within the Venus Smart Contract Ecosystem.\n * The contract allows the owner to set an AccessControlManager contract address.\n * It can restrict method calls based on the sender's role and the method's signature.\n */\n\nabstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {\n /// @notice Access control manager contract\n IAccessControlManagerV8 private _accessControlManager;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when access control manager contract address is changed\n event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);\n\n /// @notice Thrown when the action is prohibited by AccessControlManager\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Sets the address of AccessControlManager\n * @dev Admin function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n * @custom:event Emits NewAccessControlManager event\n * @custom:access Only Governance\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Returns the address of the access control manager contract\n */\n function accessControlManager() external view returns (IAccessControlManagerV8) {\n return _accessControlManager;\n }\n\n /**\n * @dev Internal function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n */\n function _setAccessControlManager(address accessControlManager_) internal {\n require(address(accessControlManager_) != address(0), \"invalid acess control manager address\");\n address oldAccessControlManager = address(_accessControlManager);\n _accessControlManager = IAccessControlManagerV8(accessControlManager_);\n emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);\n }\n\n /**\n * @notice Reverts if the call is not allowed by AccessControlManager\n * @param signature Method signature\n */\n function _checkAccessAllowed(string memory signature) internal view {\n bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title Venus Access Control Contract\n * @author venus\n * @dev This contract is a wrapper of OpenZeppelin AccessControl\n *\t\textending it in a way to standartize access control\n *\t\twithin Venus Smart Contract Ecosystem\n */\ncontract AccessControlManager is AccessControl, IAccessControlManagerV8 {\n /// @notice Emitted when an account is given a permission to a certain contract function\n /// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and\n /// can call any contract function with this signature\n event PermissionGranted(address account, address contractAddress, string functionSig);\n\n /// @notice Emitted when an account is revoked a permission to a certain contract function\n event PermissionRevoked(address account, address contractAddress, string functionSig);\n\n constructor() {\n // Grant the contract deployer the default admin role: it will be able\n // to grant and revoke any roles\n _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n /**\n * @notice Gives a function call permission to one single account\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * @param contractAddress address of contract for which call permissions will be granted\n * @dev if contractAddress is zero address, the account can access the specified function\n * on **any** contract managed by this ACL\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @param accountToPermit account that will be given access to the contract function\n * @custom:event Emits a {RoleGranted} and {PermissionGranted} events.\n */\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n grantRole(role, accountToPermit);\n emit PermissionGranted(accountToPermit, contractAddress, functionSig);\n }\n\n /**\n * @notice Revokes an account's permission to a particular function call\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * \t\tMay emit a {RoleRevoked} event.\n * @param contractAddress address of contract for which call permissions will be revoked\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.\n */\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n revokeRole(role, accountToRevoke);\n emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender\n * @param account for which call permissions will be checked\n * @param functionSig restricted function signature e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n *\n */\n function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));\n\n if (hasRole(role, account)) {\n return true;\n } else {\n role = keccak256(abi.encodePacked(address(0), functionSig));\n return hasRole(role, account);\n }\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.\n * @param account for which call permissions will be checked against\n * @param contractAddress address of the restricted contract\n * @param functionSig signature of the restricted function e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n */\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n return hasRole(role, account);\n }\n}\n" + }, + "@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/FeedRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface FeedRegistryInterface {\n function latestRoundDataByName(\n string memory base,\n string memory quote\n )\n external\n view\n returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n function decimalsByName(string memory base, string memory quote) external view returns (uint8);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface OracleInterface {\n function getPrice(address asset) external view returns (uint256);\n}\n\ninterface ResilientOracleInterface is OracleInterface {\n function updatePrice(address vToken) external;\n\n function updateAssetPrice(address asset) external;\n\n function getUnderlyingPrice(address vToken) external view returns (uint256);\n}\n\ninterface TwapInterface is OracleInterface {\n function updateTwap(address asset) external returns (uint256);\n}\n\ninterface BoundValidatorInterface {\n function validatePriceWithAnchorPrice(\n address asset,\n uint256 reporterPrice,\n uint256 anchorPrice\n ) external view returns (bool);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/PublicResolverInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.13;\n\ninterface PublicResolverInterface {\n function addr(bytes32 node) external view returns (address payable);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/SIDRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n// SPDX-FileCopyrightText: 2022 Venus\npragma solidity 0.8.13;\n\ninterface SIDRegistryInterface {\n function resolver(bytes32 node) external view returns (address);\n}\n" + }, + "@venusprotocol/oracle/contracts/interfaces/VBep20Interface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\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" + }, + "@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/SIDRegistryInterface.sol\";\nimport \"../interfaces/FeedRegistryInterface.sol\";\nimport \"../interfaces/PublicResolverInterface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport \"../interfaces/OracleInterface.sol\";\n\n/**\n * @title BinanceOracle\n * @author Venus\n * @notice This oracle fetches price of assets from Binance.\n */\ncontract BinanceOracle is AccessControlledV8, OracleInterface {\n address public sidRegistryAddress;\n\n /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Max stale period configuration for assets\n mapping(string => uint256) public maxStalePeriod;\n\n /// @notice Override symbols to be compatible with Binance feed registry\n mapping(string => string) public symbols;\n\n event MaxStalePeriodAdded(string indexed asset, uint256 maxStalePeriod);\n\n event SymbolOverridden(string indexed symbol, string overriddenSymbol);\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 /// @notice Constructor for the implementation contract.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Used to set the max stale period of an asset\n * @param symbol The symbol of the asset\n * @param _maxStalePeriod The max stake period\n */\n function setMaxStalePeriod(string memory symbol, uint256 _maxStalePeriod) external {\n _checkAccessAllowed(\"setMaxStalePeriod(string,uint256)\");\n if (_maxStalePeriod == 0) revert(\"stale period can't be zero\");\n if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n maxStalePeriod[symbol] = _maxStalePeriod;\n emit MaxStalePeriodAdded(symbol, _maxStalePeriod);\n }\n\n /**\n * @notice Used to override a symbol when fetching price\n * @param symbol The symbol to override\n * @param overrideSymbol The symbol after override\n */\n function setSymbolOverride(string calldata symbol, string calldata overrideSymbol) external {\n _checkAccessAllowed(\"setSymbolOverride(string,string)\");\n if (bytes(symbol).length == 0) revert(\"symbol cannot be empty\");\n\n symbols[symbol] = overrideSymbol;\n emit SymbolOverridden(symbol, overrideSymbol);\n }\n\n /**\n * @notice Sets the contracts required to fetch prices\n * @param _sidRegistryAddress Address of SID registry\n * @param _accessControlManager Address of the access control manager contract\n */\n function initialize(\n address _sidRegistryAddress,\n address _accessControlManager\n ) external initializer notNullAddress(_sidRegistryAddress) {\n sidRegistryAddress = _sidRegistryAddress;\n __AccessControlled_init(_accessControlManager);\n }\n\n /**\n * @notice Uses Space ID to fetch the feed registry address\n * @return feedRegistryAddress Address of binance oracle feed registry.\n */\n function getFeedRegistryAddress() public view returns (address) {\n bytes32 nodeHash = 0x94fe3821e0768eb35012484db4df61890f9a6ca5bfa984ef8ff717e73139faff;\n\n SIDRegistryInterface sidRegistry = SIDRegistryInterface(sidRegistryAddress);\n address publicResolverAddress = sidRegistry.resolver(nodeHash);\n PublicResolverInterface publicResolver = PublicResolverInterface(publicResolverAddress);\n\n return publicResolver.addr(nodeHash);\n }\n\n /**\n * @notice Gets the price of a asset from the binance oracle\n * @param asset Address of the asset\n * @return Price in USD\n */\n function getPrice(address asset) public view returns (uint256) {\n string memory symbol;\n uint256 decimals;\n\n if (asset == BNB_ADDR) {\n symbol = \"BNB\";\n decimals = 18;\n } else {\n IERC20Metadata token = IERC20Metadata(asset);\n symbol = token.symbol();\n decimals = token.decimals();\n }\n\n string memory overrideSymbol = symbols[symbol];\n\n if (bytes(overrideSymbol).length != 0) {\n symbol = overrideSymbol;\n }\n\n return _getPrice(symbol, decimals);\n }\n\n function _getPrice(string memory symbol, uint256 decimals) internal view returns (uint256) {\n FeedRegistryInterface feedRegistry = FeedRegistryInterface(getFeedRegistryAddress());\n\n (, int256 answer, , uint256 updatedAt, ) = feedRegistry.latestRoundDataByName(symbol, \"USD\");\n if (answer <= 0) revert(\"invalid binance oracle price\");\n if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n uint256 deltaTime;\n unchecked {\n deltaTime = block.timestamp - updatedAt;\n }\n if (deltaTime > maxStalePeriod[symbol]) revert(\"binance oracle price expired\");\n\n uint256 decimalDelta = feedRegistry.decimalsByName(symbol, \"USD\");\n return (uint256(answer) * (10 ** (18 - decimalDelta))) * (10 ** (18 - decimals));\n }\n}\n" + }, + "@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport \"../interfaces/VBep20Interface.sol\";\nimport \"../interfaces/OracleInterface.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\n/**\n * @title ChainlinkOracle\n * @author Venus\n * @notice This oracle fetches prices of assets from the Chainlink oracle.\n */\ncontract ChainlinkOracle is AccessControlledV8, OracleInterface {\n struct TokenConfig {\n /// @notice Underlying token address, which can't be a null address\n /// @notice Used to check if a token is supported\n /// @notice 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB for BNB\n address asset;\n /// @notice Chainlink feed address\n address feed;\n /// @notice Price expiration period of this asset\n uint256 maxStalePeriod;\n }\n\n /// @notice Set this as asset address for BNB. This is the underlying address for vBNB\n address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n /// @notice Manually set an override price, useful under extenuating conditions such as price feed failure\n mapping(address => uint256) public prices;\n\n /// @notice Token config by assets\n mapping(address => TokenConfig) public tokenConfigs;\n\n /// @notice Emit when a price is manually set\n event PricePosted(address indexed asset, uint256 previousPriceMantissa, uint256 newPriceMantissa);\n\n /// @notice Emit when a token config is added\n event TokenConfigAdded(address indexed asset, address feed, uint256 maxStalePeriod);\n\n modifier notNullAddress(address someone) {\n if (someone == address(0)) revert(\"can't be zero address\");\n _;\n }\n\n /// @notice Constructor for the implementation contract.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Manually set the price of a given asset\n * @param asset Asset address\n * @param price Asset price in 18 decimals\n * @custom:access Only Governance\n * @custom:event Emits PricePosted event on succesfully setup of asset price\n */\n function setDirectPrice(address asset, uint256 price) external notNullAddress(asset) {\n _checkAccessAllowed(\"setDirectPrice(address,uint256)\");\n\n uint256 previousPriceMantissa = prices[asset];\n prices[asset] = price;\n emit PricePosted(asset, previousPriceMantissa, price);\n }\n\n /**\n * @notice Add multiple token configs at the same time\n * @param tokenConfigs_ config array\n * @custom:access Only Governance\n * @custom:error Zero length error thrown, if length of the array in parameter 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 Initializes the owner of the contract\n * @param accessControlManager_ Address of the access control manager contract\n */\n function initialize(address accessControlManager_) external initializer {\n __AccessControlled_init(accessControlManager_);\n }\n\n /**\n * @notice Add single token config. asset & feed cannot be null addresses and maxStalePeriod must be positive\n * @param tokenConfig Token config struct\n * @custom:access Only Governance\n * @custom:error NotNullAddress error is thrown if asset address is null\n * @custom:error NotNullAddress error is thrown if token feed address is null\n * @custom:error Range error is thrown if maxStale period of token is not greater than zero\n * @custom:event Emits TokenConfigAdded event on succesfully setting of the token config\n */\n function setTokenConfig(\n TokenConfig memory tokenConfig\n ) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.feed) {\n _checkAccessAllowed(\"setTokenConfig(TokenConfig)\");\n\n if (tokenConfig.maxStalePeriod == 0) revert(\"stale period can't be zero\");\n tokenConfigs[tokenConfig.asset] = tokenConfig;\n emit TokenConfigAdded(tokenConfig.asset, tokenConfig.feed, tokenConfig.maxStalePeriod);\n }\n\n /**\n * @notice Gets the price of a asset from the chainlink oracle\n * @param asset Address of the asset\n * @return Price in USD from Chainlink or a manually set price for the asset\n */\n function getPrice(address asset) public view returns (uint256) {\n uint256 decimals;\n\n if (asset == BNB_ADDR) {\n decimals = 18;\n } else {\n IERC20Metadata token = IERC20Metadata(asset);\n decimals = token.decimals();\n }\n\n return _getPriceInternal(asset, decimals);\n }\n\n /**\n * @notice Gets the Chainlink price for a given asset\n * @param asset address of the asset\n * @param decimals decimals of the asset\n * @return price Asset price in USD or a manually set price of the asset\n */\n function _getPriceInternal(address asset, uint256 decimals) internal view returns (uint256 price) {\n uint256 tokenPrice = prices[asset];\n if (tokenPrice != 0) {\n price = tokenPrice;\n } else {\n price = _getChainlinkPrice(asset);\n }\n\n uint256 decimalDelta = 18 - decimals;\n return price * (10 ** decimalDelta);\n }\n\n /**\n * @notice Get the Chainlink price for an asset, revert if token config doesn't exist\n * @dev The precision of the price feed is used to ensure the returned price has 18 decimals of precision\n * @param asset Address of the asset\n * @return price Price in USD, with 18 decimals of precision\n * @custom:error NotNullAddress error is thrown if the asset address is null\n * @custom:error Price error is thrown if the Chainlink price of asset is not greater than zero\n * @custom:error Timing error is thrown if current timestamp is less than the last updatedAt timestamp\n * @custom:error Timing error is thrown if time difference between current time and last updated time\n * is greater than maxStalePeriod\n */\n function _getChainlinkPrice(\n address asset\n ) private view notNullAddress(tokenConfigs[asset].asset) returns (uint256) {\n TokenConfig memory tokenConfig = tokenConfigs[asset];\n AggregatorV3Interface feed = AggregatorV3Interface(tokenConfig.feed);\n\n // note: maxStalePeriod cannot be 0\n uint256 maxStalePeriod = tokenConfig.maxStalePeriod;\n\n // Chainlink USD-denominated feeds store answers at 8 decimals, mostly\n uint256 decimalDelta = 18 - feed.decimals();\n\n (, int256 answer, , uint256 updatedAt, ) = feed.latestRoundData();\n if (answer <= 0) revert(\"chainlink price must be positive\");\n if (block.timestamp < updatedAt) revert(\"updatedAt exceeds block time\");\n\n uint256 deltaTime;\n unchecked {\n deltaTime = block.timestamp - updatedAt;\n }\n\n if (deltaTime > maxStalePeriod) revert(\"chainlink price expired\");\n\n return uint256(answer) * (10 ** decimalDelta);\n }\n}\n" + }, + "contracts/BaseJumpRateModelV2.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\n\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { BLOCKS_PER_YEAR, EXP_SCALE, MANTISSA_ONE } from \"./lib/constants.sol\";\n\n/**\n * @title Logic for Compound's JumpRateModel Contract V2.\n * @author Compound (modified by Dharma Labs, Arr00 and Venus)\n * @notice An interest rate model with a steep increase after a certain utilization threshold called **kink** is reached.\n * The parameters of this interest rate model can be adjusted by the owner. Version 2 modifies Version 1 by enabling updateable parameters.\n */\nabstract contract BaseJumpRateModelV2 is InterestRateModel {\n /**\n * @notice The address of the AccessControlManager contract\n */\n IAccessControlManagerV8 public accessControlManager;\n\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public baseRatePerBlock;\n\n /**\n * @notice The multiplier per block after hitting a specified utilization point\n */\n uint256 public jumpMultiplierPerBlock;\n\n /**\n * @notice The utilization point at which the jump multiplier is applied\n */\n uint256 public kink;\n\n event NewInterestParams(\n uint256 baseRatePerBlock,\n uint256 multiplierPerBlock,\n uint256 jumpMultiplierPerBlock,\n uint256 kink\n );\n\n /**\n * @notice Thrown when the action is prohibited by AccessControlManager\n */\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @param accessControlManager_ The address of the AccessControlManager contract\n */\n constructor(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n IAccessControlManagerV8 accessControlManager_\n ) {\n require(address(accessControlManager_) != address(0), \"invalid ACM address\");\n\n accessControlManager = accessControlManager_;\n\n _updateJumpRateModel(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n * @custom:error Unauthorized if the sender is not allowed to call this function\n * @custom:access Controlled by AccessControlManager\n */\n function updateJumpRateModel(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) external virtual {\n string memory signature = \"updateJumpRateModel(uint256,uint256,uint256,uint256)\";\n bool isAllowedToCall = accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n\n _updateJumpRateModel(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) public view virtual override returns (uint256) {\n uint256 oneMinusReserveFactor = MANTISSA_ONE - reserveFactorMantissa;\n uint256 borrowRate = _getBorrowRate(cash, borrows, reserves, badDebt);\n uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / EXP_SCALE;\n uint256 incomeToDistribute = borrows * rateToPool;\n uint256 supply = cash + borrows + badDebt - reserves;\n return incomeToDistribute / supply;\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `(borrows + badDebt) / (cash + borrows + badDebt - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @param badDebt The amount of badDebt in the market\n * @return The utilization rate as a mantissa between [0, MANTISSA_ONE]\n */\n function utilizationRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public pure returns (uint256) {\n // Utilization rate is 0 when there are no borrows and badDebt\n if ((borrows + badDebt) == 0) {\n return 0;\n }\n\n uint256 rate = ((borrows + badDebt) * EXP_SCALE) / (cash + borrows + badDebt - reserves);\n\n if (rate > EXP_SCALE) {\n rate = EXP_SCALE;\n }\n\n return rate;\n }\n\n /**\n * @notice Internal function to update the parameters of the interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n * @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point\n * @param kink_ The utilization point at which the jump multiplier is applied\n */\n function _updateJumpRateModel(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_\n ) internal {\n baseRatePerBlock = baseRatePerYear / BLOCKS_PER_YEAR;\n multiplierPerBlock = multiplierPerYear / BLOCKS_PER_YEAR;\n jumpMultiplierPerBlock = jumpMultiplierPerYear / BLOCKS_PER_YEAR;\n kink = kink_;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function _getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) internal view returns (uint256) {\n uint256 util = utilizationRate(cash, borrows, reserves, badDebt);\n uint256 kink_ = kink;\n\n if (util <= kink_) {\n return ((util * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n }\n uint256 normalRate = ((kink_ * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n uint256 excessUtil;\n unchecked {\n excessUtil = util - kink_;\n }\n return ((excessUtil * jumpMultiplierPerBlock) / EXP_SCALE) + normalRate;\n }\n}\n" + }, + "contracts/Comptroller.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { ComptrollerStorage } from \"./ComptrollerStorage.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\nimport { MaxLoopsLimitHelper } from \"./MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title Comptroller\n * @author Venus\n * @notice The Comptroller is designed to provide checks for all minting, redeeming, transferring, borrowing, lending, repaying, liquidating,\n * and seizing done by the `vToken` contract. Each pool has one `Comptroller` checking these interactions across markets. When a user interacts\n * with a given market by one of these main actions, a call is made to a corresponding hook in the associated `Comptroller`, which either allows\n * or reverts the transaction. These hooks also update supply and borrow rewards as they are called. The comptroller holds the logic for assessing\n * liquidity snapshots of an account via the collateral factor and liquidation threshold. This check determines the collateral needed for a borrow,\n * as well as how much of a borrow may be liquidated. A user may borrow a portion of their collateral with the maximum amount determined by the\n * markets collateral factor. However, if their borrowed amount exceeds an amount calculated using the market’s corresponding liquidation threshold,\n * the borrow is eligible for liquidation.\n *\n * The `Comptroller` also includes two functions `liquidateAccount()` and `healAccount()`, which are meant to handle accounts that do not exceed\n * the `minLiquidatableCollateral` for the `Comptroller`:\n *\n * - `healAccount()`: This function is called to seize all of a given user’s collateral, requiring the `msg.sender` repay a certain percentage\n * of the debt calculated by `collateral/(borrows*liquidationIncentive)`. The function can only be called if the calculated percentage does not exceed\n * 100%, because otherwise no `badDebt` would be created and `liquidateAccount()` should be used instead. The difference in the actual amount of debt\n * and debt paid off is recorded as `badDebt` for each market, which can then be auctioned off for the risk reserves of the associated pool.\n * - `liquidateAccount()`: This function can only be called if the collateral seized will cover all borrows of an account, as well as the liquidation\n * incentive. Otherwise, the pool will incur bad debt, in which case the function `healAccount()` should be used instead. This function skips the logic\n * verifying that the repay amount does not exceed the close factor.\n */\ncontract Comptroller is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n ComptrollerStorage,\n ComptrollerInterface,\n ExponentialNoError,\n MaxLoopsLimitHelper\n{\n // PoolRegistry, immutable to save on gas\n /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n address public immutable poolRegistry;\n\n /// @notice Emitted when an account enters a market\n event MarketEntered(VToken indexed vToken, address indexed account);\n\n /// @notice Emitted when an account exits a market\n event MarketExited(VToken indexed vToken, address indexed account);\n\n /// @notice Emitted when close factor is changed by admin\n event NewCloseFactor(uint256 oldCloseFactorMantissa, uint256 newCloseFactorMantissa);\n\n /// @notice Emitted when a collateral factor is changed by admin\n event NewCollateralFactor(VToken vToken, uint256 oldCollateralFactorMantissa, uint256 newCollateralFactorMantissa);\n\n /// @notice Emitted when liquidation threshold is changed by admin\n event NewLiquidationThreshold(\n VToken vToken,\n uint256 oldLiquidationThresholdMantissa,\n uint256 newLiquidationThresholdMantissa\n );\n\n /// @notice Emitted when liquidation incentive is changed by admin\n event NewLiquidationIncentive(uint256 oldLiquidationIncentiveMantissa, uint256 newLiquidationIncentiveMantissa);\n\n /// @notice Emitted when price oracle is changed\n event NewPriceOracle(ResilientOracleInterface oldPriceOracle, ResilientOracleInterface newPriceOracle);\n\n /// @notice Emitted when an action is paused on a market\n event ActionPausedMarket(VToken vToken, Action action, bool pauseState);\n\n /// @notice Emitted when borrow cap for a vToken is changed\n event NewBorrowCap(VToken indexed vToken, uint256 newBorrowCap);\n\n /// @notice Emitted when the collateral threshold (in USD) for non-batch liquidations is changed\n event NewMinLiquidatableCollateral(uint256 oldMinLiquidatableCollateral, uint256 newMinLiquidatableCollateral);\n\n /// @notice Emitted when supply cap for a vToken is changed\n event NewSupplyCap(VToken indexed vToken, uint256 newSupplyCap);\n\n /// @notice Emitted when a rewards distributor is added\n event NewRewardsDistributor(address indexed rewardsDistributor);\n\n /// @notice Emitted when a market is supported\n event MarketSupported(VToken vToken);\n\n /// @notice Thrown when collateral factor exceeds the upper bound\n error InvalidCollateralFactor();\n\n /// @notice Thrown when liquidation threshold exceeds the collateral factor\n error InvalidLiquidationThreshold();\n\n /// @notice Thrown when the action is only available to specific sender, but the real sender was different\n error UnexpectedSender(address expectedSender, address actualSender);\n\n /// @notice Thrown when the oracle returns an invalid price for some asset\n error PriceError(address vToken);\n\n /// @notice Thrown if VToken unexpectedly returned a nonzero error code while trying to get account snapshot\n error SnapshotError(address vToken, address user);\n\n /// @notice Thrown when the market is not listed\n error MarketNotListed(address market);\n\n /// @notice Thrown when a market has an unexpected comptroller\n error ComptrollerMismatch();\n\n /// @notice Thrown when user is not member of market\n error MarketNotCollateral(address vToken, address user);\n\n /**\n * @notice Thrown during the liquidation if user's total collateral amount is lower than\n * a predefined threshold. In this case only batch liquidations (either liquidateAccount\n * or healAccount) are available.\n */\n error MinimalCollateralViolated(uint256 expectedGreaterThan, uint256 actual);\n error CollateralExceedsThreshold(uint256 expectedLessThanOrEqualTo, uint256 actual);\n error InsufficientCollateral(uint256 collateralToSeize, uint256 availableCollateral);\n\n /// @notice Thrown when the account doesn't have enough liquidity to redeem or borrow\n error InsufficientLiquidity();\n\n /// @notice Thrown when trying to liquidate a healthy account\n error InsufficientShortfall();\n\n /// @notice Thrown when trying to repay more than allowed by close factor\n error TooMuchRepay();\n\n /// @notice Thrown if the user is trying to exit a market in which they have an outstanding debt\n error NonzeroBorrowBalance();\n\n /// @notice Thrown when trying to perform an action that is paused\n error ActionPaused(address market, Action action);\n\n /// @notice Thrown when trying to add a market that is already listed\n error MarketAlreadyListed(address market);\n\n /// @notice Thrown if the supply cap is exceeded\n error SupplyCapExceeded(address market, uint256 cap);\n\n /// @notice Thrown if the borrow cap is exceeded\n error BorrowCapExceeded(address market, uint256 cap);\n\n /// @param poolRegistry_ Pool registry address\n /// @custom:oz-upgrades-unsafe-allow constructor\n /// @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n constructor(address poolRegistry_) {\n ensureNonzeroAddress(poolRegistry_);\n\n poolRegistry = poolRegistry_;\n _disableInitializers();\n }\n\n /**\n * @param loopLimit Limit for the loops can iterate to avoid the DOS\n * @param accessControlManager Access control manager contract address\n */\n function initialize(uint256 loopLimit, address accessControlManager) external initializer {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager);\n\n _setMaxLoopsLimit(loopLimit);\n }\n\n /**\n * @notice Add assets to be included in account liquidity calculation; enabling them to be used as collateral\n * @param vTokens The list of addresses of the vToken markets to be enabled\n * @return errors An array of NO_ERROR for compatibility with Venus core tooling\n * @custom:event MarketEntered is emitted for each market on success\n * @custom:error ActionPaused error is thrown if entering any of the markets is paused\n * @custom:error MarketNotListed error is thrown if any of the markets is not listed\n * @custom:access Not restricted\n */\n function enterMarkets(address[] memory vTokens) external override returns (uint256[] memory) {\n uint256 len = vTokens.length;\n\n uint256[] memory results = new uint256[](len);\n for (uint256 i; i < len; ++i) {\n VToken vToken = VToken(vTokens[i]);\n\n _addToMarket(vToken, msg.sender);\n results[i] = NO_ERROR;\n }\n\n return results;\n }\n\n /**\n * @notice Removes asset from sender's account liquidity calculation; disabling them as collateral\n * @dev Sender must not have an outstanding borrow balance in the asset,\n * or be providing necessary collateral for an outstanding borrow.\n * @param vTokenAddress The address of the asset to be removed\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event MarketExited is emitted on success\n * @custom:error ActionPaused error is thrown if exiting the market is paused\n * @custom:error NonzeroBorrowBalance error is thrown if the user has an outstanding borrow in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if exiting the market would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function exitMarket(address vTokenAddress) external override returns (uint256) {\n _checkActionPauseState(vTokenAddress, Action.EXIT_MARKET);\n VToken vToken = VToken(vTokenAddress);\n /* Get sender tokensHeld and amountOwed underlying from the vToken */\n (uint256 tokensHeld, uint256 amountOwed, ) = _safeGetAccountSnapshot(vToken, msg.sender);\n\n /* Fail if the sender has a borrow balance */\n if (amountOwed != 0) {\n revert NonzeroBorrowBalance();\n }\n\n /* Fail if the sender is not permitted to redeem all of their tokens */\n _checkRedeemAllowed(vTokenAddress, msg.sender, tokensHeld);\n\n Market storage marketToExit = markets[address(vToken)];\n\n /* Return true if the sender is not already ‘in’ the market */\n if (!marketToExit.accountMembership[msg.sender]) {\n return NO_ERROR;\n }\n\n /* Set vToken account membership to false */\n delete marketToExit.accountMembership[msg.sender];\n\n /* Delete vToken from the account’s list of assets */\n // load into memory for faster iteration\n VToken[] memory userAssetList = accountAssets[msg.sender];\n uint256 len = userAssetList.length;\n\n uint256 assetIndex = len;\n for (uint256 i; i < len; ++i) {\n if (userAssetList[i] == vToken) {\n assetIndex = i;\n break;\n }\n }\n\n // We *must* have found the asset in the list or our redundant data structure is broken\n assert(assetIndex < len);\n\n // copy last item in list to location of item to be removed, reduce length by 1\n VToken[] storage storedList = accountAssets[msg.sender];\n storedList[assetIndex] = storedList[storedList.length - 1];\n storedList.pop();\n\n emit MarketExited(vToken, msg.sender);\n\n return NO_ERROR;\n }\n\n /*** Policy Hooks ***/\n\n /**\n * @notice Checks if the account should be allowed to mint tokens in the given market\n * @param vToken The market to verify the mint against\n * @param minter The account which would get the minted tokens\n * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens\n * @custom:error ActionPaused error is thrown if supplying to this market is paused\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error SupplyCapExceeded error is thrown if the total supply exceeds the cap after minting\n * @custom:access Not restricted\n */\n function preMintHook(\n address vToken,\n address minter,\n uint256 mintAmount\n ) external override {\n _checkActionPauseState(vToken, Action.MINT);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n uint256 supplyCap = supplyCaps[vToken];\n // Skipping the cap check for uncapped coins to save some gas\n if (supplyCap != type(uint256).max) {\n uint256 vTokenSupply = VToken(vToken).totalSupply();\n Exp memory exchangeRate = Exp({ mantissa: VToken(vToken).exchangeRateStored() });\n uint256 nextTotalSupply = mul_ScalarTruncateAddUInt(exchangeRate, vTokenSupply, mintAmount);\n if (nextTotalSupply > supplyCap) {\n revert SupplyCapExceeded(vToken, supplyCap);\n }\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, minter);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to redeem tokens in the given market\n * @param vToken The market to verify the redeem against\n * @param redeemer The account which would redeem the tokens\n * @param redeemTokens The number of vTokens to exchange for the underlying asset in the market\n * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function preRedeemHook(\n address vToken,\n address redeemer,\n uint256 redeemTokens\n ) external override {\n _checkActionPauseState(vToken, Action.REDEEM);\n\n _checkRedeemAllowed(vToken, redeemer, redeemTokens);\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, redeemer);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to borrow the underlying asset of the given market\n * @param vToken The market to verify the borrow against\n * @param borrower The account which would borrow the asset\n * @param borrowAmount The amount of underlying the account would borrow\n * @custom:error ActionPaused error is thrown if borrowing is paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if there is not enough collateral to borrow\n * @custom:error BorrowCapExceeded is thrown if the borrow cap will be exceeded should this borrow succeed\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted if vToken is enabled as collateral, otherwise only vToken\n */\n /// disable-eslint\n function preBorrowHook(\n address vToken,\n address borrower,\n uint256 borrowAmount\n ) external override {\n _checkActionPauseState(vToken, Action.BORROW);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n if (!markets[vToken].accountMembership[borrower]) {\n // only vTokens may call borrowAllowed if borrower not in market\n _checkSenderIs(vToken);\n\n // attempt to add borrower to the market or revert\n _addToMarket(VToken(msg.sender), borrower);\n }\n\n // Update the prices of tokens\n updatePrices(borrower);\n\n if (oracle.getUnderlyingPrice(vToken) == 0) {\n revert PriceError(address(vToken));\n }\n\n uint256 borrowCap = borrowCaps[vToken];\n // Skipping the cap check for uncapped coins to save some gas\n if (borrowCap != type(uint256).max) {\n uint256 totalBorrows = VToken(vToken).totalBorrows();\n uint256 badDebt = VToken(vToken).badDebt();\n uint256 nextTotalBorrows = totalBorrows + borrowAmount + badDebt;\n if (nextTotalBorrows > borrowCap) {\n revert BorrowCapExceeded(vToken, borrowCap);\n }\n }\n\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n borrower,\n VToken(vToken),\n 0,\n borrowAmount,\n _getCollateralFactor\n );\n\n if (snapshot.shortfall > 0) {\n revert InsufficientLiquidity();\n }\n\n Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to repay a borrow in the given market\n * @param vToken The market to verify the repay against\n * @param borrower The account which would borrowed the asset\n * @custom:error ActionPaused error is thrown if repayments are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:access Not restricted\n */\n function preRepayHook(address vToken, address borrower) external override {\n _checkActionPauseState(vToken, Action.REPAY);\n\n oracle.updatePrice(vToken);\n\n if (!markets[vToken].isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n Exp memory borrowIndex = Exp({ mantissa: VToken(vToken).borrowIndex() });\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenBorrowIndex(vToken, borrowIndex);\n rewardsDistributor.distributeBorrowerRewardToken(vToken, borrower, borrowIndex);\n }\n }\n\n /**\n * @notice Checks if the liquidation should be allowed to occur\n * @param vTokenBorrowed Asset which was borrowed by the borrower\n * @param vTokenCollateral Asset which was used as collateral and will be seized\n * @param borrower The address of the borrower\n * @param repayAmount The amount of underlying being repaid\n * @param skipLiquidityCheck Allows the borrow to be liquidated regardless of the account liquidity\n * @custom:error ActionPaused error is thrown if liquidations are paused in this market\n * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n * @custom:error TooMuchRepay error is thrown if the liquidator is trying to repay more than allowed by close factor\n * @custom:error MinimalCollateralViolated is thrown if the users' total collateral is lower than the threshold for non-batch liquidations\n * @custom:error InsufficientShortfall is thrown when trying to liquidate a healthy account\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n */\n function preLiquidateHook(\n address vTokenBorrowed,\n address vTokenCollateral,\n address borrower,\n uint256 repayAmount,\n bool skipLiquidityCheck\n ) external override {\n // Pause Action.LIQUIDATE on BORROWED TOKEN to prevent liquidating it.\n // If we want to pause liquidating to vTokenCollateral, we should pause\n // Action.SEIZE on it\n _checkActionPauseState(vTokenBorrowed, Action.LIQUIDATE);\n\n // Update the prices of tokens\n updatePrices(borrower);\n\n if (!markets[vTokenBorrowed].isListed) {\n revert MarketNotListed(address(vTokenBorrowed));\n }\n if (!markets[vTokenCollateral].isListed) {\n revert MarketNotListed(address(vTokenCollateral));\n }\n\n uint256 borrowBalance = VToken(vTokenBorrowed).borrowBalanceStored(borrower);\n\n /* Allow accounts to be liquidated if the market is deprecated or it is a forced liquidation */\n if (skipLiquidityCheck || isDeprecated(VToken(vTokenBorrowed))) {\n if (repayAmount > borrowBalance) {\n revert TooMuchRepay();\n }\n return;\n }\n\n /* The borrower must have shortfall and collateral > threshold in order to be liquidatable */\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral <= minLiquidatableCollateral) {\n /* The liquidator should use either liquidateAccount or healAccount */\n revert MinimalCollateralViolated(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n /* The liquidator may not repay more than what is allowed by the closeFactor */\n uint256 maxClose = mul_ScalarTruncate(Exp({ mantissa: closeFactorMantissa }), borrowBalance);\n if (repayAmount > maxClose) {\n revert TooMuchRepay();\n }\n }\n\n /**\n * @notice Checks if the seizing of assets should be allowed to occur\n * @param vTokenCollateral Asset which was used as collateral and will be seized\n * @param seizerContract Contract that tries to seize the asset (either borrowed vToken or Comptroller)\n * @param liquidator The address repaying the borrow and seizing the collateral\n * @param borrower The address of the borrower\n * @custom:error ActionPaused error is thrown if seizing this type of collateral is paused\n * @custom:error MarketNotListed error is thrown if either collateral or borrowed token is not listed\n * @custom:error ComptrollerMismatch error is when seizer contract or seized asset belong to different pools\n * @custom:access Not restricted\n */\n function preSeizeHook(\n address vTokenCollateral,\n address seizerContract,\n address liquidator,\n address borrower\n ) external override {\n // Pause Action.SEIZE on COLLATERAL to prevent seizing it.\n // If we want to pause liquidating vTokenBorrowed, we should pause\n // Action.LIQUIDATE on it\n _checkActionPauseState(vTokenCollateral, Action.SEIZE);\n\n Market storage market = markets[vTokenCollateral];\n\n if (!market.isListed) {\n revert MarketNotListed(vTokenCollateral);\n }\n\n if (seizerContract == address(this)) {\n // If Comptroller is the seizer, just check if collateral's comptroller\n // is equal to the current address\n if (address(VToken(vTokenCollateral).comptroller()) != address(this)) {\n revert ComptrollerMismatch();\n }\n } else {\n // If the seizer is not the Comptroller, check that the seizer is a\n // listed market, and that the markets' comptrollers match\n if (!markets[seizerContract].isListed) {\n revert MarketNotListed(seizerContract);\n }\n if (VToken(vTokenCollateral).comptroller() != VToken(seizerContract).comptroller()) {\n revert ComptrollerMismatch();\n }\n }\n\n if (!market.accountMembership[borrower]) {\n revert MarketNotCollateral(vTokenCollateral, borrower);\n }\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vTokenCollateral);\n rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, borrower);\n rewardsDistributor.distributeSupplierRewardToken(vTokenCollateral, liquidator);\n }\n }\n\n /**\n * @notice Checks if the account should be allowed to transfer tokens in the given market\n * @param vToken The market to verify the transfer against\n * @param src The account which sources the tokens\n * @param dst The account which receives the tokens\n * @param transferTokens The number of vTokens to transfer\n * @custom:error ActionPaused error is thrown if withdrawals are paused in this market\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InsufficientLiquidity error is thrown if the withdrawal would lead to user's insolvency\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function preTransferHook(\n address vToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external override {\n _checkActionPauseState(vToken, Action.TRANSFER);\n\n // Currently the only consideration is whether or not\n // the src is allowed to redeem this many tokens\n _checkRedeemAllowed(vToken, src, transferTokens);\n\n // Keep the flywheel moving\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n rewardsDistributor.updateRewardTokenSupplyIndex(vToken);\n rewardsDistributor.distributeSupplierRewardToken(vToken, src);\n rewardsDistributor.distributeSupplierRewardToken(vToken, dst);\n }\n }\n\n /*** Pool-level operations ***/\n\n /**\n * @notice Seizes all the remaining collateral, makes msg.sender repay the existing\n * borrows, and treats the rest of the debt as bad debt (for each market).\n * The sender has to repay a certain percentage of the debt, computed as\n * collateral / (borrows * liquidationIncentive).\n * @param user account to heal\n * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for healing\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function healAccount(address user) external {\n VToken[] memory userAssets = accountAssets[user];\n uint256 userAssetsCount = userAssets.length;\n\n address liquidator = msg.sender;\n {\n ResilientOracleInterface oracle_ = oracle;\n // We need all user's markets to be fresh for the computations to be correct\n for (uint256 i; i < userAssetsCount; ++i) {\n userAssets[i].accrueInterest();\n oracle_.updatePrice(address(userAssets[i]));\n }\n }\n\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(user, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral > minLiquidatableCollateral) {\n revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n // percentage = collateral / (borrows * liquidation incentive)\n Exp memory collateral = Exp({ mantissa: snapshot.totalCollateral });\n Exp memory scaledBorrows = mul_(\n Exp({ mantissa: snapshot.borrows }),\n Exp({ mantissa: liquidationIncentiveMantissa })\n );\n\n Exp memory percentage = div_(collateral, scaledBorrows);\n if (lessThanExp(Exp({ mantissa: MANTISSA_ONE }), percentage)) {\n revert CollateralExceedsThreshold(scaledBorrows.mantissa, collateral.mantissa);\n }\n\n for (uint256 i; i < userAssetsCount; ++i) {\n VToken market = userAssets[i];\n\n (uint256 tokens, uint256 borrowBalance, ) = _safeGetAccountSnapshot(market, user);\n uint256 repaymentAmount = mul_ScalarTruncate(percentage, borrowBalance);\n\n // Seize the entire collateral\n if (tokens != 0) {\n market.seize(liquidator, user, tokens);\n }\n // Repay a certain percentage of the borrow, forgive the rest\n if (borrowBalance != 0) {\n market.healBorrow(liquidator, user, repaymentAmount);\n }\n }\n }\n\n /**\n * @notice Liquidates all borrows of the borrower. Callable only if the collateral is less than\n * a predefined threshold, and the account collateral can be seized to cover all borrows. If\n * the collateral is higher than the threshold, use regular liquidations. If the collateral is\n * below the threshold, and the account is insolvent, use healAccount.\n * @param borrower the borrower address\n * @param orders an array of liquidation orders\n * @custom:error CollateralExceedsThreshold error is thrown when the collateral is too big for a batch liquidation\n * @custom:error InsufficientCollateral error is thrown when there is not enough collateral to cover the debt\n * @custom:error SnapshotError is thrown if some vToken fails to return the account's supply and borrows\n * @custom:error PriceError is thrown if the oracle returns an incorrect price for some asset\n * @custom:access Not restricted\n */\n function liquidateAccount(address borrower, LiquidationOrder[] calldata orders) external {\n // We will accrue interest and update the oracle prices later during the liquidation\n\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(borrower, _getLiquidationThreshold);\n\n if (snapshot.totalCollateral > minLiquidatableCollateral) {\n // You should use the regular vToken.liquidateBorrow(...) call\n revert CollateralExceedsThreshold(minLiquidatableCollateral, snapshot.totalCollateral);\n }\n\n uint256 collateralToSeize = mul_ScalarTruncate(\n Exp({ mantissa: liquidationIncentiveMantissa }),\n snapshot.borrows\n );\n if (collateralToSeize >= snapshot.totalCollateral) {\n // There is not enough collateral to seize. Use healBorrow to repay some part of the borrow\n // and record bad debt.\n revert InsufficientCollateral(collateralToSeize, snapshot.totalCollateral);\n }\n\n if (snapshot.shortfall == 0) {\n revert InsufficientShortfall();\n }\n\n uint256 ordersCount = orders.length;\n\n _ensureMaxLoops(ordersCount / 2);\n\n for (uint256 i; i < ordersCount; ++i) {\n if (!markets[address(orders[i].vTokenBorrowed)].isListed) {\n revert MarketNotListed(address(orders[i].vTokenBorrowed));\n }\n if (!markets[address(orders[i].vTokenCollateral)].isListed) {\n revert MarketNotListed(address(orders[i].vTokenCollateral));\n }\n\n LiquidationOrder calldata order = orders[i];\n order.vTokenBorrowed.forceLiquidateBorrow(\n msg.sender,\n borrower,\n order.repayAmount,\n order.vTokenCollateral,\n true\n );\n }\n\n VToken[] memory borrowMarkets = accountAssets[borrower];\n uint256 marketsCount = borrowMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n (, uint256 borrowBalance, ) = _safeGetAccountSnapshot(borrowMarkets[i], borrower);\n require(borrowBalance == 0, \"Nonzero borrow balance after liquidation\");\n }\n }\n\n /**\n * @notice Sets the closeFactor to use when liquidating borrows\n * @param newCloseFactorMantissa New close factor, scaled by 1e18\n * @custom:event Emits NewCloseFactor on success\n * @custom:access Controlled by AccessControlManager\n */\n function setCloseFactor(uint256 newCloseFactorMantissa) external {\n _checkAccessAllowed(\"setCloseFactor(uint256)\");\n require(MAX_CLOSE_FACTOR_MANTISSA >= newCloseFactorMantissa, \"Close factor greater than maximum close factor\");\n require(MIN_CLOSE_FACTOR_MANTISSA <= newCloseFactorMantissa, \"Close factor smaller than minimum close factor\");\n\n uint256 oldCloseFactorMantissa = closeFactorMantissa;\n closeFactorMantissa = newCloseFactorMantissa;\n emit NewCloseFactor(oldCloseFactorMantissa, newCloseFactorMantissa);\n }\n\n /**\n * @notice Sets the collateralFactor for a market\n * @dev This function is restricted by the AccessControlManager\n * @param vToken The market to set the factor on\n * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18\n * @param newLiquidationThresholdMantissa The new liquidation threshold, scaled by 1e18\n * @custom:event Emits NewCollateralFactor when collateral factor is updated\n * and NewLiquidationThreshold when liquidation threshold is updated\n * @custom:error MarketNotListed error is thrown when the market is not listed\n * @custom:error InvalidCollateralFactor error is thrown when collateral factor is too high\n * @custom:error InvalidLiquidationThreshold error is thrown when liquidation threshold is lower than collateral factor\n * @custom:error PriceError is thrown when the oracle returns an invalid price for the asset\n * @custom:access Controlled by AccessControlManager\n */\n function setCollateralFactor(\n VToken vToken,\n uint256 newCollateralFactorMantissa,\n uint256 newLiquidationThresholdMantissa\n ) external {\n _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n\n // Verify market is listed\n Market storage market = markets[address(vToken)];\n if (!market.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n // Check collateral factor <= 0.9\n if (newCollateralFactorMantissa > MAX_COLLATERAL_FACTOR_MANTISSA) {\n revert InvalidCollateralFactor();\n }\n\n // Ensure that liquidation threshold <= 1\n if (newLiquidationThresholdMantissa > MANTISSA_ONE) {\n revert InvalidLiquidationThreshold();\n }\n\n // Ensure that liquidation threshold >= CF\n if (newLiquidationThresholdMantissa < newCollateralFactorMantissa) {\n revert InvalidLiquidationThreshold();\n }\n\n // If collateral factor != 0, fail if price == 0\n if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(address(vToken)) == 0) {\n revert PriceError(address(vToken));\n }\n\n uint256 oldCollateralFactorMantissa = market.collateralFactorMantissa;\n if (newCollateralFactorMantissa != oldCollateralFactorMantissa) {\n market.collateralFactorMantissa = newCollateralFactorMantissa;\n emit NewCollateralFactor(vToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);\n }\n\n uint256 oldLiquidationThresholdMantissa = market.liquidationThresholdMantissa;\n if (newLiquidationThresholdMantissa != oldLiquidationThresholdMantissa) {\n market.liquidationThresholdMantissa = newLiquidationThresholdMantissa;\n emit NewLiquidationThreshold(vToken, oldLiquidationThresholdMantissa, newLiquidationThresholdMantissa);\n }\n }\n\n /**\n * @notice Sets liquidationIncentive\n * @dev This function is restricted by the AccessControlManager\n * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18\n * @custom:event Emits NewLiquidationIncentive on success\n * @custom:access Controlled by AccessControlManager\n */\n function setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) external {\n require(newLiquidationIncentiveMantissa >= MANTISSA_ONE, \"liquidation incentive should be greater than 1e18\");\n\n _checkAccessAllowed(\"setLiquidationIncentive(uint256)\");\n\n // Save current value for use in log\n uint256 oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;\n\n // Set liquidation incentive to new incentive\n liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;\n\n // Emit event with old incentive, new incentive\n emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);\n }\n\n /**\n * @notice Add the market to the markets mapping and set it as listed\n * @dev Only callable by the PoolRegistry\n * @param vToken The address of the market (token) to list\n * @custom:error MarketAlreadyListed is thrown if the market is already listed in this pool\n * @custom:access Only PoolRegistry\n */\n function supportMarket(VToken vToken) external {\n _checkSenderIs(poolRegistry);\n\n if (markets[address(vToken)].isListed) {\n revert MarketAlreadyListed(address(vToken));\n }\n\n require(vToken.isVToken(), \"Comptroller: Invalid vToken\"); // Sanity check to make sure its really a VToken\n\n Market storage newMarket = markets[address(vToken)];\n newMarket.isListed = true;\n newMarket.collateralFactorMantissa = 0;\n newMarket.liquidationThresholdMantissa = 0;\n\n _addMarket(address(vToken));\n\n uint256 rewardDistributorsCount = rewardsDistributors.length;\n\n for (uint256 i; i < rewardDistributorsCount; ++i) {\n rewardsDistributors[i].initializeMarket(address(vToken));\n }\n\n emit MarketSupported(vToken);\n }\n\n /**\n * @notice Set the given borrow caps for the given vToken markets. Borrowing that brings total borrows to or above borrow cap will revert.\n * @dev This function is restricted by the AccessControlManager\n * @dev A borrow cap of type(uint256).max corresponds to unlimited borrowing.\n * @dev Borrow caps smaller than the current total borrows are accepted. This way, new borrows will not be allowed\n until the total borrows amount goes below the new borrow cap\n * @param vTokens The addresses of the markets (tokens) to change the borrow caps for\n * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited borrowing.\n * @custom:access Controlled by AccessControlManager\n */\n function setMarketBorrowCaps(VToken[] calldata vTokens, uint256[] calldata newBorrowCaps) external {\n _checkAccessAllowed(\"setMarketBorrowCaps(address[],uint256[])\");\n\n uint256 numMarkets = vTokens.length;\n uint256 numBorrowCaps = newBorrowCaps.length;\n\n require(numMarkets != 0 && numMarkets == numBorrowCaps, \"invalid input\");\n\n _ensureMaxLoops(numMarkets);\n\n for (uint256 i; i < numMarkets; ++i) {\n borrowCaps[address(vTokens[i])] = newBorrowCaps[i];\n emit NewBorrowCap(vTokens[i], newBorrowCaps[i]);\n }\n }\n\n /**\n * @notice Set the given supply caps for the given vToken markets. Supply that brings total Supply to or above supply cap will revert.\n * @dev This function is restricted by the AccessControlManager\n * @dev A supply cap of type(uint256).max corresponds to unlimited supply.\n * @dev Supply caps smaller than the current total supplies are accepted. This way, new supplies will not be allowed\n until the total supplies amount goes below the new supply cap\n * @param vTokens The addresses of the markets (tokens) to change the supply caps for\n * @param newSupplyCaps The new supply cap values in underlying to be set. A value of type(uint256).max corresponds to unlimited supply.\n * @custom:access Controlled by AccessControlManager\n */\n function setMarketSupplyCaps(VToken[] calldata vTokens, uint256[] calldata newSupplyCaps) external {\n _checkAccessAllowed(\"setMarketSupplyCaps(address[],uint256[])\");\n uint256 vTokensCount = vTokens.length;\n\n require(vTokensCount != 0, \"invalid number of markets\");\n require(vTokensCount == newSupplyCaps.length, \"invalid number of markets\");\n\n _ensureMaxLoops(vTokensCount);\n\n for (uint256 i; i < vTokensCount; ++i) {\n supplyCaps[address(vTokens[i])] = newSupplyCaps[i];\n emit NewSupplyCap(vTokens[i], newSupplyCaps[i]);\n }\n }\n\n /**\n * @notice Pause/unpause specified actions\n * @dev This function is restricted by the AccessControlManager\n * @param marketsList Markets to pause/unpause the actions on\n * @param actionsList List of action ids to pause/unpause\n * @param paused The new paused state (true=paused, false=unpaused)\n * @custom:access Controlled by AccessControlManager\n */\n function setActionsPaused(\n VToken[] calldata marketsList,\n Action[] calldata actionsList,\n bool paused\n ) external {\n _checkAccessAllowed(\"setActionsPaused(address[],uint256[],bool)\");\n\n uint256 marketsCount = marketsList.length;\n uint256 actionsCount = actionsList.length;\n\n _ensureMaxLoops(marketsCount * actionsCount);\n\n for (uint256 marketIdx; marketIdx < marketsCount; ++marketIdx) {\n for (uint256 actionIdx; actionIdx < actionsCount; ++actionIdx) {\n _setActionPaused(address(marketsList[marketIdx]), actionsList[actionIdx], paused);\n }\n }\n }\n\n /**\n * @notice Set the given collateral threshold for non-batch liquidations. Regular liquidations\n * will fail if the collateral amount is less than this threshold. Liquidators should use batch\n * operations like liquidateAccount or healAccount.\n * @dev This function is restricted by the AccessControlManager\n * @param newMinLiquidatableCollateral The new min liquidatable collateral (in USD).\n * @custom:access Controlled by AccessControlManager\n */\n function setMinLiquidatableCollateral(uint256 newMinLiquidatableCollateral) external {\n _checkAccessAllowed(\"setMinLiquidatableCollateral(uint256)\");\n\n uint256 oldMinLiquidatableCollateral = minLiquidatableCollateral;\n minLiquidatableCollateral = newMinLiquidatableCollateral;\n emit NewMinLiquidatableCollateral(oldMinLiquidatableCollateral, newMinLiquidatableCollateral);\n }\n\n /**\n * @notice Add a new RewardsDistributor and initialize it with all markets\n * @dev Only callable by the admin\n * @param _rewardsDistributor Address of the RewardDistributor contract to add\n * @custom:access Only Governance\n * @custom:event Emits NewRewardsDistributor with distributor address\n */\n function addRewardsDistributor(RewardsDistributor _rewardsDistributor) external onlyOwner {\n require(!rewardsDistributorExists[address(_rewardsDistributor)], \"already exists\");\n\n uint256 rewardsDistributorsLen = rewardsDistributors.length;\n _ensureMaxLoops(rewardsDistributorsLen + 1);\n\n rewardsDistributors.push(_rewardsDistributor);\n rewardsDistributorExists[address(_rewardsDistributor)] = true;\n\n uint256 marketsCount = allMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n _rewardsDistributor.initializeMarket(address(allMarkets[i]));\n }\n\n emit NewRewardsDistributor(address(_rewardsDistributor));\n }\n\n /**\n * @notice Sets a new price oracle for the Comptroller\n * @dev Only callable by the admin\n * @param newOracle Address of the new price oracle to set\n * @custom:event Emits NewPriceOracle on success\n * @custom:error ZeroAddressNotAllowed is thrown when the new oracle address is zero\n */\n function setPriceOracle(ResilientOracleInterface newOracle) external onlyOwner {\n ensureNonzeroAddress(address(newOracle));\n\n ResilientOracleInterface oldOracle = oracle;\n oracle = newOracle;\n emit NewPriceOracle(oldOracle, newOracle);\n }\n\n /**\n * @notice Set the for loop iteration limit to avoid DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Determine the current account liquidity with respect to liquidation threshold requirements\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param account The account get liquidity for\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Account liquidity in excess of liquidation threshold requirements,\n * @return shortfall Account shortfall below liquidation threshold requirements\n */\n function getAccountLiquidity(address account)\n external\n view\n returns (\n uint256 error,\n uint256 liquidity,\n uint256 shortfall\n )\n {\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getLiquidationThreshold);\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Determine the current account liquidity with respect to collateral requirements\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param account The account get liquidity for\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Account liquidity in excess of collateral requirements,\n * @return shortfall Account shortfall below collateral requirements\n */\n function getBorrowingPower(address account)\n external\n view\n returns (\n uint256 error,\n uint256 liquidity,\n uint256 shortfall\n )\n {\n AccountLiquiditySnapshot memory snapshot = _getCurrentLiquiditySnapshot(account, _getCollateralFactor);\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed\n * @dev The interface of this function is intentionally kept compatible with Compound and Venus Core\n * @param vTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return liquidity Hypothetical account liquidity in excess of collateral requirements,\n * @return shortfall Hypothetical account shortfall below collateral requirements\n */\n function getHypotheticalAccountLiquidity(\n address account,\n address vTokenModify,\n uint256 redeemTokens,\n uint256 borrowAmount\n )\n external\n view\n returns (\n uint256 error,\n uint256 liquidity,\n uint256 shortfall\n )\n {\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n account,\n VToken(vTokenModify),\n redeemTokens,\n borrowAmount,\n _getCollateralFactor\n );\n return (NO_ERROR, snapshot.liquidity, snapshot.shortfall);\n }\n\n /**\n * @notice Return all of the markets\n * @dev The automatic getter may be used to access an individual market.\n * @return markets The list of market addresses\n */\n function getAllMarkets() external view override returns (VToken[] memory) {\n return allMarkets;\n }\n\n /**\n * @notice Check if a market is marked as listed (active)\n * @param vToken vToken Address for the market to check\n * @return listed True if listed otherwise false\n */\n function isMarketListed(VToken vToken) external view returns (bool) {\n return markets[address(vToken)].isListed;\n }\n\n /*** Assets You Are In ***/\n\n /**\n * @notice Returns the assets an account has entered\n * @param account The address of the account to pull assets for\n * @return A list with the assets the account has entered\n */\n function getAssetsIn(address account) external view returns (VToken[] memory) {\n VToken[] memory assetsIn = accountAssets[account];\n\n return assetsIn;\n }\n\n /**\n * @notice Returns whether the given account is entered in a given market\n * @param account The address of the account to check\n * @param vToken The vToken to check\n * @return True if the account is in the market specified, otherwise false.\n */\n function checkMembership(address account, VToken vToken) external view returns (bool) {\n return markets[address(vToken)].accountMembership[account];\n }\n\n /**\n * @notice Calculate number of tokens of collateral asset to seize given an underlying amount\n * @dev Used in liquidation (called in vToken.liquidateBorrowFresh)\n * @param vTokenBorrowed The address of the borrowed vToken\n * @param vTokenCollateral The address of the collateral vToken\n * @param actualRepayAmount The amount of vTokenBorrowed underlying to convert into vTokenCollateral tokens\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return tokensToSeize Number of vTokenCollateral tokens to be seized in a liquidation\n * @custom:error PriceError if the oracle returns an invalid price\n */\n function liquidateCalculateSeizeTokens(\n address vTokenBorrowed,\n address vTokenCollateral,\n uint256 actualRepayAmount\n ) external view override returns (uint256 error, uint256 tokensToSeize) {\n /* Read oracle prices for borrowed and collateral markets */\n uint256 priceBorrowedMantissa = _safeGetUnderlyingPrice(VToken(vTokenBorrowed));\n uint256 priceCollateralMantissa = _safeGetUnderlyingPrice(VToken(vTokenCollateral));\n\n /*\n * Get the exchange rate and calculate the number of collateral tokens to seize:\n * seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral\n * seizeTokens = seizeAmount / exchangeRate\n * = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)\n */\n uint256 exchangeRateMantissa = VToken(vTokenCollateral).exchangeRateStored(); // Note: reverts on error\n uint256 seizeTokens;\n Exp memory numerator;\n Exp memory denominator;\n Exp memory ratio;\n\n numerator = mul_(Exp({ mantissa: liquidationIncentiveMantissa }), Exp({ mantissa: priceBorrowedMantissa }));\n denominator = mul_(Exp({ mantissa: priceCollateralMantissa }), Exp({ mantissa: exchangeRateMantissa }));\n ratio = div_(numerator, denominator);\n\n seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);\n\n return (NO_ERROR, seizeTokens);\n }\n\n /**\n * @notice Returns reward speed given a vToken\n * @param vToken The vToken to get the reward speeds for\n * @return rewardSpeeds Array of total supply and borrow speeds and reward token for all reward distributors\n */\n function getRewardsByMarket(address vToken) external view returns (RewardSpeeds[] memory rewardSpeeds) {\n uint256 rewardsDistributorsLength = rewardsDistributors.length;\n rewardSpeeds = new RewardSpeeds[](rewardsDistributorsLength);\n for (uint256 i; i < rewardsDistributorsLength; ++i) {\n RewardsDistributor rewardsDistributor = rewardsDistributors[i];\n address rewardToken = address(rewardsDistributor.rewardToken());\n rewardSpeeds[i] = RewardSpeeds({\n rewardToken: rewardToken,\n supplySpeed: rewardsDistributor.rewardTokenSupplySpeeds(vToken),\n borrowSpeed: rewardsDistributor.rewardTokenBorrowSpeeds(vToken)\n });\n }\n return rewardSpeeds;\n }\n\n /**\n * @notice Return all reward distributors for this pool\n * @return Array of RewardDistributor addresses\n */\n function getRewardDistributors() external view returns (RewardsDistributor[] memory) {\n return rewardsDistributors;\n }\n\n /**\n * @notice A marker method that returns true for a valid Comptroller contract\n * @return Always true\n */\n function isComptroller() external pure override returns (bool) {\n return true;\n }\n\n /**\n * @notice Update the prices of all the tokens associated with the provided account\n * @param account Address of the account to get associated tokens with\n */\n function updatePrices(address account) public {\n VToken[] memory vTokens = accountAssets[account];\n uint256 vTokensCount = vTokens.length;\n\n ResilientOracleInterface oracle_ = oracle;\n\n for (uint256 i; i < vTokensCount; ++i) {\n oracle_.updatePrice(address(vTokens[i]));\n }\n }\n\n /**\n * @notice Checks if a certain action is paused on a market\n * @param market vToken address\n * @param action Action to check\n * @return paused True if the action is paused otherwise false\n */\n function actionPaused(address market, Action action) public view returns (bool) {\n return _actionPaused[market][action];\n }\n\n /**\n * @notice Check if a vToken market has been deprecated\n * @dev All borrows in a deprecated vToken market can be immediately liquidated\n * @param vToken The market to check if deprecated\n * @return deprecated True if the given vToken market has been deprecated\n */\n function isDeprecated(VToken vToken) public view returns (bool) {\n return\n markets[address(vToken)].collateralFactorMantissa == 0 &&\n actionPaused(address(vToken), Action.BORROW) &&\n vToken.reserveFactorMantissa() == MANTISSA_ONE;\n }\n\n /**\n * @notice Add the market to the borrower's \"assets in\" for liquidity calculations\n * @param vToken The market to enter\n * @param borrower The address of the account to modify\n */\n function _addToMarket(VToken vToken, address borrower) internal {\n _checkActionPauseState(address(vToken), Action.ENTER_MARKET);\n Market storage marketToJoin = markets[address(vToken)];\n\n if (!marketToJoin.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n if (marketToJoin.accountMembership[borrower]) {\n // already joined\n return;\n }\n\n // survived the gauntlet, add to list\n // NOTE: we store these somewhat redundantly as a significant optimization\n // this avoids having to iterate through the list for the most common use cases\n // that is, only when we need to perform liquidity checks\n // and not whenever we want to check if an account is in a particular market\n marketToJoin.accountMembership[borrower] = true;\n accountAssets[borrower].push(vToken);\n\n emit MarketEntered(vToken, borrower);\n }\n\n /**\n * @notice Internal function to validate that a market hasn't already been added\n * and if it hasn't adds it\n * @param vToken The market to support\n */\n function _addMarket(address vToken) internal {\n uint256 marketsCount = allMarkets.length;\n\n for (uint256 i; i < marketsCount; ++i) {\n if (allMarkets[i] == VToken(vToken)) {\n revert MarketAlreadyListed(vToken);\n }\n }\n allMarkets.push(VToken(vToken));\n marketsCount = allMarkets.length;\n _ensureMaxLoops(marketsCount);\n }\n\n /**\n * @dev Pause/unpause an action on a market\n * @param market Market to pause/unpause the action on\n * @param action Action id to pause/unpause\n * @param paused The new paused state (true=paused, false=unpaused)\n */\n function _setActionPaused(\n address market,\n Action action,\n bool paused\n ) internal {\n require(markets[market].isListed, \"cannot pause a market that is not listed\");\n _actionPaused[market][action] = paused;\n emit ActionPausedMarket(VToken(market), action, paused);\n }\n\n /**\n * @dev Internal function to check that vTokens can be safely redeemed for the underlying asset.\n * @param vToken Address of the vTokens to redeem\n * @param redeemer Account redeeming the tokens\n * @param redeemTokens The number of tokens to redeem\n */\n function _checkRedeemAllowed(\n address vToken,\n address redeemer,\n uint256 redeemTokens\n ) internal {\n Market storage market = markets[vToken];\n\n if (!market.isListed) {\n revert MarketNotListed(address(vToken));\n }\n\n /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */\n if (!market.accountMembership[redeemer]) {\n return;\n }\n\n // Update the prices of tokens\n updatePrices(redeemer);\n\n /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */\n AccountLiquiditySnapshot memory snapshot = _getHypotheticalLiquiditySnapshot(\n redeemer,\n VToken(vToken),\n redeemTokens,\n 0,\n _getCollateralFactor\n );\n if (snapshot.shortfall > 0) {\n revert InsufficientLiquidity();\n }\n }\n\n /**\n * @notice Get the total collateral, weighted collateral, borrow balance, liquidity, shortfall\n * @param account The account to get the snapshot for\n * @param weight The function to compute the weight of the collateral – either collateral factor or\n * liquidation threshold. Accepts the address of the vToken and returns the weight as Exp.\n * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n * without calculating accumulated interest.\n * @return snapshot Account liquidity snapshot\n */\n function _getCurrentLiquiditySnapshot(address account, function(VToken) internal view returns (Exp memory) weight)\n internal\n view\n returns (AccountLiquiditySnapshot memory snapshot)\n {\n return _getHypotheticalLiquiditySnapshot(account, VToken(address(0)), 0, 0, weight);\n }\n\n /**\n * @notice Determine what the supply/borrow balances would be if the given amounts were redeemed/borrowed\n * @param vTokenModify The market to hypothetically redeem/borrow in\n * @param account The account to determine liquidity for\n * @param redeemTokens The number of tokens to hypothetically redeem\n * @param borrowAmount The amount of underlying to hypothetically borrow\n * @param weight The function to compute the weight of the collateral – either collateral factor or\n liquidation threshold. Accepts the address of the VToken and returns the weight\n * @dev Note that we calculate the exchangeRateStored for each collateral vToken using stored data,\n * without calculating accumulated interest.\n * @return snapshot Account liquidity snapshot\n */\n function _getHypotheticalLiquiditySnapshot(\n address account,\n VToken vTokenModify,\n uint256 redeemTokens,\n uint256 borrowAmount,\n function(VToken) internal view returns (Exp memory) weight\n ) internal view returns (AccountLiquiditySnapshot memory snapshot) {\n // For each asset the account is in\n VToken[] memory assets = accountAssets[account];\n uint256 assetsCount = assets.length;\n\n for (uint256 i; i < assetsCount; ++i) {\n VToken asset = assets[i];\n\n // Read the balances and exchange rate from the vToken\n (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) = _safeGetAccountSnapshot(\n asset,\n account\n );\n\n // Get the normalized price of the asset\n Exp memory oraclePrice = Exp({ mantissa: _safeGetUnderlyingPrice(asset) });\n\n // Pre-compute conversion factors from vTokens -> usd\n Exp memory vTokenPrice = mul_(Exp({ mantissa: exchangeRateMantissa }), oraclePrice);\n Exp memory weightedVTokenPrice = mul_(weight(asset), vTokenPrice);\n\n // weightedCollateral += weightedVTokenPrice * vTokenBalance\n snapshot.weightedCollateral = mul_ScalarTruncateAddUInt(\n weightedVTokenPrice,\n vTokenBalance,\n snapshot.weightedCollateral\n );\n\n // totalCollateral += vTokenPrice * vTokenBalance\n snapshot.totalCollateral = mul_ScalarTruncateAddUInt(vTokenPrice, vTokenBalance, snapshot.totalCollateral);\n\n // borrows += oraclePrice * borrowBalance\n snapshot.borrows = mul_ScalarTruncateAddUInt(oraclePrice, borrowBalance, snapshot.borrows);\n\n // Calculate effects of interacting with vTokenModify\n if (asset == vTokenModify) {\n // redeem effect\n // effects += tokensToDenom * redeemTokens\n snapshot.effects = mul_ScalarTruncateAddUInt(weightedVTokenPrice, redeemTokens, snapshot.effects);\n\n // borrow effect\n // effects += oraclePrice * borrowAmount\n snapshot.effects = mul_ScalarTruncateAddUInt(oraclePrice, borrowAmount, snapshot.effects);\n }\n }\n\n uint256 borrowPlusEffects = snapshot.borrows + snapshot.effects;\n // These are safe, as the underflow condition is checked first\n unchecked {\n if (snapshot.weightedCollateral > borrowPlusEffects) {\n snapshot.liquidity = snapshot.weightedCollateral - borrowPlusEffects;\n snapshot.shortfall = 0;\n } else {\n snapshot.liquidity = 0;\n snapshot.shortfall = borrowPlusEffects - snapshot.weightedCollateral;\n }\n }\n\n return snapshot;\n }\n\n /**\n * @dev Retrieves price from oracle for an asset and checks it is nonzero\n * @param asset Address for asset to query price\n * @return Underlying price\n */\n function _safeGetUnderlyingPrice(VToken asset) internal view returns (uint256) {\n uint256 oraclePriceMantissa = oracle.getUnderlyingPrice(address(asset));\n if (oraclePriceMantissa == 0) {\n revert PriceError(address(asset));\n }\n return oraclePriceMantissa;\n }\n\n /**\n * @dev Return collateral factor for a market\n * @param asset Address for asset\n * @return Collateral factor as exponential\n */\n function _getCollateralFactor(VToken asset) internal view returns (Exp memory) {\n return Exp({ mantissa: markets[address(asset)].collateralFactorMantissa });\n }\n\n /**\n * @dev Retrieves liquidation threshold for a market as an exponential\n * @param asset Address for asset to liquidation threshold\n * @return Liquidation threshold as exponential\n */\n function _getLiquidationThreshold(VToken asset) internal view returns (Exp memory) {\n return Exp({ mantissa: markets[address(asset)].liquidationThresholdMantissa });\n }\n\n /**\n * @dev Returns supply and borrow balances of user in vToken, reverts on failure\n * @param vToken Market to query\n * @param user Account address\n * @return vTokenBalance Balance of vTokens, the same as vToken.balanceOf(user)\n * @return borrowBalance Borrowed amount, including the interest\n * @return exchangeRateMantissa Stored exchange rate\n */\n function _safeGetAccountSnapshot(VToken vToken, address user)\n internal\n view\n returns (\n uint256 vTokenBalance,\n uint256 borrowBalance,\n uint256 exchangeRateMantissa\n )\n {\n uint256 err;\n (err, vTokenBalance, borrowBalance, exchangeRateMantissa) = vToken.getAccountSnapshot(user);\n if (err != 0) {\n revert SnapshotError(address(vToken), user);\n }\n return (vTokenBalance, borrowBalance, exchangeRateMantissa);\n }\n\n /// @notice Reverts if the call is not from expectedSender\n /// @param expectedSender Expected transaction sender\n function _checkSenderIs(address expectedSender) internal view {\n if (msg.sender != expectedSender) {\n revert UnexpectedSender(expectedSender, msg.sender);\n }\n }\n\n /// @notice Reverts if a certain action is paused on a market\n /// @param market Market to check\n /// @param action Action to check\n function _checkActionPauseState(address market, Action action) private view {\n if (actionPaused(market, action)) {\n revert ActionPaused(market, action);\n }\n }\n}\n" + }, + "contracts/ComptrollerInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\n/**\n * @title ComptrollerInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract.\n */\ninterface ComptrollerInterface {\n /*** Assets You Are In ***/\n\n function enterMarkets(address[] calldata vTokens) external returns (uint256[] memory);\n\n function exitMarket(address vToken) external returns (uint256);\n\n /*** Policy Hooks ***/\n\n function preMintHook(\n address vToken,\n address minter,\n uint256 mintAmount\n ) external;\n\n function preRedeemHook(\n address vToken,\n address redeemer,\n uint256 redeemTokens\n ) external;\n\n function preBorrowHook(\n address vToken,\n address borrower,\n uint256 borrowAmount\n ) external;\n\n function preRepayHook(address vToken, address borrower) external;\n\n function preLiquidateHook(\n address vTokenBorrowed,\n address vTokenCollateral,\n address borrower,\n uint256 repayAmount,\n bool skipLiquidityCheck\n ) external;\n\n function preSeizeHook(\n address vTokenCollateral,\n address vTokenBorrowed,\n address liquidator,\n address borrower\n ) external;\n\n function preTransferHook(\n address vToken,\n address src,\n address dst,\n uint256 transferTokens\n ) external;\n\n function isComptroller() external view returns (bool);\n\n /*** Liquidity/Liquidation Calculations ***/\n\n function liquidateCalculateSeizeTokens(\n address vTokenBorrowed,\n address vTokenCollateral,\n uint256 repayAmount\n ) external view returns (uint256, uint256);\n\n function getAllMarkets() external view returns (VToken[] memory);\n}\n\n/**\n * @title ComptrollerViewInterface\n * @author Venus\n * @notice Interface implemented by the `Comptroller` contract, including only some util view functions.\n */\ninterface ComptrollerViewInterface {\n function markets(address) external view returns (bool, uint256);\n\n function oracle() external view returns (ResilientOracleInterface);\n\n function getAssetsIn(address) external view returns (VToken[] memory);\n\n function closeFactorMantissa() external view returns (uint256);\n\n function liquidationIncentiveMantissa() external view returns (uint256);\n\n function minLiquidatableCollateral() external view returns (uint256);\n\n function getRewardDistributors() external view returns (RewardsDistributor[] memory);\n\n function getAllMarkets() external view returns (VToken[] memory);\n\n function borrowCaps(address) external view returns (uint256);\n\n function supplyCaps(address) external view returns (uint256);\n}\n" + }, + "contracts/ComptrollerStorage.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { VToken } from \"./VToken.sol\";\nimport { RewardsDistributor } from \"./Rewards/RewardsDistributor.sol\";\n\n/**\n * @title ComptrollerStorage\n * @author Venus\n * @notice Storage layout for the `Comptroller` contract.\n */\ncontract ComptrollerStorage {\n struct LiquidationOrder {\n VToken vTokenCollateral;\n VToken vTokenBorrowed;\n uint256 repayAmount;\n }\n\n struct AccountLiquiditySnapshot {\n uint256 totalCollateral;\n uint256 weightedCollateral;\n uint256 borrows;\n uint256 effects;\n uint256 liquidity;\n uint256 shortfall;\n }\n\n struct RewardSpeeds {\n address rewardToken;\n uint256 supplySpeed;\n uint256 borrowSpeed;\n }\n\n struct Market {\n // Whether or not this market is listed\n bool isListed;\n // Multiplier representing the most one can borrow against their collateral in this market.\n // For instance, 0.9 to allow borrowing 90% of collateral value.\n // Must be between 0 and 1, and stored as a mantissa.\n uint256 collateralFactorMantissa;\n // Multiplier representing the collateralization after which the borrow is eligible\n // for liquidation. For instance, 0.8 liquidate when the borrow is 80% of collateral\n // value. Must be between 0 and collateral factor, stored as a mantissa.\n uint256 liquidationThresholdMantissa;\n // Per-market mapping of \"accounts in this asset\"\n mapping(address => bool) accountMembership;\n }\n\n enum Action {\n MINT,\n REDEEM,\n BORROW,\n REPAY,\n SEIZE,\n LIQUIDATE,\n TRANSFER,\n ENTER_MARKET,\n EXIT_MARKET\n }\n\n /**\n * @notice Oracle which gives the price of any given asset\n */\n ResilientOracleInterface public oracle;\n\n /**\n * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow\n */\n uint256 public closeFactorMantissa;\n\n /**\n * @notice Multiplier representing the discount on collateral that a liquidator receives\n */\n uint256 public liquidationIncentiveMantissa;\n\n /**\n * @notice Per-account mapping of \"assets you are in\"\n */\n mapping(address => VToken[]) public accountAssets;\n\n /**\n * @notice Official mapping of vTokens -> Market metadata\n * @dev Used e.g. to determine if a market is supported\n */\n mapping(address => Market) public markets;\n\n /// @notice A list of all markets\n VToken[] public allMarkets;\n\n /// @notice Borrow caps enforced by borrowAllowed for each vToken address. Defaults to zero which restricts borrowing.\n mapping(address => uint256) public borrowCaps;\n\n /// @notice Minimal collateral required for regular (non-batch) liquidations\n uint256 public minLiquidatableCollateral;\n\n /// @notice Supply caps enforced by mintAllowed for each vToken address. Defaults to zero which corresponds to minting not allowed\n mapping(address => uint256) public supplyCaps;\n\n /// @notice True if a certain action is paused on a certain market\n mapping(address => mapping(Action => bool)) internal _actionPaused;\n\n // List of Reward Distributors added\n RewardsDistributor[] internal rewardsDistributors;\n\n // Used to check if rewards distributor is added\n mapping(address => bool) internal rewardsDistributorExists;\n\n uint256 internal constant NO_ERROR = 0;\n\n // closeFactorMantissa must be strictly greater than this value\n uint256 internal constant MIN_CLOSE_FACTOR_MANTISSA = 0.05e18; // 0.05\n\n // closeFactorMantissa must not exceed this value\n uint256 internal constant MAX_CLOSE_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n // No collateralFactorMantissa may exceed this value\n uint256 internal constant MAX_COLLATERAL_FACTOR_MANTISSA = 0.9e18; // 0.9\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "contracts/ErrorReporter.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title TokenErrorReporter\n * @author Venus\n * @notice Errors that can be thrown by the `VToken` contract.\n */\ncontract TokenErrorReporter {\n uint256 public constant NO_ERROR = 0; // support legacy return codes\n\n error TransferNotAllowed();\n\n error MintFreshnessCheck();\n\n error RedeemFreshnessCheck();\n error RedeemTransferOutNotPossible();\n\n error BorrowFreshnessCheck();\n error BorrowCashNotAvailable();\n\n error RepayBorrowFreshnessCheck();\n\n error HealBorrowUnauthorized();\n error ForceLiquidateBorrowUnauthorized();\n\n error LiquidateFreshnessCheck();\n error LiquidateCollateralFreshnessCheck();\n error LiquidateAccrueCollateralInterestFailed(uint256 errorCode);\n error LiquidateLiquidatorIsBorrower();\n error LiquidateCloseAmountIsZero();\n error LiquidateCloseAmountIsUintMax();\n\n error LiquidateSeizeLiquidatorIsBorrower();\n\n error ProtocolSeizeShareTooBig();\n\n error SetReserveFactorFreshCheck();\n error SetReserveFactorBoundsCheck();\n\n error AddReservesFactorFreshCheck(uint256 actualAddAmount);\n\n error ReduceReservesFreshCheck();\n error ReduceReservesCashNotAvailable();\n error ReduceReservesCashValidation();\n\n error SetInterestRateModelFreshCheck();\n}\n" + }, + "contracts/ExponentialNoError.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { EXP_SCALE as EXP_SCALE_, MANTISSA_ONE as MANTISSA_ONE_ } from \"./lib/constants.sol\";\n\n/**\n * @title Exponential module for storing fixed-precision decimals\n * @author Compound\n * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.\n * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:\n * `Exp({mantissa: 5100000000000000000})`.\n */\ncontract ExponentialNoError {\n struct Exp {\n uint256 mantissa;\n }\n\n struct Double {\n uint256 mantissa;\n }\n\n uint256 internal constant EXP_SCALE = EXP_SCALE_;\n uint256 internal constant DOUBLE_SCALE = 1e36;\n uint256 internal constant HALF_EXP_SCALE = EXP_SCALE / 2;\n uint256 internal constant MANTISSA_ONE = MANTISSA_ONE_;\n\n /**\n * @dev Truncates the given exp to a whole number value.\n * For example, truncate(Exp{mantissa: 15 * EXP_SCALE}) = 15\n */\n function truncate(Exp memory exp) internal pure returns (uint256) {\n // Note: We are not using careful math here as we're performing a division that cannot fail\n return exp.mantissa / EXP_SCALE;\n }\n\n /**\n * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.\n */\n // solhint-disable-next-line func-name-mixedcase\n function mul_ScalarTruncate(Exp memory a, uint256 scalar) internal pure returns (uint256) {\n Exp memory product = mul_(a, scalar);\n return truncate(product);\n }\n\n /**\n * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.\n */\n // solhint-disable-next-line func-name-mixedcase\n function mul_ScalarTruncateAddUInt(\n Exp memory a,\n uint256 scalar,\n uint256 addend\n ) internal pure returns (uint256) {\n Exp memory product = mul_(a, scalar);\n return add_(truncate(product), addend);\n }\n\n /**\n * @dev Checks if first Exp is less than second Exp.\n */\n function lessThanExp(Exp memory left, Exp memory right) internal pure returns (bool) {\n return left.mantissa < right.mantissa;\n }\n\n function safe224(uint256 n, string memory errorMessage) internal pure returns (uint224) {\n require(n <= type(uint224).max, errorMessage);\n return uint224(n);\n }\n\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n <= type(uint32).max, errorMessage);\n return uint32(n);\n }\n\n function add_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: add_(a.mantissa, b.mantissa) });\n }\n\n function add_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: add_(a.mantissa, b.mantissa) });\n }\n\n function add_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a + b;\n }\n\n function sub_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: sub_(a.mantissa, b.mantissa) });\n }\n\n function sub_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: sub_(a.mantissa, b.mantissa) });\n }\n\n function sub_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a - b;\n }\n\n function mul_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: mul_(a.mantissa, b.mantissa) / EXP_SCALE });\n }\n\n function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n return Exp({ mantissa: mul_(a.mantissa, b) });\n }\n\n function mul_(uint256 a, Exp memory b) internal pure returns (uint256) {\n return mul_(a, b.mantissa) / EXP_SCALE;\n }\n\n function mul_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: mul_(a.mantissa, b.mantissa) / DOUBLE_SCALE });\n }\n\n function mul_(Double memory a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: mul_(a.mantissa, b) });\n }\n\n function mul_(uint256 a, Double memory b) internal pure returns (uint256) {\n return mul_(a, b.mantissa) / DOUBLE_SCALE;\n }\n\n function mul_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a * b;\n }\n\n function div_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {\n return Exp({ mantissa: div_(mul_(a.mantissa, EXP_SCALE), b.mantissa) });\n }\n\n function div_(Exp memory a, uint256 b) internal pure returns (Exp memory) {\n return Exp({ mantissa: div_(a.mantissa, b) });\n }\n\n function div_(uint256 a, Exp memory b) internal pure returns (uint256) {\n return div_(mul_(a, EXP_SCALE), b.mantissa);\n }\n\n function div_(Double memory a, Double memory b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(mul_(a.mantissa, DOUBLE_SCALE), b.mantissa) });\n }\n\n function div_(Double memory a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(a.mantissa, b) });\n }\n\n function div_(uint256 a, Double memory b) internal pure returns (uint256) {\n return div_(mul_(a, DOUBLE_SCALE), b.mantissa);\n }\n\n function div_(uint256 a, uint256 b) internal pure returns (uint256) {\n return a / b;\n }\n\n function fraction(uint256 a, uint256 b) internal pure returns (Double memory) {\n return Double({ mantissa: div_(mul_(a, DOUBLE_SCALE), b) });\n }\n}\n" + }, + "contracts/InterestRateModel.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title Compound's InterestRateModel Interface\n * @author Compound\n */\nabstract contract InterestRateModel {\n /**\n * @notice Calculates the current borrow interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate per block (as a percentage, and scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) external view virtual returns (uint256);\n\n /**\n * @notice Calculates the current supply interest rate per block\n * @param cash The total amount of cash the market has\n * @param borrows The total amount of borrows the market has outstanding\n * @param reserves The total amount of reserves the market has\n * @param reserveFactorMantissa The current reserve factor the market has\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate per block (as a percentage, and scaled by 1e18)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) external view virtual returns (uint256);\n\n /**\n * @notice Indicator that this is an InterestRateModel contract (for inspection)\n * @return Always true\n */\n function isInterestRateModel() external pure virtual returns (bool) {\n return true;\n }\n}\n" + }, + "contracts/IPancakeswapV2Router.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\ninterface IPancakeswapV2Router {\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n}\n" + }, + "contracts/JumpRateModelV2.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IAccessControlManagerV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/IAccessControlManagerV8.sol\";\n\nimport { BaseJumpRateModelV2 } from \"./BaseJumpRateModelV2.sol\";\n\n/**\n * @title Compound's JumpRateModel Contract V2 for V2 vTokens\n * @author Arr00\n * @notice Supports only for V2 vTokens\n */\ncontract JumpRateModelV2 is BaseJumpRateModelV2 {\n constructor(\n uint256 baseRatePerYear,\n uint256 multiplierPerYear,\n uint256 jumpMultiplierPerYear,\n uint256 kink_,\n IAccessControlManagerV8 accessControlManager_\n )\n BaseJumpRateModelV2(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_, accessControlManager_)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n /**\n * @notice Calculates the current borrow rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by 1e18)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) external view override returns (uint256) {\n return _getBorrowRate(cash, borrows, reserves, badDebt);\n }\n}\n" + }, + "contracts/Lens/PoolLens.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { RewardsDistributor } from \"../Rewards/RewardsDistributor.sol\";\n\n/**\n * @title PoolLens\n * @author Venus\n * @notice The `PoolLens` contract is designed to retrieve important information for each registered pool. A list of essential information\n * for all pools within the lending protocol can be acquired through the function `getAllPools()`. Additionally, the following records can be\n * looked up for specific pools and markets:\n- the vToken balance of a given user;\n- the pool data (oracle address, associated vToken, liquidation incentive, etc) of a pool via its associated comptroller address;\n- the vToken address in a pool for a given asset;\n- a list of all pools that support an asset;\n- the underlying asset price of a vToken;\n- the metadata (exchange/borrow/supply rate, total supply, collateral factor, etc) of any vToken.\n */\ncontract PoolLens is ExponentialNoError {\n /**\n * @dev Struct for PoolDetails.\n */\n struct PoolData {\n string name;\n address creator;\n address comptroller;\n uint256 blockPosted;\n uint256 timestampPosted;\n string category;\n string logoURL;\n string description;\n address priceOracle;\n uint256 closeFactor;\n uint256 liquidationIncentive;\n uint256 minLiquidatableCollateral;\n VTokenMetadata[] vTokens;\n }\n\n /**\n * @dev Struct for VToken.\n */\n struct VTokenMetadata {\n address vToken;\n uint256 exchangeRateCurrent;\n uint256 supplyRatePerBlock;\n uint256 borrowRatePerBlock;\n uint256 reserveFactorMantissa;\n uint256 supplyCaps;\n uint256 borrowCaps;\n uint256 totalBorrows;\n uint256 totalReserves;\n uint256 totalSupply;\n uint256 totalCash;\n bool isListed;\n uint256 collateralFactorMantissa;\n address underlyingAssetAddress;\n uint256 vTokenDecimals;\n uint256 underlyingDecimals;\n }\n\n /**\n * @dev Struct for VTokenBalance.\n */\n struct VTokenBalances {\n address vToken;\n uint256 balanceOf;\n uint256 borrowBalanceCurrent;\n uint256 balanceOfUnderlying;\n uint256 tokenBalance;\n uint256 tokenAllowance;\n }\n\n /**\n * @dev Struct for underlyingPrice of VToken.\n */\n struct VTokenUnderlyingPrice {\n address vToken;\n uint256 underlyingPrice;\n }\n\n /**\n * @dev Struct with pending reward info for a market.\n */\n struct PendingReward {\n address vTokenAddress;\n uint256 amount;\n }\n\n /**\n * @dev Struct with reward distribution totals for a single reward token and distributor.\n */\n struct RewardSummary {\n address distributorAddress;\n address rewardTokenAddress;\n uint256 totalRewards;\n PendingReward[] pendingRewards;\n }\n\n /**\n * @dev Struct used in RewardDistributor to save last updated market state.\n */\n struct RewardTokenState {\n // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n uint224 index;\n // The block number the index was last updated at\n uint32 block;\n // The block number at which to stop rewards\n uint32 lastRewardingBlock;\n }\n\n /**\n * @dev Struct with bad debt of a market denominated\n */\n struct BadDebt {\n address vTokenAddress;\n uint256 badDebtUsd;\n }\n\n /**\n * @dev Struct with bad debt total denominated in usd for a pool and an array of BadDebt structs for each market\n */\n struct BadDebtSummary {\n address comptroller;\n uint256 totalBadDebtUsd;\n BadDebt[] badDebts;\n }\n\n /**\n * @notice Queries the user's supply/borrow balances in vTokens\n * @param vTokens The list of vToken addresses\n * @param account The user Account\n * @return A list of structs containing balances data\n */\n function vTokenBalancesAll(VToken[] calldata vTokens, address account) external returns (VTokenBalances[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenBalances[] memory res = new VTokenBalances[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenBalances(vTokens[i], account);\n }\n return res;\n }\n\n /**\n * @notice Queries all pools with addtional details for each of them\n * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @return Arrays of all Venus pools' data\n */\n function getAllPools(address poolRegistryAddress) external view returns (PoolData[] memory) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n PoolRegistry.VenusPool[] memory venusPools = poolRegistryInterface.getAllPools();\n uint256 poolLength = venusPools.length;\n\n PoolData[] memory poolDataItems = new PoolData[](poolLength);\n\n for (uint256 i; i < poolLength; ++i) {\n PoolRegistry.VenusPool memory venusPool = venusPools[i];\n PoolData memory poolData = getPoolDataFromVenusPool(poolRegistryAddress, venusPool);\n poolDataItems[i] = poolData;\n }\n\n return poolDataItems;\n }\n\n /**\n * @notice Queries the details of a pool identified by Comptroller address\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param comptroller The Comptroller implementation address\n * @return PoolData structure containing the details of the pool\n */\n function getPoolByComptroller(address poolRegistryAddress, address comptroller)\n external\n view\n returns (PoolData memory)\n {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return getPoolDataFromVenusPool(poolRegistryAddress, poolRegistryInterface.getPoolByComptroller(comptroller));\n }\n\n /**\n * @notice Returns vToken holding the specified underlying asset in the specified pool\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param comptroller The pool comptroller\n * @param asset The underlyingAsset of VToken\n * @return Address of the vToken\n */\n function getVTokenForAsset(\n address poolRegistryAddress,\n address comptroller,\n address asset\n ) external view returns (address) {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return poolRegistryInterface.getVTokenForAsset(comptroller, asset);\n }\n\n /**\n * @notice Returns all pools that support the specified underlying asset\n * @param poolRegistryAddress The address of the PoolRegistry contract\n * @param asset The underlying asset of vToken\n * @return A list of Comptroller contracts\n */\n function getPoolsSupportedByAsset(address poolRegistryAddress, address asset)\n external\n view\n returns (address[] memory)\n {\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n return poolRegistryInterface.getPoolsSupportedByAsset(asset);\n }\n\n /**\n * @notice Returns the price data for the underlying assets of the specified vTokens\n * @param vTokens The list of vToken addresses\n * @return An array containing the price data for each asset\n */\n function vTokenUnderlyingPriceAll(VToken[] calldata vTokens)\n external\n view\n returns (VTokenUnderlyingPrice[] memory)\n {\n uint256 vTokenCount = vTokens.length;\n VTokenUnderlyingPrice[] memory res = new VTokenUnderlyingPrice[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenUnderlyingPrice(vTokens[i]);\n }\n return res;\n }\n\n /**\n * @notice Returns the pending rewards for a user for a given pool.\n * @param account The user account.\n * @param comptrollerAddress address\n * @return Pending rewards array\n */\n function getPendingRewards(address account, address comptrollerAddress)\n external\n view\n returns (RewardSummary[] memory)\n {\n VToken[] memory markets = ComptrollerInterface(comptrollerAddress).getAllMarkets();\n RewardsDistributor[] memory rewardsDistributors = ComptrollerViewInterface(comptrollerAddress)\n .getRewardDistributors();\n RewardSummary[] memory rewardSummary = new RewardSummary[](rewardsDistributors.length);\n for (uint256 i; i < rewardsDistributors.length; ++i) {\n RewardSummary memory reward;\n reward.distributorAddress = address(rewardsDistributors[i]);\n reward.rewardTokenAddress = address(rewardsDistributors[i].rewardToken());\n reward.totalRewards = rewardsDistributors[i].rewardTokenAccrued(account);\n reward.pendingRewards = _calculateNotDistributedAwards(account, markets, rewardsDistributors[i]);\n rewardSummary[i] = reward;\n }\n return rewardSummary;\n }\n\n /**\n * @notice Returns a summary of a pool's bad debt broken down by market\n *\n * @param comptrollerAddress Address of the comptroller\n *\n * @return badDebtSummary A struct with comptroller address, total bad debut denominated in usd, and\n * a break down of bad debt by market\n */\n function getPoolBadDebt(address comptrollerAddress) external view returns (BadDebtSummary memory) {\n uint256 totalBadDebtUsd;\n\n // Get every market in the pool\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n VToken[] memory markets = comptroller.getAllMarkets();\n ResilientOracleInterface priceOracle = comptroller.oracle();\n\n BadDebt[] memory badDebts = new BadDebt[](markets.length);\n\n BadDebtSummary memory badDebtSummary;\n badDebtSummary.comptroller = comptrollerAddress;\n badDebtSummary.badDebts = badDebts;\n\n // // Calculate the bad debt is USD per market\n for (uint256 i; i < markets.length; ++i) {\n BadDebt memory badDebt;\n badDebt.vTokenAddress = address(markets[i]);\n badDebt.badDebtUsd =\n (VToken(address(markets[i])).badDebt() * priceOracle.getUnderlyingPrice(address(markets[i]))) /\n EXP_SCALE;\n badDebtSummary.badDebts[i] = badDebt;\n totalBadDebtUsd = totalBadDebtUsd + badDebt.badDebtUsd;\n }\n\n badDebtSummary.totalBadDebtUsd = totalBadDebtUsd;\n\n return badDebtSummary;\n }\n\n /**\n * @notice Queries the user's supply/borrow balances in the specified vToken\n * @param vToken vToken address\n * @param account The user Account\n * @return A struct containing the balances data\n */\n function vTokenBalances(VToken vToken, address account) public returns (VTokenBalances memory) {\n uint256 balanceOf = vToken.balanceOf(account);\n uint256 borrowBalanceCurrent = vToken.borrowBalanceCurrent(account);\n uint256 balanceOfUnderlying = vToken.balanceOfUnderlying(account);\n uint256 tokenBalance;\n uint256 tokenAllowance;\n\n IERC20 underlying = IERC20(vToken.underlying());\n tokenBalance = underlying.balanceOf(account);\n tokenAllowance = underlying.allowance(account, address(vToken));\n\n return\n VTokenBalances({\n vToken: address(vToken),\n balanceOf: balanceOf,\n borrowBalanceCurrent: borrowBalanceCurrent,\n balanceOfUnderlying: balanceOfUnderlying,\n tokenBalance: tokenBalance,\n tokenAllowance: tokenAllowance\n });\n }\n\n /**\n * @notice Queries additional information for the pool\n * @param poolRegistryAddress Address of the PoolRegistry\n * @param venusPool The VenusPool Object from PoolRegistry\n * @return Enriched PoolData\n */\n function getPoolDataFromVenusPool(address poolRegistryAddress, PoolRegistry.VenusPool memory venusPool)\n public\n view\n returns (PoolData memory)\n {\n // Get tokens in the Pool\n ComptrollerInterface comptrollerInstance = ComptrollerInterface(venusPool.comptroller);\n\n VToken[] memory vTokens = comptrollerInstance.getAllMarkets();\n\n VTokenMetadata[] memory vTokenMetadataItems = vTokenMetadataAll(vTokens);\n\n PoolRegistryInterface poolRegistryInterface = PoolRegistryInterface(poolRegistryAddress);\n\n PoolRegistry.VenusPoolMetaData memory venusPoolMetaData = poolRegistryInterface.getVenusPoolMetadata(\n venusPool.comptroller\n );\n\n ComptrollerViewInterface comptrollerViewInstance = ComptrollerViewInterface(venusPool.comptroller);\n\n PoolData memory poolData = PoolData({\n name: venusPool.name,\n creator: venusPool.creator,\n comptroller: venusPool.comptroller,\n blockPosted: venusPool.blockPosted,\n timestampPosted: venusPool.timestampPosted,\n category: venusPoolMetaData.category,\n logoURL: venusPoolMetaData.logoURL,\n description: venusPoolMetaData.description,\n vTokens: vTokenMetadataItems,\n priceOracle: address(comptrollerViewInstance.oracle()),\n closeFactor: comptrollerViewInstance.closeFactorMantissa(),\n liquidationIncentive: comptrollerViewInstance.liquidationIncentiveMantissa(),\n minLiquidatableCollateral: comptrollerViewInstance.minLiquidatableCollateral()\n });\n\n return poolData;\n }\n\n /**\n * @notice Returns the metadata of VToken\n * @param vToken The address of vToken\n * @return VTokenMetadata struct\n */\n function vTokenMetadata(VToken vToken) public view returns (VTokenMetadata memory) {\n uint256 exchangeRateCurrent = vToken.exchangeRateStored();\n address comptrollerAddress = address(vToken.comptroller());\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(comptrollerAddress);\n (bool isListed, uint256 collateralFactorMantissa) = comptroller.markets(address(vToken));\n\n address underlyingAssetAddress = vToken.underlying();\n uint256 underlyingDecimals = IERC20Metadata(underlyingAssetAddress).decimals();\n\n return\n VTokenMetadata({\n vToken: address(vToken),\n exchangeRateCurrent: exchangeRateCurrent,\n supplyRatePerBlock: vToken.supplyRatePerBlock(),\n borrowRatePerBlock: vToken.borrowRatePerBlock(),\n reserveFactorMantissa: vToken.reserveFactorMantissa(),\n supplyCaps: comptroller.supplyCaps(address(vToken)),\n borrowCaps: comptroller.borrowCaps(address(vToken)),\n totalBorrows: vToken.totalBorrows(),\n totalReserves: vToken.totalReserves(),\n totalSupply: vToken.totalSupply(),\n totalCash: vToken.getCash(),\n isListed: isListed,\n collateralFactorMantissa: collateralFactorMantissa,\n underlyingAssetAddress: underlyingAssetAddress,\n vTokenDecimals: vToken.decimals(),\n underlyingDecimals: underlyingDecimals\n });\n }\n\n /**\n * @notice Returns the metadata of all VTokens\n * @param vTokens The list of vToken addresses\n * @return An array of VTokenMetadata structs\n */\n function vTokenMetadataAll(VToken[] memory vTokens) public view returns (VTokenMetadata[] memory) {\n uint256 vTokenCount = vTokens.length;\n VTokenMetadata[] memory res = new VTokenMetadata[](vTokenCount);\n for (uint256 i; i < vTokenCount; ++i) {\n res[i] = vTokenMetadata(vTokens[i]);\n }\n return res;\n }\n\n /**\n * @notice Returns the price data for the underlying asset of the specified vToken\n * @param vToken vToken address\n * @return The price data for each asset\n */\n function vTokenUnderlyingPrice(VToken vToken) public view returns (VTokenUnderlyingPrice memory) {\n ComptrollerViewInterface comptroller = ComptrollerViewInterface(address(vToken.comptroller()));\n ResilientOracleInterface priceOracle = comptroller.oracle();\n\n return\n VTokenUnderlyingPrice({\n vToken: address(vToken),\n underlyingPrice: priceOracle.getUnderlyingPrice(address(vToken))\n });\n }\n\n function _calculateNotDistributedAwards(\n address account,\n VToken[] memory markets,\n RewardsDistributor rewardsDistributor\n ) internal view returns (PendingReward[] memory) {\n PendingReward[] memory pendingRewards = new PendingReward[](markets.length);\n for (uint256 i; i < markets.length; ++i) {\n // Market borrow and supply state we will modify update in-memory, in order to not modify storage\n RewardTokenState memory borrowState;\n (borrowState.index, borrowState.block, borrowState.lastRewardingBlock) = rewardsDistributor\n .rewardTokenBorrowState(address(markets[i]));\n RewardTokenState memory supplyState;\n (supplyState.index, supplyState.block, supplyState.lastRewardingBlock) = rewardsDistributor\n .rewardTokenSupplyState(address(markets[i]));\n Exp memory marketBorrowIndex = Exp({ mantissa: markets[i].borrowIndex() });\n\n // Update market supply and borrow index in-memory\n updateMarketBorrowIndex(address(markets[i]), rewardsDistributor, borrowState, marketBorrowIndex);\n updateMarketSupplyIndex(address(markets[i]), rewardsDistributor, supplyState);\n\n // Calculate pending rewards\n uint256 borrowReward = calculateBorrowerReward(\n address(markets[i]),\n rewardsDistributor,\n account,\n borrowState,\n marketBorrowIndex\n );\n uint256 supplyReward = calculateSupplierReward(\n address(markets[i]),\n rewardsDistributor,\n account,\n supplyState\n );\n\n PendingReward memory pendingReward;\n pendingReward.vTokenAddress = address(markets[i]);\n pendingReward.amount = borrowReward + supplyReward;\n pendingRewards[i] = pendingReward;\n }\n return pendingRewards;\n }\n\n function updateMarketBorrowIndex(\n address vToken,\n RewardsDistributor rewardsDistributor,\n RewardTokenState memory borrowState,\n Exp memory marketBorrowIndex\n ) internal view {\n uint256 borrowSpeed = rewardsDistributor.rewardTokenBorrowSpeeds(vToken);\n uint256 blockNumber = block.number;\n\n if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n blockNumber = borrowState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(blockNumber, uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n // Remove the total earned interest rate since the opening of the market from total borrows\n uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n uint256 tokensAccrued = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0 ? fraction(tokensAccrued, borrowAmount) : Double({ mantissa: 0 });\n Double memory index = add_(Double({ mantissa: borrowState.index }), ratio);\n borrowState.index = safe224(index.mantissa, \"new index overflows\");\n borrowState.block = safe32(blockNumber, \"block number overflows\");\n } else if (deltaBlocks > 0) {\n borrowState.block = safe32(blockNumber, \"block number overflows\");\n }\n }\n\n function updateMarketSupplyIndex(\n address vToken,\n RewardsDistributor rewardsDistributor,\n RewardTokenState memory supplyState\n ) internal view {\n uint256 supplySpeed = rewardsDistributor.rewardTokenSupplySpeeds(vToken);\n uint256 blockNumber = block.number;\n\n if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n blockNumber = supplyState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(blockNumber, uint256(supplyState.block));\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = VToken(vToken).totalSupply();\n uint256 tokensAccrued = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0 ? fraction(tokensAccrued, supplyTokens) : Double({ mantissa: 0 });\n Double memory index = add_(Double({ mantissa: supplyState.index }), ratio);\n supplyState.index = safe224(index.mantissa, \"new index overflows\");\n supplyState.block = safe32(blockNumber, \"block number overflows\");\n } else if (deltaBlocks > 0) {\n supplyState.block = safe32(blockNumber, \"block number overflows\");\n }\n }\n\n function calculateBorrowerReward(\n address vToken,\n RewardsDistributor rewardsDistributor,\n address borrower,\n RewardTokenState memory borrowState,\n Exp memory marketBorrowIndex\n ) internal view returns (uint256) {\n Double memory borrowIndex = Double({ mantissa: borrowState.index });\n Double memory borrowerIndex = Double({\n mantissa: rewardsDistributor.rewardTokenBorrowerIndex(vToken, borrower)\n });\n if (borrowerIndex.mantissa == 0 && borrowIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n // Covers the case where users borrowed tokens before the market's borrow state index was set\n borrowerIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n }\n Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);\n uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n return borrowerDelta;\n }\n\n function calculateSupplierReward(\n address vToken,\n RewardsDistributor rewardsDistributor,\n address supplier,\n RewardTokenState memory supplyState\n ) internal view returns (uint256) {\n Double memory supplyIndex = Double({ mantissa: supplyState.index });\n Double memory supplierIndex = Double({\n mantissa: rewardsDistributor.rewardTokenSupplierIndex(vToken, supplier)\n });\n if (supplierIndex.mantissa == 0 && supplyIndex.mantissa >= rewardsDistributor.INITIAL_INDEX()) {\n // Covers the case where users supplied tokens before the market's supply state index was set\n supplierIndex.mantissa = rewardsDistributor.INITIAL_INDEX();\n }\n Double memory deltaIndex = sub_(supplyIndex, supplierIndex);\n uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n return supplierDelta;\n }\n}\n" + }, + "contracts/lib/ApproveOrRevert.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\n\nlibrary ApproveOrRevert {\n /// @notice Thrown if a contract is unable to approve a transfer\n error ApproveFailed();\n\n /// @notice Approves a transfer, ensuring that it is successful. This function supports non-compliant\n /// tokens like the ones that don't return a boolean value on success. Thus, such approve call supports\n /// three different kinds of tokens:\n /// * Compliant tokens that revert on failure\n /// * Compliant tokens that return false on failure\n /// * Non-compliant tokens that don't return a value\n /// @param token The contract address of the token which will be transferred\n /// @param spender The spender contract address\n /// @param amount The value of the transfer\n function approveOrRevert(\n IERC20Upgradeable token,\n address spender,\n uint256 amount\n ) internal {\n bytes memory callData = abi.encodeCall(token.approve, (spender, amount));\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory result) = address(token).call(callData);\n\n if (!success || (result.length != 0 && !abi.decode(result, (bool)))) {\n revert ApproveFailed();\n }\n }\n}\n" + }, + "contracts/lib/constants.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/// @dev The approximate number of blocks per year that is assumed by the interest rate model\nuint256 constant BLOCKS_PER_YEAR = 10_512_000;\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" + }, + "contracts/lib/imports.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n// This file is needed to make hardhat and typechain generate artifacts for\n// contracts we depend on (e.g. in tests or deployments) but not use directly.\n// Another way to do this would be to use hardhat-dependency-compiler, but\n// since we only have a couple of dependencies, installing a separate package\n// seems an overhead.\n\nimport { UpgradeableBeacon } from \"@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol\";\nimport { BeaconProxy } from \"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\";\n" + }, + "contracts/lib/TokenDebtTracker.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\n/**\n * @title TokenDebtTracker\n * @author Venus\n * @notice TokenDebtTracker is an abstract contract that handles transfers _out_ of the inheriting contract.\n * If there is an error transferring out (due to any reason, e.g. the token contract restricted the user from\n * receiving incoming transfers), the amount is recorded as a debt that can be claimed later.\n * @dev Note that the inheriting contract keeps some amount of users' tokens on its balance, so be careful when\n * using balanceOf(address(this))!\n */\nabstract contract TokenDebtTracker is Initializable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /**\n * @notice Mapping (IERC20Upgradeable token => (address user => uint256 amount)).\n * Tracks failed transfers: when a token transfer fails, we record the\n * amount of the transfer, so that the user can redeem this debt later.\n */\n mapping(IERC20Upgradeable => mapping(address => uint256)) public tokenDebt;\n\n /**\n * @notice Mapping (IERC20Upgradeable token => uint256 amount) shows how many\n * tokens the contract owes to all users. This is useful for accounting to\n * understand how much of balanceOf(address(this)) is already owed to users.\n */\n mapping(IERC20Upgradeable => uint256) public totalTokenDebt;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[48] private __gap;\n\n /**\n * @notice Emitted when the contract's debt to the user is increased due to a failed transfer\n * @param token Token address\n * @param user User address\n * @param amount The amount of debt added\n */\n event TokenDebtAdded(address indexed token, address indexed user, uint256 amount);\n\n /**\n * @notice Emitted when a user claims tokens that the contract owes them\n * @param token Token address\n * @param user User address\n * @param amount The amount transferred\n */\n event TokenDebtClaimed(address indexed token, address indexed user, uint256 amount);\n\n /**\n * @notice Thrown if the user tries to claim more tokens than they are owed\n * @param token The token the user is trying to claim\n * @param owedAmount The amount of tokens the contract owes to the user\n * @param amount The amount of tokens the user is trying to claim\n */\n error InsufficientDebt(address token, address user, uint256 owedAmount, uint256 amount);\n\n /**\n * @notice Thrown if trying to transfer more tokens than the contract currently has\n * @param token The token the contract is trying to transfer\n * @param recipient The recipient of the transfer\n * @param amount The amount of tokens the contract is trying to transfer\n * @param availableBalance The amount of tokens the contract currently has\n */\n error InsufficientBalance(address token, address recipient, uint256 amount, uint256 availableBalance);\n\n /**\n * @notice Transfers the tokens we owe to msg.sender, if any\n * @param token The token to claim\n * @param amount_ The amount of tokens to claim (or max uint256 to claim all)\n * @custom:error InsufficientDebt The contract doesn't have enough debt to the user\n */\n function claimTokenDebt(IERC20Upgradeable token, uint256 amount_) external {\n uint256 owedAmount = tokenDebt[token][msg.sender];\n uint256 amount = (amount_ == type(uint256).max ? owedAmount : amount_);\n if (amount > owedAmount) {\n revert InsufficientDebt(address(token), msg.sender, owedAmount, amount);\n }\n unchecked {\n // Safe because we revert if amount > owedAmount above\n tokenDebt[token][msg.sender] = owedAmount - amount;\n }\n totalTokenDebt[token] -= amount;\n emit TokenDebtClaimed(address(token), msg.sender, amount);\n token.safeTransfer(msg.sender, amount);\n }\n\n // solhint-disable-next-line func-name-mixedcase\n function __TokenDebtTracker_init() internal onlyInitializing {\n __TokenDebtTracker_init_unchained();\n }\n\n // solhint-disable-next-line func-name-mixedcase, no-empty-blocks\n function __TokenDebtTracker_init_unchained() internal onlyInitializing {}\n\n /**\n * @dev Transfers tokens to the recipient if the contract has enough balance, or\n * records the debt if the transfer fails due to reasons unrelated to the contract's\n * balance (e.g. if the token forbids transfers to the recipient).\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n * @custom:error InsufficientBalance The contract doesn't have enough balance to transfer\n */\n function _transferOutOrTrackDebt(\n IERC20Upgradeable token,\n address to,\n uint256 amount\n ) internal {\n uint256 balance = token.balanceOf(address(this));\n if (balance < amount) {\n revert InsufficientBalance(address(token), address(this), amount, balance);\n }\n _transferOutOrTrackDebtSkippingBalanceCheck(token, to, amount);\n }\n\n /**\n * @dev Transfers tokens to the recipient, or records the debt if the transfer fails\n * due to any reason, including insufficient balance.\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n */\n function _transferOutOrTrackDebtSkippingBalanceCheck(\n IERC20Upgradeable token,\n address to,\n uint256 amount\n ) internal {\n // We can't use safeTransfer here because we can't try-catch internal calls\n bool success = _tryTransferOut(token, to, amount);\n if (!success) {\n tokenDebt[token][to] += amount;\n totalTokenDebt[token] += amount;\n emit TokenDebtAdded(address(token), to, amount);\n }\n }\n\n /**\n * @dev Either transfers tokens to the recepient or returns false. Supports tokens\n * thet revert or return false to indicate failure, and the non-compliant ones\n * that do not return any value.\n * @param token The token to transfer\n * @param to The recipient of the transfer\n * @param amount The amount to transfer\n * @return true if the transfer succeeded, false otherwise\n */\n function _tryTransferOut(\n IERC20Upgradeable token,\n address to,\n uint256 amount\n ) private returns (bool) {\n bytes memory callData = abi.encodeCall(token.transfer, (to, amount));\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(callData);\n return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n }\n}\n" + }, + "contracts/lib/validators.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n}\n" + }, + "contracts/MaxLoopsLimitHelper.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title MaxLoopsLimitHelper\n * @author Venus\n * @notice Abstract contract used to avoid collection with too many items that would generate gas errors and DoS.\n */\nabstract contract MaxLoopsLimitHelper {\n // Limit for the loops to avoid the DOS\n uint256 public maxLoopsLimit;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when max loops limit is set\n event MaxLoopsLimitUpdated(uint256 oldMaxLoopsLimit, uint256 newmaxLoopsLimit);\n\n /// @notice Thrown an error on maxLoopsLimit exceeds for any loop\n error MaxLoopsLimitExceeded(uint256 loopsLimit, uint256 requiredLoops);\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function _setMaxLoopsLimit(uint256 limit) internal {\n require(limit > maxLoopsLimit, \"Comptroller: Invalid maxLoopsLimit\");\n\n uint256 oldMaxLoopsLimit = maxLoopsLimit;\n maxLoopsLimit = limit;\n\n emit MaxLoopsLimitUpdated(oldMaxLoopsLimit, limit);\n }\n\n /**\n * @notice Compare the maxLoopsLimit with number of the times loop iterate\n * @param len Length of the loops iterate\n * @custom:error MaxLoopsLimitExceeded error is thrown when loops length exceeds maxLoopsLimit\n */\n function _ensureMaxLoops(uint256 len) internal view {\n if (len > maxLoopsLimit) {\n revert MaxLoopsLimitExceeded(maxLoopsLimit, len);\n }\n }\n}\n" + }, + "contracts/Pool/PoolRegistry.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { PoolRegistryInterface } from \"./PoolRegistryInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\n/**\n * @title PoolRegistry\n * @author Venus\n * @notice The Isolated Pools architecture centers around the `PoolRegistry` contract. The `PoolRegistry` maintains a directory of isolated lending\n * pools and can perform actions like creating and registering new pools, adding new markets to existing pools, setting and updating the pool's required\n * metadata, and providing the getter methods to get information on the pools.\n *\n * Isolated lending has three main components: PoolRegistry, pools, and markets. The PoolRegistry is responsible for managing pools.\n * It can create new pools, update pool metadata and manage markets within pools. PoolRegistry contains getter methods to get the details of\n * any existing pool like `getVTokenForAsset` and `getPoolsSupportedByAsset`. It also contains methods for updating pool metadata (`updatePoolMetadata`)\n * and setting pool name (`setPoolName`).\n *\n * The directory of pools is managed through two mappings: `_poolByComptroller` which is a hashmap with the comptroller address as the key and `VenusPool` as\n * the value and `_poolsByID` which is an array of comptroller addresses. Individual pools can be accessed by calling `getPoolByComptroller` with the pool's\n * comptroller address. `_poolsByID` is used to iterate through all of the pools.\n *\n * PoolRegistry also contains a map of asset addresses called `_supportedPools` that maps to an array of assets suppored by each pool. This array of pools by\n * asset is retrieved by calling `getPoolsSupportedByAsset`.\n *\n * PoolRegistry registers new isolated pools in the directory with the `createRegistryPool` method. Isolated pools are composed of independent markets with\n * specific assets and custom risk management configurations according to their markets.\n */\ncontract PoolRegistry is Ownable2StepUpgradeable, AccessControlledV8, PoolRegistryInterface {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n struct AddMarketInput {\n VToken vToken;\n uint256 collateralFactor;\n uint256 liquidationThreshold;\n uint256 initialSupply;\n address vTokenReceiver;\n uint256 supplyCap;\n uint256 borrowCap;\n }\n\n uint256 internal constant MAX_POOL_NAME_LENGTH = 100;\n\n /**\n * @notice Maps pool's comptroller address to metadata.\n */\n mapping(address => VenusPoolMetaData) public metadata;\n\n /**\n * @dev Maps pool ID to pool's comptroller address\n */\n mapping(uint256 => address) private _poolsByID;\n\n /**\n * @dev Total number of pools created.\n */\n uint256 private _numberOfPools;\n\n /**\n * @dev Maps comptroller address to Venus pool Index.\n */\n mapping(address => VenusPool) private _poolByComptroller;\n\n /**\n * @dev Maps pool's comptroller address to asset to vToken.\n */\n mapping(address => mapping(address => address)) private _vTokens;\n\n /**\n * @dev Maps asset to list of supported pools.\n */\n mapping(address => address[]) private _supportedPools;\n\n /**\n * @notice Emitted when a new Venus pool is added to the directory.\n */\n event PoolRegistered(address indexed comptroller, VenusPool pool);\n\n /**\n * @notice Emitted when a pool name is set.\n */\n event PoolNameSet(address indexed comptroller, string oldName, string newName);\n\n /**\n * @notice Emitted when a pool metadata is updated.\n */\n event PoolMetadataUpdated(\n address indexed comptroller,\n VenusPoolMetaData oldMetadata,\n VenusPoolMetaData newMetadata\n );\n\n /**\n * @notice Emitted when a Market is added to the pool.\n */\n event MarketAdded(address indexed comptroller, address indexed vTokenAddress);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner\n * @param accessControlManager_ AccessControlManager contract address\n */\n function initialize(address accessControlManager_) external initializer {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n /**\n * @notice Adds a new Venus pool to the directory\n * @dev Price oracle must be configured before adding a pool\n * @param name The name of the pool\n * @param comptroller Pool's Comptroller contract\n * @param closeFactor The pool's close factor (scaled by 1e18)\n * @param liquidationIncentive The pool's liquidation incentive (scaled by 1e18)\n * @param minLiquidatableCollateral Minimal collateral for regular (non-batch) liquidations flow\n * @return index The index of the registered Venus pool\n * @custom:error ZeroAddressNotAllowed is thrown when Comptroller address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when price oracle address is zero\n */\n function addPool(\n string calldata name,\n Comptroller comptroller,\n uint256 closeFactor,\n uint256 liquidationIncentive,\n uint256 minLiquidatableCollateral\n ) external virtual returns (uint256 index) {\n _checkAccessAllowed(\"addPool(string,address,uint256,uint256,uint256)\");\n // Input validation\n ensureNonzeroAddress(address(comptroller));\n ensureNonzeroAddress(address(comptroller.oracle()));\n\n uint256 poolId = _registerPool(name, address(comptroller));\n\n // Set Venus pool parameters\n comptroller.setCloseFactor(closeFactor);\n comptroller.setLiquidationIncentive(liquidationIncentive);\n comptroller.setMinLiquidatableCollateral(minLiquidatableCollateral);\n\n return poolId;\n }\n\n /**\n * @notice Add a market to an existing pool and then mint to provide initial supply\n * @param input The structure describing the parameters for adding a market to a pool\n * @custom:error ZeroAddressNotAllowed is thrown when vToken address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when vTokenReceiver address is zero\n */\n function addMarket(AddMarketInput memory input) external {\n _checkAccessAllowed(\"addMarket(AddMarketInput)\");\n ensureNonzeroAddress(address(input.vToken));\n ensureNonzeroAddress(input.vTokenReceiver);\n require(input.initialSupply > 0, \"PoolRegistry: initialSupply is zero\");\n\n VToken vToken = input.vToken;\n address vTokenAddress = address(vToken);\n address comptrollerAddress = address(vToken.comptroller());\n Comptroller comptroller = Comptroller(comptrollerAddress);\n address underlyingAddress = vToken.underlying();\n IERC20Upgradeable underlying = IERC20Upgradeable(underlyingAddress);\n\n require(_poolByComptroller[comptrollerAddress].creator != address(0), \"PoolRegistry: Pool not registered\");\n // solhint-disable-next-line reason-string\n require(\n _vTokens[comptrollerAddress][underlyingAddress] == address(0),\n \"PoolRegistry: Market already added for asset comptroller combination\"\n );\n\n comptroller.supportMarket(vToken);\n comptroller.setCollateralFactor(vToken, input.collateralFactor, input.liquidationThreshold);\n\n uint256[] memory newSupplyCaps = new uint256[](1);\n uint256[] memory newBorrowCaps = new uint256[](1);\n VToken[] memory vTokens = new VToken[](1);\n\n newSupplyCaps[0] = input.supplyCap;\n newBorrowCaps[0] = input.borrowCap;\n vTokens[0] = vToken;\n\n comptroller.setMarketSupplyCaps(vTokens, newSupplyCaps);\n comptroller.setMarketBorrowCaps(vTokens, newBorrowCaps);\n\n _vTokens[comptrollerAddress][underlyingAddress] = vTokenAddress;\n _supportedPools[underlyingAddress].push(comptrollerAddress);\n\n uint256 amountToSupply = _transferIn(underlying, msg.sender, input.initialSupply);\n underlying.approve(vTokenAddress, 0);\n underlying.approve(vTokenAddress, amountToSupply);\n vToken.mintBehalf(input.vTokenReceiver, amountToSupply);\n\n emit MarketAdded(comptrollerAddress, vTokenAddress);\n }\n\n /**\n * @notice Modify existing Venus pool name\n * @param comptroller Pool's Comptroller\n * @param name New pool name\n */\n function setPoolName(address comptroller, string calldata name) external {\n _checkAccessAllowed(\"setPoolName(address,string)\");\n _ensureValidName(name);\n VenusPool storage pool = _poolByComptroller[comptroller];\n string memory oldName = pool.name;\n pool.name = name;\n emit PoolNameSet(comptroller, oldName, name);\n }\n\n /**\n * @notice Update metadata of an existing pool\n * @param comptroller Pool's Comptroller\n * @param metadata_ New pool metadata\n */\n function updatePoolMetadata(address comptroller, VenusPoolMetaData calldata metadata_) external {\n _checkAccessAllowed(\"updatePoolMetadata(address,VenusPoolMetaData)\");\n VenusPoolMetaData memory oldMetadata = metadata[comptroller];\n metadata[comptroller] = metadata_;\n emit PoolMetadataUpdated(comptroller, oldMetadata, metadata_);\n }\n\n /**\n * @notice Returns arrays of all Venus pools' data\n * @dev This function is not designed to be called in a transaction: it is too gas-intensive\n * @return A list of all pools within PoolRegistry, with details for each pool\n */\n function getAllPools() external view override returns (VenusPool[] memory) {\n uint256 numberOfPools_ = _numberOfPools; // storage load to save gas\n VenusPool[] memory _pools = new VenusPool[](numberOfPools_);\n for (uint256 i = 1; i <= numberOfPools_; ++i) {\n address comptroller = _poolsByID[i];\n _pools[i - 1] = (_poolByComptroller[comptroller]);\n }\n return _pools;\n }\n\n /**\n * @param comptroller The comptroller proxy address associated to the pool\n * @return Returns Venus pool\n */\n function getPoolByComptroller(address comptroller) external view override returns (VenusPool memory) {\n return _poolByComptroller[comptroller];\n }\n\n /**\n * @param comptroller comptroller of Venus pool\n * @return Returns Metadata of Venus pool\n */\n function getVenusPoolMetadata(address comptroller) external view override returns (VenusPoolMetaData memory) {\n return metadata[comptroller];\n }\n\n function getVTokenForAsset(address comptroller, address asset) external view override returns (address) {\n return _vTokens[comptroller][asset];\n }\n\n function getPoolsSupportedByAsset(address asset) external view override returns (address[] memory) {\n return _supportedPools[asset];\n }\n\n /**\n * @dev Adds a new Venus pool to the directory (without checking msg.sender).\n * @param name The name of the pool\n * @param comptroller The pool's Comptroller proxy contract address\n * @return The index of the registered Venus pool\n */\n function _registerPool(string calldata name, address comptroller) internal returns (uint256) {\n VenusPool storage storedPool = _poolByComptroller[comptroller];\n\n require(storedPool.creator == address(0), \"PoolRegistry: Pool already exists in the directory.\");\n _ensureValidName(name);\n\n ++_numberOfPools;\n uint256 numberOfPools_ = _numberOfPools; // cache on stack to save storage read gas\n\n VenusPool memory pool = VenusPool(name, msg.sender, comptroller, block.number, block.timestamp);\n\n _poolsByID[numberOfPools_] = comptroller;\n _poolByComptroller[comptroller] = pool;\n\n emit PoolRegistered(comptroller, pool);\n return numberOfPools_;\n }\n\n function _transferIn(\n IERC20Upgradeable token,\n address from,\n uint256 amount\n ) internal returns (uint256) {\n uint256 balanceBefore = token.balanceOf(address(this));\n token.safeTransferFrom(from, address(this), amount);\n uint256 balanceAfter = token.balanceOf(address(this));\n return balanceAfter - balanceBefore;\n }\n\n function _ensureValidName(string calldata name) internal pure {\n require(bytes(name).length <= MAX_POOL_NAME_LENGTH, \"Pool's name is too large\");\n }\n}\n" + }, + "contracts/Pool/PoolRegistryInterface.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title PoolRegistryInterface\n * @author Venus\n * @notice Interface implemented by `PoolRegistry`.\n */\ninterface PoolRegistryInterface {\n /**\n * @notice Struct for a Venus interest rate pool.\n */\n struct VenusPool {\n string name;\n address creator;\n address comptroller;\n uint256 blockPosted;\n uint256 timestampPosted;\n }\n\n /**\n * @notice Struct for a Venus interest rate pool metadata.\n */\n struct VenusPoolMetaData {\n string category;\n string logoURL;\n string description;\n }\n\n /// @notice Get all pools in PoolRegistry\n function getAllPools() external view returns (VenusPool[] memory);\n\n /// @notice Get a pool by comptroller address\n function getPoolByComptroller(address comptroller) external view returns (VenusPool memory);\n\n /// @notice Get the address of the VToken contract in the Pool where the underlying token is the provided 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 /// @notice Get the metadata of a Pool by comptroller address\n function getVenusPoolMetadata(address comptroller) external view returns (VenusPoolMetaData memory);\n}\n" + }, + "contracts/Rewards/RewardsDistributor.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\n\n/**\n * @title `RewardsDistributor`\n * @author Venus\n * @notice Contract used to configure, track and distribute rewards to users based on their actions (borrows and supplies) in the protocol.\n * Users can receive additional rewards through a `RewardsDistributor`. Each `RewardsDistributor` proxy is initialized with a specific reward\n * token and `Comptroller`, which can then distribute the reward token to users that supply or borrow in the associated pool.\n * Authorized users can set the reward token borrow and supply speeds for each market in the pool. This sets a fixed amount of reward\n * token to be released each block for borrowers and suppliers, which is distributed based on a user’s percentage of the borrows or supplies\n * respectively. The owner can also set up reward distributions to contributor addresses (distinct from suppliers and borrowers) by setting\n * their contributor reward token speed, which similarly allocates a fixed amount of reward token per block.\n *\n * The owner has the ability to transfer any amount of reward tokens held by the contract to any other address. Rewards are not distributed\n * automatically and must be claimed by a user calling `claimRewardToken()`. Users should be aware that it is up to the owner and other centralized\n * entities to ensure that the `RewardsDistributor` holds enough tokens to distribute the accumulated rewards of users and contributors.\n */\ncontract RewardsDistributor is ExponentialNoError, Ownable2StepUpgradeable, AccessControlledV8, MaxLoopsLimitHelper {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n struct RewardToken {\n // The market's last updated rewardTokenBorrowIndex or rewardTokenSupplyIndex\n uint224 index;\n // The block number the index was last updated at\n uint32 block;\n // The block number at which to stop rewards\n uint32 lastRewardingBlock;\n }\n\n /// @notice The initial REWARD TOKEN index for a market\n uint224 public constant INITIAL_INDEX = 1e36;\n\n /// @notice The REWARD TOKEN market supply state for each market\n mapping(address => RewardToken) public rewardTokenSupplyState;\n\n /// @notice The REWARD TOKEN borrow index for each market for each supplier as of the last time they accrued REWARD TOKEN\n mapping(address => mapping(address => uint256)) public rewardTokenSupplierIndex;\n\n /// @notice The REWARD TOKEN accrued but not yet transferred to each user\n mapping(address => uint256) public rewardTokenAccrued;\n\n /// @notice The rate at which rewardToken is distributed to the corresponding borrow market (per block)\n mapping(address => uint256) public rewardTokenBorrowSpeeds;\n\n /// @notice The rate at which rewardToken is distributed to the corresponding supply market (per block)\n mapping(address => uint256) public rewardTokenSupplySpeeds;\n\n /// @notice The REWARD TOKEN market borrow state for each market\n mapping(address => RewardToken) public rewardTokenBorrowState;\n\n /// @notice The portion of REWARD TOKEN that each contributor receives per block\n mapping(address => uint256) public rewardTokenContributorSpeeds;\n\n /// @notice Last block at which a contributor's REWARD TOKEN rewards have been allocated\n mapping(address => uint256) public lastContributorBlock;\n\n /// @notice The REWARD TOKEN borrow index for each market for each borrower as of the last time they accrued REWARD TOKEN\n mapping(address => mapping(address => uint256)) public rewardTokenBorrowerIndex;\n\n Comptroller private comptroller;\n\n IERC20Upgradeable public rewardToken;\n\n /// @notice Emitted when REWARD TOKEN is distributed to a supplier\n event DistributedSupplierRewardToken(\n VToken indexed vToken,\n address indexed supplier,\n uint256 rewardTokenDelta,\n uint256 rewardTokenTotal,\n uint256 rewardTokenSupplyIndex\n );\n\n /// @notice Emitted when REWARD TOKEN is distributed to a borrower\n event DistributedBorrowerRewardToken(\n VToken indexed vToken,\n address indexed borrower,\n uint256 rewardTokenDelta,\n uint256 rewardTokenTotal,\n uint256 rewardTokenBorrowIndex\n );\n\n /// @notice Emitted when a new supply-side REWARD TOKEN speed is calculated for a market\n event RewardTokenSupplySpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n /// @notice Emitted when a new borrow-side REWARD TOKEN speed is calculated for a market\n event RewardTokenBorrowSpeedUpdated(VToken indexed vToken, uint256 newSpeed);\n\n /// @notice Emitted when REWARD TOKEN is granted by admin\n event RewardTokenGranted(address indexed recipient, uint256 amount);\n\n /// @notice Emitted when a new REWARD TOKEN speed is set for a contributor\n event ContributorRewardTokenSpeedUpdated(address indexed contributor, uint256 newSpeed);\n\n /// @notice Emitted when a market is initialized\n event MarketInitialized(address indexed vToken);\n\n /// @notice Emitted when a reward token supply index is updated\n event RewardTokenSupplyIndexUpdated(address indexed vToken);\n\n /// @notice Emitted when a reward token borrow index is updated\n event RewardTokenBorrowIndexUpdated(address indexed vToken, Exp marketBorrowIndex);\n\n /// @notice Emitted when a reward for contributor is updated\n event ContributorRewardsUpdated(address indexed contributor, uint256 rewardAccrued);\n\n /// @notice Emitted when a reward token last rewarding block for supply is updated\n event SupplyLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n /// @notice Emitted when a reward token last rewarding block for borrow is updated\n event BorrowLastRewardingBlockUpdated(address indexed vToken, uint32 newBlock);\n\n modifier onlyComptroller() {\n require(address(comptroller) == msg.sender, \"Only comptroller can call this function\");\n _;\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice RewardsDistributor initializer\n * @dev Initializes the deployer to owner\n * @param comptroller_ Comptroller to attach the reward distributor to\n * @param rewardToken_ Reward token to distribute\n * @param loopsLimit_ Maximum number of iterations for the loops in this contract\n * @param accessControlManager_ AccessControlManager contract address\n */\n function initialize(\n Comptroller comptroller_,\n IERC20Upgradeable rewardToken_,\n uint256 loopsLimit_,\n address accessControlManager_\n ) external initializer {\n comptroller = comptroller_;\n rewardToken = rewardToken_;\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n\n _setMaxLoopsLimit(loopsLimit_);\n }\n\n function initializeMarket(address vToken) external onlyComptroller {\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n\n /*\n * Update market state indices\n */\n if (supplyState.index == 0) {\n // Initialize supply state index with default value\n supplyState.index = INITIAL_INDEX;\n }\n\n if (borrowState.index == 0) {\n // Initialize borrow state index with default value\n borrowState.index = INITIAL_INDEX;\n }\n\n /*\n * Update market state block numbers\n */\n supplyState.block = borrowState.block = blockNumber;\n\n emit MarketInitialized(vToken);\n }\n\n /*** Reward Token Distribution ***/\n\n /**\n * @notice Calculate reward token accrued by a borrower and possibly transfer it to them\n * Borrowers will begin to accrue after the first interaction with the protocol.\n * @dev This function should only be called when the user has a borrow position in the market\n * (e.g. Comptroller.preBorrowHook, and Comptroller.preRepayHook)\n * We avoid an external call to check if they are in the market to save gas because this function is called in many places\n * @param vToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute REWARD TOKEN to\n * @param marketBorrowIndex The current global borrow index of vToken\n */\n function distributeBorrowerRewardToken(\n address vToken,\n address borrower,\n Exp memory marketBorrowIndex\n ) external onlyComptroller {\n _distributeBorrowerRewardToken(vToken, borrower, marketBorrowIndex);\n }\n\n function updateRewardTokenSupplyIndex(address vToken) external onlyComptroller {\n _updateRewardTokenSupplyIndex(vToken);\n }\n\n /**\n * @notice Transfer REWARD TOKEN to the recipient\n * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all\n * @param recipient The address of the recipient to transfer REWARD TOKEN to\n * @param amount The amount of REWARD TOKEN to (possibly) transfer\n */\n function grantRewardToken(address recipient, uint256 amount) external onlyOwner {\n uint256 amountLeft = _grantRewardToken(recipient, amount);\n require(amountLeft == 0, \"insufficient rewardToken for grant\");\n emit RewardTokenGranted(recipient, amount);\n }\n\n function updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) external onlyComptroller {\n _updateRewardTokenBorrowIndex(vToken, marketBorrowIndex);\n }\n\n /**\n * @notice Set REWARD TOKEN borrow and supply speeds for the specified markets\n * @param vTokens The markets whose REWARD TOKEN speed to update\n * @param supplySpeeds New supply-side REWARD TOKEN speed for the corresponding market\n * @param borrowSpeeds New borrow-side REWARD TOKEN speed for the corresponding market\n */\n function setRewardTokenSpeeds(\n VToken[] memory vTokens,\n uint256[] memory supplySpeeds,\n uint256[] memory borrowSpeeds\n ) external {\n _checkAccessAllowed(\"setRewardTokenSpeeds(address[],uint256[],uint256[])\");\n uint256 numTokens = vTokens.length;\n require(numTokens == supplySpeeds.length && numTokens == borrowSpeeds.length, \"invalid setRewardTokenSpeeds\");\n\n for (uint256 i; i < numTokens; ++i) {\n _setRewardTokenSpeed(vTokens[i], supplySpeeds[i], borrowSpeeds[i]);\n }\n }\n\n /**\n * @notice Set REWARD TOKEN last rewarding block for the specified markets\n * @param vTokens The markets whose REWARD TOKEN last rewarding block to update\n * @param supplyLastRewardingBlocks New supply-side REWARD TOKEN last rewarding block for the corresponding market\n * @param borrowLastRewardingBlocks New borrow-side REWARD TOKEN last rewarding block for the corresponding market\n */\n function setLastRewardingBlocks(\n VToken[] calldata vTokens,\n uint32[] calldata supplyLastRewardingBlocks,\n uint32[] calldata borrowLastRewardingBlocks\n ) external {\n _checkAccessAllowed(\"setLastRewardingBlock(address[],uint32[],uint32[])\");\n uint256 numTokens = vTokens.length;\n require(\n numTokens == supplyLastRewardingBlocks.length && numTokens == borrowLastRewardingBlocks.length,\n \"RewardsDistributor::setLastRewardingBlocks invalid input\"\n );\n\n for (uint256 i; i < numTokens; ) {\n _setLastRewardingBlock(vTokens[i], supplyLastRewardingBlocks[i], borrowLastRewardingBlocks[i]);\n unchecked {\n ++i;\n }\n }\n }\n\n /**\n * @notice Set REWARD TOKEN speed for a single contributor\n * @param contributor The contributor whose REWARD TOKEN speed to update\n * @param rewardTokenSpeed New REWARD TOKEN speed for contributor\n */\n function setContributorRewardTokenSpeed(address contributor, uint256 rewardTokenSpeed) external onlyOwner {\n // note that REWARD TOKEN speed could be set to 0 to halt liquidity rewards for a contributor\n updateContributorRewards(contributor);\n if (rewardTokenSpeed == 0) {\n // release storage\n delete lastContributorBlock[contributor];\n } else {\n lastContributorBlock[contributor] = getBlockNumber();\n }\n rewardTokenContributorSpeeds[contributor] = rewardTokenSpeed;\n\n emit ContributorRewardTokenSpeedUpdated(contributor, rewardTokenSpeed);\n }\n\n function distributeSupplierRewardToken(address vToken, address supplier) external onlyComptroller {\n _distributeSupplierRewardToken(vToken, supplier);\n }\n\n /**\n * @notice Claim all the rewardToken accrued by holder in all markets\n * @param holder The address to claim REWARD TOKEN for\n */\n function claimRewardToken(address holder) external {\n return claimRewardToken(holder, comptroller.getAllMarkets());\n }\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Calculate additional accrued REWARD TOKEN for a contributor since last accrual\n * @param contributor The address to calculate contributor rewards for\n */\n function updateContributorRewards(address contributor) public {\n uint256 rewardTokenSpeed = rewardTokenContributorSpeeds[contributor];\n uint256 blockNumber = getBlockNumber();\n uint256 deltaBlocks = sub_(blockNumber, lastContributorBlock[contributor]);\n if (deltaBlocks > 0 && rewardTokenSpeed > 0) {\n uint256 newAccrued = mul_(deltaBlocks, rewardTokenSpeed);\n uint256 contributorAccrued = add_(rewardTokenAccrued[contributor], newAccrued);\n\n rewardTokenAccrued[contributor] = contributorAccrued;\n lastContributorBlock[contributor] = blockNumber;\n\n emit ContributorRewardsUpdated(contributor, rewardTokenAccrued[contributor]);\n }\n }\n\n /**\n * @notice Claim all the rewardToken accrued by holder in the specified markets\n * @param holder The address to claim REWARD TOKEN for\n * @param vTokens The list of markets to claim REWARD TOKEN in\n */\n function claimRewardToken(address holder, VToken[] memory vTokens) public {\n uint256 vTokensCount = vTokens.length;\n\n _ensureMaxLoops(vTokensCount);\n\n for (uint256 i; i < vTokensCount; ++i) {\n VToken vToken = vTokens[i];\n require(comptroller.isMarketListed(vToken), \"market must be listed\");\n Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n _distributeBorrowerRewardToken(address(vToken), holder, borrowIndex);\n _updateRewardTokenSupplyIndex(address(vToken));\n _distributeSupplierRewardToken(address(vToken), holder);\n }\n rewardTokenAccrued[holder] = _grantRewardToken(holder, rewardTokenAccrued[holder]);\n }\n\n function getBlockNumber() public view virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Set REWARD TOKEN last rewarding block for a single market.\n * @param vToken market's whose reward token last rewarding block to be updated\n * @param supplyLastRewardingBlock New supply-side REWARD TOKEN last rewarding block for market\n * @param borrowLastRewardingBlock New borrow-side REWARD TOKEN last rewarding block for market\n */\n function _setLastRewardingBlock(\n VToken vToken,\n uint32 supplyLastRewardingBlock,\n uint32 borrowLastRewardingBlock\n ) internal {\n require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n uint256 blockNumber = getBlockNumber();\n\n require(supplyLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n require(borrowLastRewardingBlock > blockNumber, \"setting last rewarding block in the past is not allowed\");\n\n uint32 currentSupplyLastRewardingBlock = rewardTokenSupplyState[address(vToken)].lastRewardingBlock;\n uint32 currentBorrowLastRewardingBlock = rewardTokenBorrowState[address(vToken)].lastRewardingBlock;\n\n require(\n currentSupplyLastRewardingBlock == 0 || currentSupplyLastRewardingBlock > blockNumber,\n \"this RewardsDistributor is already locked\"\n );\n require(\n currentBorrowLastRewardingBlock == 0 || currentBorrowLastRewardingBlock > blockNumber,\n \"this RewardsDistributor is already locked\"\n );\n\n if (currentSupplyLastRewardingBlock != supplyLastRewardingBlock) {\n rewardTokenSupplyState[address(vToken)].lastRewardingBlock = supplyLastRewardingBlock;\n emit SupplyLastRewardingBlockUpdated(address(vToken), supplyLastRewardingBlock);\n }\n\n if (currentBorrowLastRewardingBlock != borrowLastRewardingBlock) {\n rewardTokenBorrowState[address(vToken)].lastRewardingBlock = borrowLastRewardingBlock;\n emit BorrowLastRewardingBlockUpdated(address(vToken), borrowLastRewardingBlock);\n }\n }\n\n /**\n * @notice Set REWARD TOKEN speed for a single market.\n * @param vToken market's whose reward token rate to be updated\n * @param supplySpeed New supply-side REWARD TOKEN speed for market\n * @param borrowSpeed New borrow-side REWARD TOKEN speed for market\n */\n function _setRewardTokenSpeed(\n VToken vToken,\n uint256 supplySpeed,\n uint256 borrowSpeed\n ) internal {\n require(comptroller.isMarketListed(vToken), \"rewardToken market is not listed\");\n\n if (rewardTokenSupplySpeeds[address(vToken)] != supplySpeed) {\n // Supply speed updated so let's update supply state to ensure that\n // 1. REWARD TOKEN accrued properly for the old speed, and\n // 2. REWARD TOKEN accrued at the new speed starts after this block.\n _updateRewardTokenSupplyIndex(address(vToken));\n\n // Update speed and emit event\n rewardTokenSupplySpeeds[address(vToken)] = supplySpeed;\n emit RewardTokenSupplySpeedUpdated(vToken, supplySpeed);\n }\n\n if (rewardTokenBorrowSpeeds[address(vToken)] != borrowSpeed) {\n // Borrow speed updated so let's update borrow state to ensure that\n // 1. REWARD TOKEN accrued properly for the old speed, and\n // 2. REWARD TOKEN accrued at the new speed starts after this block.\n Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() });\n _updateRewardTokenBorrowIndex(address(vToken), borrowIndex);\n\n // Update speed and emit event\n rewardTokenBorrowSpeeds[address(vToken)] = borrowSpeed;\n emit RewardTokenBorrowSpeedUpdated(vToken, borrowSpeed);\n }\n }\n\n /**\n * @notice Calculate REWARD TOKEN accrued by a supplier and possibly transfer it to them.\n * @param vToken The market in which the supplier is interacting\n * @param supplier The address of the supplier to distribute REWARD TOKEN to\n */\n function _distributeSupplierRewardToken(address vToken, address supplier) internal {\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n uint256 supplyIndex = supplyState.index;\n uint256 supplierIndex = rewardTokenSupplierIndex[vToken][supplier];\n\n // Update supplier's index to the current index since we are distributing accrued REWARD TOKEN\n rewardTokenSupplierIndex[vToken][supplier] = supplyIndex;\n\n if (supplierIndex == 0 && supplyIndex >= INITIAL_INDEX) {\n // Covers the case where users supplied tokens before the market's supply state index was set.\n // Rewards the user with REWARD TOKEN accrued from the start of when supplier rewards were first\n // set for the market.\n supplierIndex = INITIAL_INDEX;\n }\n\n // Calculate change in the cumulative sum of the REWARD TOKEN per vToken accrued\n Double memory deltaIndex = Double({ mantissa: sub_(supplyIndex, supplierIndex) });\n\n uint256 supplierTokens = VToken(vToken).balanceOf(supplier);\n\n // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerVToken\n uint256 supplierDelta = mul_(supplierTokens, deltaIndex);\n\n uint256 supplierAccrued = add_(rewardTokenAccrued[supplier], supplierDelta);\n rewardTokenAccrued[supplier] = supplierAccrued;\n\n emit DistributedSupplierRewardToken(VToken(vToken), supplier, supplierDelta, supplierAccrued, supplyIndex);\n }\n\n /**\n * @notice Calculate reward token accrued by a borrower and possibly transfer it to them.\n * @param vToken The market in which the borrower is interacting\n * @param borrower The address of the borrower to distribute REWARD TOKEN to\n * @param marketBorrowIndex The current global borrow index of vToken\n */\n function _distributeBorrowerRewardToken(\n address vToken,\n address borrower,\n Exp memory marketBorrowIndex\n ) internal {\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n uint256 borrowIndex = borrowState.index;\n uint256 borrowerIndex = rewardTokenBorrowerIndex[vToken][borrower];\n\n // Update borrowers's index to the current index since we are distributing accrued REWARD TOKEN\n rewardTokenBorrowerIndex[vToken][borrower] = borrowIndex;\n\n if (borrowerIndex == 0 && borrowIndex >= INITIAL_INDEX) {\n // Covers the case where users borrowed tokens before the market's borrow state index was set.\n // Rewards the user with REWARD TOKEN accrued from the start of when borrower rewards were first\n // set for the market.\n borrowerIndex = INITIAL_INDEX;\n }\n\n // Calculate change in the cumulative sum of the REWARD TOKEN per borrowed unit accrued\n Double memory deltaIndex = Double({ mantissa: sub_(borrowIndex, borrowerIndex) });\n\n uint256 borrowerAmount = div_(VToken(vToken).borrowBalanceStored(borrower), marketBorrowIndex);\n\n // Calculate REWARD TOKEN accrued: vTokenAmount * accruedPerBorrowedUnit\n if (borrowerAmount != 0) {\n uint256 borrowerDelta = mul_(borrowerAmount, deltaIndex);\n\n uint256 borrowerAccrued = add_(rewardTokenAccrued[borrower], borrowerDelta);\n rewardTokenAccrued[borrower] = borrowerAccrued;\n\n emit DistributedBorrowerRewardToken(VToken(vToken), borrower, borrowerDelta, borrowerAccrued, borrowIndex);\n }\n }\n\n /**\n * @notice Transfer REWARD TOKEN to the user.\n * @dev Note: If there is not enough REWARD TOKEN, we do not perform the transfer all.\n * @param user The address of the user to transfer REWARD TOKEN to\n * @param amount The amount of REWARD TOKEN to (possibly) transfer\n * @return The amount of REWARD TOKEN which was NOT transferred to the user\n */\n function _grantRewardToken(address user, uint256 amount) internal returns (uint256) {\n uint256 rewardTokenRemaining = rewardToken.balanceOf(address(this));\n if (amount > 0 && amount <= rewardTokenRemaining) {\n rewardToken.safeTransfer(user, amount);\n return 0;\n }\n return amount;\n }\n\n /**\n * @notice Accrue REWARD TOKEN to the market by updating the supply index\n * @param vToken The market whose supply index to update\n * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n */\n function _updateRewardTokenSupplyIndex(address vToken) internal {\n RewardToken storage supplyState = rewardTokenSupplyState[vToken];\n uint256 supplySpeed = rewardTokenSupplySpeeds[vToken];\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n if (supplyState.lastRewardingBlock > 0 && blockNumber > supplyState.lastRewardingBlock) {\n blockNumber = supplyState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(uint256(blockNumber), uint256(supplyState.block));\n\n if (deltaBlocks > 0 && supplySpeed > 0) {\n uint256 supplyTokens = VToken(vToken).totalSupply();\n uint256 accruedSinceUpdate = mul_(deltaBlocks, supplySpeed);\n Double memory ratio = supplyTokens > 0\n ? fraction(accruedSinceUpdate, supplyTokens)\n : Double({ mantissa: 0 });\n supplyState.index = safe224(\n add_(Double({ mantissa: supplyState.index }), ratio).mantissa,\n \"new index exceeds 224 bits\"\n );\n supplyState.block = blockNumber;\n } else if (deltaBlocks > 0) {\n supplyState.block = blockNumber;\n }\n\n emit RewardTokenSupplyIndexUpdated(vToken);\n }\n\n /**\n * @notice Accrue REWARD TOKEN to the market by updating the borrow index\n * @param vToken The market whose borrow index to update\n * @param marketBorrowIndex The current global borrow index of vToken\n * @dev Index is a cumulative sum of the REWARD TOKEN per vToken accrued\n */\n function _updateRewardTokenBorrowIndex(address vToken, Exp memory marketBorrowIndex) internal {\n RewardToken storage borrowState = rewardTokenBorrowState[vToken];\n uint256 borrowSpeed = rewardTokenBorrowSpeeds[vToken];\n uint32 blockNumber = safe32(getBlockNumber(), \"block number exceeds 32 bits\");\n\n if (borrowState.lastRewardingBlock > 0 && blockNumber > borrowState.lastRewardingBlock) {\n blockNumber = borrowState.lastRewardingBlock;\n }\n\n uint256 deltaBlocks = sub_(uint256(blockNumber), uint256(borrowState.block));\n if (deltaBlocks > 0 && borrowSpeed > 0) {\n uint256 borrowAmount = div_(VToken(vToken).totalBorrows(), marketBorrowIndex);\n uint256 accruedSinceUpdate = mul_(deltaBlocks, borrowSpeed);\n Double memory ratio = borrowAmount > 0\n ? fraction(accruedSinceUpdate, borrowAmount)\n : Double({ mantissa: 0 });\n borrowState.index = safe224(\n add_(Double({ mantissa: borrowState.index }), ratio).mantissa,\n \"new index exceeds 224 bits\"\n );\n borrowState.block = blockNumber;\n } else if (deltaBlocks > 0) {\n borrowState.block = blockNumber;\n }\n\n emit RewardTokenBorrowIndexUpdated(vToken, marketBorrowIndex);\n }\n}\n" + }, + "contracts/RiskFund/IProtocolShareReserve.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IProtocolShareReserve\n * @author Venus\n * @notice Interface implemented by `ProtocolShareReserve`.\n */\ninterface IProtocolShareReserve {\n function updateAssetsState(address comptroller, address asset) external;\n}\n" + }, + "contracts/RiskFund/IRiskFund.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IRiskFund\n * @author Venus\n * @notice Interface implemented by `RiskFund`.\n */\ninterface IRiskFund {\n function swapPoolsAssets(\n address[] calldata markets,\n uint256[] calldata amountsOutMin,\n address[][] calldata paths,\n uint256 deadline\n ) external returns (uint256);\n\n function transferReserveForAuction(address comptroller, uint256 amount) external returns (uint256);\n\n function updateAssetsState(address comptroller, address asset) external;\n\n function convertibleBaseAsset() external view returns (address);\n\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256);\n}\n" + }, + "contracts/RiskFund/ProtocolShareReserve.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { IProtocolShareReserve } from \"./IProtocolShareReserve.sol\";\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\n\ncontract ProtocolShareReserve is ExponentialNoError, ReserveHelpers, IProtocolShareReserve {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n address public protocolIncome;\n address public riskFund;\n // Percentage of funds not sent to the RiskFund contract when the funds are released, following the project Tokenomics\n uint256 private constant PROTOCOL_SHARE_PERCENTAGE = 50;\n uint256 private constant BASE_UNIT = 100;\n\n /// @notice Emitted when funds are released\n event FundsReleased(address indexed comptroller, address indexed asset, uint256 amount);\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner.\n * @param protocolIncome_ The address protocol income will be sent to\n * @param riskFund_ Risk fund address\n * @custom:error ZeroAddressNotAllowed is thrown when protocol income address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n */\n function initialize(address protocolIncome_, address riskFund_) external initializer {\n ensureNonzeroAddress(protocolIncome_);\n ensureNonzeroAddress(riskFund_);\n\n __Ownable2Step_init();\n\n protocolIncome = protocolIncome_;\n riskFund = riskFund_;\n }\n\n /**\n * @notice Pool registry setter.\n * @param poolRegistry_ Address of the pool registry\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function setPoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Release funds\n * @param comptroller Pool's Comptroller\n * @param asset Asset to be released\n * @param amount Amount to release\n * @return Number of total released tokens\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function releaseFunds(\n address comptroller,\n address asset,\n uint256 amount\n ) external nonReentrant returns (uint256) {\n ensureNonzeroAddress(asset);\n require(amount <= _poolsAssetsReserves[comptroller][asset], \"ProtocolShareReserve: Insufficient pool balance\");\n\n assetsReserves[asset] -= amount;\n _poolsAssetsReserves[comptroller][asset] -= amount;\n uint256 protocolIncomeAmount = mul_(\n Exp({ mantissa: amount }),\n div_(Exp({ mantissa: PROTOCOL_SHARE_PERCENTAGE * EXP_SCALE }), BASE_UNIT)\n ).mantissa;\n\n address riskFund_ = riskFund;\n\n emit FundsReleased(comptroller, asset, amount);\n\n IERC20Upgradeable(asset).safeTransfer(protocolIncome, protocolIncomeAmount);\n IERC20Upgradeable(asset).safeTransfer(riskFund_, amount - protocolIncomeAmount);\n\n // Update the pool asset's state in the risk fund for the above transfer.\n IRiskFund(riskFund_).updateAssetsState(comptroller, asset);\n\n return amount;\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to the protocol share reserve.\n * @param comptroller Comptroller address(pool)\n * @param asset Asset address.\n */\n function updateAssetsState(address comptroller, address asset)\n public\n override(IProtocolShareReserve, ReserveHelpers)\n {\n super.updateAssetsState(comptroller, asset);\n }\n}\n" + }, + "contracts/RiskFund/ReserveHelpers.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\n\ncontract ReserveHelpers is Ownable2StepUpgradeable {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n uint256 private constant NOT_ENTERED = 1;\n\n uint256 private constant ENTERED = 2;\n\n // Store the previous state for the asset transferred to ProtocolShareReserve combined(for all pools).\n mapping(address => uint256) public assetsReserves;\n\n // Store the asset's reserve per pool in the ProtocolShareReserve.\n // Comptroller(pool) -> Asset -> amount\n mapping(address => mapping(address => uint256)) internal _poolsAssetsReserves;\n\n // Address of pool registry contract\n address public poolRegistry;\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n uint256 internal status;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n */\n uint256[46] private __gap;\n\n /// @notice Event emitted after the update of the assets reserves.\n /// @param comptroller Pool's Comptroller address\n /// @param asset Token address\n /// @param amount An amount by which the reserves have increased\n event AssetsReservesUpdated(address indexed comptroller, address indexed asset, uint256 amount);\n\n /// @notice event emitted on sweep token success\n event SweepToken(address indexed token, address indexed to, uint256 amount);\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(status != ENTERED, \"re-entered\");\n status = ENTERED;\n _;\n status = NOT_ENTERED;\n }\n\n /**\n * @notice A public function to sweep accidental BEP-20 transfers to this contract. Tokens are sent to the address `to`, provided in input\n * @param _token The address of the BEP-20 token to sweep\n * @param _to Recipient of the output tokens.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n * @custom:access Only Owner\n */\n function sweepToken(address _token, address _to) external onlyOwner nonReentrant {\n ensureNonzeroAddress(_to);\n uint256 balanceDfference_;\n uint256 balance_ = IERC20Upgradeable(_token).balanceOf(address(this));\n\n require(balance_ > assetsReserves[_token], \"ReserveHelpers: Zero surplus tokens\");\n unchecked {\n balanceDfference_ = balance_ - assetsReserves[_token];\n }\n\n emit SweepToken(_token, _to, balanceDfference_);\n IERC20Upgradeable(_token).safeTransfer(_to, balanceDfference_);\n }\n\n /**\n * @notice Get the Amount of the asset in the risk fund for the specific pool.\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n * @return Asset's reserve in risk fund.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function getPoolAssetReserve(address comptroller, address asset) external view returns (uint256) {\n ensureNonzeroAddress(asset);\n require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n return _poolsAssetsReserves[comptroller][asset];\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to risk fund\n * and transferring funds to the protocol share reserve\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n * @custom:error ZeroAddressNotAllowed is thrown when asset address is zero\n */\n function updateAssetsState(address comptroller, address asset) public virtual {\n ensureNonzeroAddress(asset);\n require(ComptrollerInterface(comptroller).isComptroller(), \"ReserveHelpers: Comptroller address invalid\");\n address poolRegistry_ = poolRegistry;\n require(poolRegistry_ != address(0), \"ReserveHelpers: Pool Registry address is not set\");\n require(\n PoolRegistryInterface(poolRegistry_).getVTokenForAsset(comptroller, asset) != address(0),\n \"ReserveHelpers: The pool doesn't support the asset\"\n );\n\n uint256 currentBalance = IERC20Upgradeable(asset).balanceOf(address(this));\n uint256 assetReserve = assetsReserves[asset];\n if (currentBalance > assetReserve) {\n uint256 balanceDifference;\n unchecked {\n balanceDifference = currentBalance - assetReserve;\n }\n assetsReserves[asset] += balanceDifference;\n _poolsAssetsReserves[comptroller][asset] += balanceDifference;\n emit AssetsReservesUpdated(comptroller, asset, balanceDifference);\n }\n }\n}\n" + }, + "contracts/RiskFund/RiskFund.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"./IRiskFund.sol\";\nimport { ReserveHelpers } from \"./ReserveHelpers.sol\";\nimport { ExponentialNoError } from \"../ExponentialNoError.sol\";\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { IPancakeswapV2Router } from \"../IPancakeswapV2Router.sol\";\nimport { IShortfall } from \"../Shortfall/IShortfall.sol\";\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { ApproveOrRevert } from \"../lib/ApproveOrRevert.sol\";\n\n/**\n * @title RiskFund\n * @author Venus\n * @notice Contract with basic features to track/hold different assets for different Comptrollers.\n * @dev This contract does not support BNB.\n */\ncontract RiskFund is AccessControlledV8, ExponentialNoError, ReserveHelpers, MaxLoopsLimitHelper, IRiskFund {\n using SafeERC20Upgradeable for IERC20Upgradeable;\n using ApproveOrRevert for IERC20Upgradeable;\n\n address public convertibleBaseAsset;\n address public shortfall;\n address public pancakeSwapRouter;\n uint256 public minAmountToConvert;\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @notice Emitted when shortfall contract address is updated\n event ShortfallContractUpdated(address indexed oldShortfallContract, address indexed newShortfallContract);\n\n /// @notice Emitted when PancakeSwap router contract address is updated\n event PancakeSwapRouterUpdated(address indexed oldPancakeSwapRouter, address indexed newPancakeSwapRouter);\n\n /// @notice Emitted when minimum amount to convert is updated\n event MinAmountToConvertUpdated(uint256 oldMinAmountToConvert, uint256 newMinAmountToConvert);\n\n /// @notice Emitted when pools assets are swapped\n event SwappedPoolsAssets(address[] markets, uint256[] amountsOutMin, uint256 totalAmount);\n\n /// @notice Emitted when reserves are transferred for auction\n event TransferredReserveForAuction(address indexed comptroller, uint256 amount);\n\n /// @dev Note that the contract is upgradeable. Use initialize() or reinitializers\n /// to set the state variables.\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n /**\n * @notice Initializes the deployer to owner.\n * @param pancakeSwapRouter_ Address of the PancakeSwap router\n * @param minAmountToConvert_ Minimum amount assets must be worth to convert into base asset\n * @param convertibleBaseAsset_ Address of the base asset\n * @param accessControlManager_ Address of the access control contract\n * @param loopsLimit_ Limit for the loops in the contract to avoid DOS\n * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n */\n function initialize(\n address pancakeSwapRouter_,\n uint256 minAmountToConvert_,\n address convertibleBaseAsset_,\n address accessControlManager_,\n uint256 loopsLimit_\n ) external initializer {\n ensureNonzeroAddress(pancakeSwapRouter_);\n ensureNonzeroAddress(convertibleBaseAsset_);\n require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n require(loopsLimit_ > 0, \"Risk Fund: Loops limit can not be zero\");\n\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n\n pancakeSwapRouter = pancakeSwapRouter_;\n minAmountToConvert = minAmountToConvert_;\n convertibleBaseAsset = convertibleBaseAsset_;\n\n _setMaxLoopsLimit(loopsLimit_);\n }\n\n /**\n * @notice Pool registry setter\n * @param poolRegistry_ Address of the pool registry\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function setPoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Shortfall contract address setter\n * @param shortfallContractAddress_ Address of the auction contract\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n */\n function setShortfallContractAddress(address shortfallContractAddress_) external onlyOwner {\n ensureNonzeroAddress(shortfallContractAddress_);\n require(\n IShortfall(shortfallContractAddress_).convertibleBaseAsset() == convertibleBaseAsset,\n \"Risk Fund: Base asset doesn't match\"\n );\n\n address oldShortfallContractAddress = shortfall;\n shortfall = shortfallContractAddress_;\n emit ShortfallContractUpdated(oldShortfallContractAddress, shortfallContractAddress_);\n }\n\n /**\n * @notice PancakeSwap router address setter\n * @param pancakeSwapRouter_ Address of the PancakeSwap router\n * @custom:error ZeroAddressNotAllowed is thrown when PCS router address is zero\n */\n function setPancakeSwapRouter(address pancakeSwapRouter_) external onlyOwner {\n ensureNonzeroAddress(pancakeSwapRouter_);\n address oldPancakeSwapRouter = pancakeSwapRouter;\n pancakeSwapRouter = pancakeSwapRouter_;\n emit PancakeSwapRouterUpdated(oldPancakeSwapRouter, pancakeSwapRouter_);\n }\n\n /**\n * @notice Min amount to convert setter\n * @param minAmountToConvert_ Min amount to convert.\n */\n function setMinAmountToConvert(uint256 minAmountToConvert_) external {\n _checkAccessAllowed(\"setMinAmountToConvert(uint256)\");\n require(minAmountToConvert_ > 0, \"Risk Fund: Invalid min amount to convert\");\n uint256 oldMinAmountToConvert = minAmountToConvert;\n minAmountToConvert = minAmountToConvert_;\n emit MinAmountToConvertUpdated(oldMinAmountToConvert, minAmountToConvert_);\n }\n\n /**\n * @notice Swap array of pool assets into base asset's tokens of at least a minimum amount\n * @param markets Array of vTokens whose assets to swap for base asset\n * @param amountsOutMin Minimum amount to receive for swap\n * @param paths A path consisting of PCS token pairs for each swap\n * @param deadline Deadline for the swap\n * @return Number of swapped tokens\n * @custom:error ZeroAddressNotAllowed is thrown if PoolRegistry contract address is not configured\n */\n function swapPoolsAssets(\n address[] calldata markets,\n uint256[] calldata amountsOutMin,\n address[][] calldata paths,\n uint256 deadline\n ) external override nonReentrant returns (uint256) {\n _checkAccessAllowed(\"swapPoolsAssets(address[],uint256[],address[][],uint256)\");\n require(deadline >= block.timestamp, \"Risk fund: deadline passed\");\n address poolRegistry_ = poolRegistry;\n ensureNonzeroAddress(poolRegistry_);\n require(markets.length == amountsOutMin.length, \"Risk fund: markets and amountsOutMin are unequal lengths\");\n require(markets.length == paths.length, \"Risk fund: markets and paths are unequal lengths\");\n\n uint256 totalAmount;\n uint256 marketsCount = markets.length;\n\n _ensureMaxLoops(marketsCount);\n\n for (uint256 i; i < marketsCount; ++i) {\n address comptroller = address(VToken(markets[i]).comptroller());\n\n PoolRegistry.VenusPool memory pool = PoolRegistry(poolRegistry_).getPoolByComptroller(comptroller);\n require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n require(Comptroller(comptroller).isMarketListed(VToken(markets[i])), \"market is not listed\");\n\n uint256 swappedTokens = _swapAsset(VToken(markets[i]), comptroller, amountsOutMin[i], paths[i]);\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] += swappedTokens;\n assetsReserves[convertibleBaseAsset] += swappedTokens;\n totalAmount = totalAmount + swappedTokens;\n }\n\n emit SwappedPoolsAssets(markets, amountsOutMin, totalAmount);\n\n return totalAmount;\n }\n\n /**\n * @notice Transfer tokens for auction.\n * @param comptroller Comptroller of the pool.\n * @param amount Amount to be transferred to auction contract.\n * @return Number reserved tokens.\n */\n function transferReserveForAuction(address comptroller, uint256 amount)\n external\n override\n nonReentrant\n returns (uint256)\n {\n address shortfall_ = shortfall;\n require(msg.sender == shortfall_, \"Risk fund: Only callable by Shortfall contract\");\n require(\n amount <= _poolsAssetsReserves[comptroller][convertibleBaseAsset],\n \"Risk Fund: Insufficient pool reserve.\"\n );\n unchecked {\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] =\n _poolsAssetsReserves[comptroller][convertibleBaseAsset] -\n amount;\n }\n unchecked {\n assetsReserves[convertibleBaseAsset] = assetsReserves[convertibleBaseAsset] - amount;\n }\n\n emit TransferredReserveForAuction(comptroller, amount);\n IERC20Upgradeable(convertibleBaseAsset).safeTransfer(shortfall_, amount);\n\n return amount;\n }\n\n /**\n * @notice Set the limit for the loops can iterate to avoid the DOS\n * @param limit Limit for the max loops can execute at a time\n */\n function setMaxLoopsLimit(uint256 limit) external onlyOwner {\n _setMaxLoopsLimit(limit);\n }\n\n /**\n * @notice Get the Amount of the Base asset in the risk fund for the specific pool.\n * @param comptroller Comptroller address(pool).\n * @return Base Asset's reserve in risk fund.\n */\n function getPoolsBaseAssetReserves(address comptroller) external view returns (uint256) {\n require(ComptrollerInterface(comptroller).isComptroller(), \"Risk Fund: Comptroller address invalid\");\n return _poolsAssetsReserves[comptroller][convertibleBaseAsset];\n }\n\n /**\n * @notice Update the reserve of the asset for the specific pool after transferring to risk fund.\n * @param comptroller Comptroller address(pool).\n * @param asset Asset address.\n */\n function updateAssetsState(address comptroller, address asset) public override(IRiskFund, ReserveHelpers) {\n super.updateAssetsState(comptroller, asset);\n }\n\n /**\n * @dev Swap single asset to base asset.\n * @param vToken VToken\n * @param comptroller Comptroller address\n * @param amountOutMin Minimum amount to receive for swap\n * @param path A path for the swap consisting of PCS token pairs\n * @return Number of swapped tokens.\n */\n function _swapAsset(\n VToken vToken,\n address comptroller,\n uint256 amountOutMin,\n address[] calldata path\n ) internal returns (uint256) {\n require(amountOutMin != 0, \"RiskFund: amountOutMin must be greater than 0 to swap vToken\");\n uint256 totalAmount;\n\n address underlyingAsset = vToken.underlying();\n address convertibleBaseAsset_ = convertibleBaseAsset;\n uint256 balanceOfUnderlyingAsset = _poolsAssetsReserves[comptroller][underlyingAsset];\n\n if (balanceOfUnderlyingAsset == 0) {\n return 0;\n }\n\n ResilientOracleInterface oracle = ComptrollerViewInterface(comptroller).oracle();\n oracle.updateAssetPrice(convertibleBaseAsset_);\n Exp memory baseAssetPrice = Exp({ mantissa: oracle.getPrice(convertibleBaseAsset_) });\n uint256 amountOutMinInUsd = mul_ScalarTruncate(baseAssetPrice, amountOutMin);\n\n require(amountOutMinInUsd >= minAmountToConvert, \"RiskFund: minAmountToConvert violated\");\n\n assetsReserves[underlyingAsset] -= balanceOfUnderlyingAsset;\n _poolsAssetsReserves[comptroller][underlyingAsset] -= balanceOfUnderlyingAsset;\n\n if (underlyingAsset != convertibleBaseAsset_) {\n require(path[0] == underlyingAsset, \"RiskFund: swap path must start with the underlying asset\");\n require(\n path[path.length - 1] == convertibleBaseAsset_,\n \"RiskFund: finally path must be convertible base asset\"\n );\n address pancakeSwapRouter_ = pancakeSwapRouter;\n IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, 0);\n IERC20Upgradeable(underlyingAsset).approveOrRevert(pancakeSwapRouter_, balanceOfUnderlyingAsset);\n uint256[] memory amounts = IPancakeswapV2Router(pancakeSwapRouter_).swapExactTokensForTokens(\n balanceOfUnderlyingAsset,\n amountOutMin,\n path,\n address(this),\n block.timestamp\n );\n totalAmount = amounts[path.length - 1];\n } else {\n totalAmount = balanceOfUnderlyingAsset;\n }\n\n return totalAmount;\n }\n}\n" + }, + "contracts/Shortfall/IShortfall.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\n/**\n * @title IShortfall\n * @author Venus\n * @notice Interface implemented by `Shortfall`.\n */\ninterface IShortfall {\n function convertibleBaseAsset() external returns (address);\n}\n" + }, + "contracts/Shortfall/Shortfall.sol": { + "content": "/// @notice SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"../ComptrollerInterface.sol\";\nimport { IRiskFund } from \"../RiskFund/IRiskFund.sol\";\nimport { IShortfall } from \"./IShortfall.sol\";\nimport { PoolRegistry } from \"../Pool/PoolRegistry.sol\";\nimport { PoolRegistryInterface } from \"../Pool/PoolRegistryInterface.sol\";\nimport { TokenDebtTracker } from \"../lib/TokenDebtTracker.sol\";\nimport { ensureNonzeroAddress } from \"../lib/validators.sol\";\nimport { EXP_SCALE } from \"../lib/constants.sol\";\n\n/**\n * @title Shortfall\n * @author Venus\n * @notice Shortfall is an auction contract designed to auction off the `convertibleBaseAsset` accumulated in `RiskFund`. The `convertibleBaseAsset`\n * is auctioned in exchange for users paying off the pool's bad debt. An auction can be started by anyone once a pool's bad debt has reached a minimum value.\n * This value is set and can be changed by the authorized accounts. If the pool’s bad debt exceeds the risk fund plus a 10% incentive, then the auction winner\n * is determined by who will pay off the largest percentage of the pool's bad debt. The auction winner then exchanges for the entire risk fund. Otherwise,\n * if the risk fund covers the pool's bad debt plus the 10% incentive, then the auction winner is determined by who will take the smallest percentage of the\n * risk fund in exchange for paying off all the pool's bad debt.\n */\ncontract Shortfall is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n ReentrancyGuardUpgradeable,\n TokenDebtTracker,\n IShortfall\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n /// @notice Type of auction\n enum AuctionType {\n LARGE_POOL_DEBT,\n LARGE_RISK_FUND\n }\n\n /// @notice Status of auction\n enum AuctionStatus {\n NOT_STARTED,\n STARTED,\n ENDED\n }\n\n /// @notice Auction metadata\n struct Auction {\n uint256 startBlock;\n AuctionType auctionType;\n AuctionStatus status;\n VToken[] markets;\n uint256 seizedRiskFund;\n address highestBidder;\n uint256 highestBidBps;\n uint256 highestBidBlock;\n uint256 startBidBps;\n mapping(VToken => uint256) marketDebt;\n mapping(VToken => uint256) bidAmount;\n }\n\n /// @dev Max basis points i.e., 100%\n uint256 private constant MAX_BPS = 10000;\n\n uint256 private constant DEFAULT_NEXT_BIDDER_BLOCK_LIMIT = 100;\n\n uint256 private constant DEFAULT_WAIT_FOR_FIRST_BIDDER = 100;\n\n uint256 private constant DEFAULT_INCENTIVE_BPS = 1000; // 10%\n\n /// @notice Pool registry address\n address public poolRegistry;\n\n /// @notice Risk fund address\n IRiskFund public riskFund;\n\n /// @notice Minimum USD debt in pool for shortfall to trigger\n uint256 public minimumPoolBadDebt;\n\n /// @notice Incentive to auction participants, initial value set to 1000 or 10%\n uint256 public incentiveBps;\n\n /// @notice Time to wait for next bidder. Initially waits for 100 blocks\n uint256 public nextBidderBlockLimit;\n\n /// @notice Boolean of if auctions are paused\n bool public auctionsPaused;\n\n /// @notice Time to wait for first bidder. Initially waits for 100 blocks\n uint256 public waitForFirstBidder;\n\n /// @notice base asset contract address\n address public convertibleBaseAsset;\n\n /// @notice Auctions for each pool\n mapping(address => Auction) public auctions;\n\n /// @notice Emitted when a auction starts\n event AuctionStarted(\n address indexed comptroller,\n uint256 auctionStartBlock,\n AuctionType auctionType,\n VToken[] markets,\n uint256[] marketsDebt,\n uint256 seizedRiskFund,\n uint256 startBidBps\n );\n\n /// @notice Emitted when a bid is placed\n event BidPlaced(address indexed comptroller, uint256 auctionStartBlock, uint256 bidBps, address indexed bidder);\n\n /// @notice Emitted when a auction is completed\n event AuctionClosed(\n address indexed comptroller,\n uint256 auctionStartBlock,\n address indexed highestBidder,\n uint256 highestBidBps,\n uint256 seizedRiskFind,\n VToken[] markets,\n uint256[] marketDebt\n );\n\n /// @notice Emitted when a auction is restarted\n event AuctionRestarted(address indexed comptroller, uint256 auctionStartBlock);\n\n /// @notice Emitted when pool registry address is updated\n event PoolRegistryUpdated(address indexed oldPoolRegistry, address indexed newPoolRegistry);\n\n /// @notice Emitted when minimum pool bad debt is updated\n event MinimumPoolBadDebtUpdated(uint256 oldMinimumPoolBadDebt, uint256 newMinimumPoolBadDebt);\n\n /// @notice Emitted when wait for first bidder block count is updated\n event WaitForFirstBidderUpdated(uint256 oldWaitForFirstBidder, uint256 newWaitForFirstBidder);\n\n /// @notice Emitted when next bidder block limit is updated\n event NextBidderBlockLimitUpdated(uint256 oldNextBidderBlockLimit, uint256 newNextBidderBlockLimit);\n\n /// @notice Emitted when incentiveBps is updated\n event IncentiveBpsUpdated(uint256 oldIncentiveBps, uint256 newIncentiveBps);\n\n /// @notice Emitted when auctions are paused\n event AuctionsPaused(address sender);\n\n /// @notice Emitted when auctions are unpaused\n event AuctionsResumed(address sender);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Initialize the shortfall contract\n * @param convertibleBaseAsset_ Asset to swap the funds to\n * @param riskFund_ RiskFund contract address\n * @param minimumPoolBadDebt_ Minimum bad debt in base asset for a pool to start auction\n * @param accessControlManager_ AccessControlManager contract address\n * @custom:error ZeroAddressNotAllowed is thrown when convertible base asset address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when risk fund address is zero\n */\n function initialize(\n address convertibleBaseAsset_,\n IRiskFund riskFund_,\n uint256 minimumPoolBadDebt_,\n address accessControlManager_\n ) external initializer {\n ensureNonzeroAddress(convertibleBaseAsset_);\n ensureNonzeroAddress(address(riskFund_));\n require(minimumPoolBadDebt_ != 0, \"invalid minimum pool bad debt\");\n\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n __ReentrancyGuard_init();\n __TokenDebtTracker_init();\n minimumPoolBadDebt = minimumPoolBadDebt_;\n convertibleBaseAsset = convertibleBaseAsset_;\n riskFund = riskFund_;\n waitForFirstBidder = DEFAULT_WAIT_FOR_FIRST_BIDDER;\n nextBidderBlockLimit = DEFAULT_NEXT_BIDDER_BLOCK_LIMIT;\n incentiveBps = DEFAULT_INCENTIVE_BPS;\n auctionsPaused = false;\n }\n\n /**\n * @notice Place a bid greater than the previous in an ongoing auction\n * @param comptroller Comptroller address of the pool\n * @param bidBps The bid percent of the risk fund or bad debt depending on auction type\n * @param auctionStartBlock The block number when auction started\n * @custom:event Emits BidPlaced event on success\n */\n function placeBid(\n address comptroller,\n uint256 bidBps,\n uint256 auctionStartBlock\n ) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(auction.startBlock == auctionStartBlock, \"auction has been restarted\");\n require(_isStarted(auction), \"no on-going auction\");\n require(!_isStale(auction), \"auction is stale, restart it\");\n require(bidBps > 0, \"basis points cannot be zero\");\n require(bidBps <= MAX_BPS, \"basis points cannot be more than 10000\");\n require(\n (auction.auctionType == AuctionType.LARGE_POOL_DEBT &&\n ((auction.highestBidder != address(0) && bidBps > auction.highestBidBps) ||\n (auction.highestBidder == address(0) && bidBps >= auction.startBidBps))) ||\n (auction.auctionType == AuctionType.LARGE_RISK_FUND &&\n ((auction.highestBidder != address(0) && bidBps < auction.highestBidBps) ||\n (auction.highestBidder == address(0) && bidBps <= auction.startBidBps))),\n \"your bid is not the highest\"\n );\n\n uint256 marketsCount = auction.markets.length;\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = VToken(address(auction.markets[i]));\n IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n if (auction.highestBidder != address(0)) {\n _transferOutOrTrackDebt(erc20, auction.highestBidder, auction.bidAmount[auction.markets[i]]);\n }\n uint256 balanceBefore = erc20.balanceOf(address(this));\n\n if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n uint256 currentBidAmount = ((auction.marketDebt[auction.markets[i]] * bidBps) / MAX_BPS);\n erc20.safeTransferFrom(msg.sender, address(this), currentBidAmount);\n } else {\n erc20.safeTransferFrom(msg.sender, address(this), auction.marketDebt[auction.markets[i]]);\n }\n\n uint256 balanceAfter = erc20.balanceOf(address(this));\n auction.bidAmount[auction.markets[i]] = balanceAfter - balanceBefore;\n }\n\n auction.highestBidder = msg.sender;\n auction.highestBidBps = bidBps;\n auction.highestBidBlock = block.number;\n\n emit BidPlaced(comptroller, auction.startBlock, bidBps, msg.sender);\n }\n\n /**\n * @notice Close an auction\n * @param comptroller Comptroller address of the pool\n * @custom:event Emits AuctionClosed event on successful close\n */\n function closeAuction(address comptroller) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(_isStarted(auction), \"no on-going auction\");\n require(\n block.number > auction.highestBidBlock + nextBidderBlockLimit && auction.highestBidder != address(0),\n \"waiting for next bidder. cannot close auction\"\n );\n\n uint256 marketsCount = auction.markets.length;\n uint256[] memory marketsDebt = new uint256[](marketsCount);\n\n auction.status = AuctionStatus.ENDED;\n\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = VToken(address(auction.markets[i]));\n IERC20Upgradeable erc20 = IERC20Upgradeable(address(vToken.underlying()));\n\n uint256 balanceBefore = erc20.balanceOf(address(auction.markets[i]));\n erc20.safeTransfer(address(auction.markets[i]), auction.bidAmount[auction.markets[i]]);\n uint256 balanceAfter = erc20.balanceOf(address(auction.markets[i]));\n marketsDebt[i] = balanceAfter - balanceBefore;\n\n auction.markets[i].badDebtRecovered(marketsDebt[i]);\n }\n\n uint256 riskFundBidAmount;\n\n if (auction.auctionType == AuctionType.LARGE_POOL_DEBT) {\n riskFundBidAmount = auction.seizedRiskFund;\n } else {\n riskFundBidAmount = (auction.seizedRiskFund * auction.highestBidBps) / MAX_BPS;\n }\n\n uint256 transferredAmount = riskFund.transferReserveForAuction(comptroller, riskFundBidAmount);\n _transferOutOrTrackDebt(IERC20Upgradeable(convertibleBaseAsset), auction.highestBidder, riskFundBidAmount);\n\n emit AuctionClosed(\n comptroller,\n auction.startBlock,\n auction.highestBidder,\n auction.highestBidBps,\n transferredAmount,\n auction.markets,\n marketsDebt\n );\n }\n\n /**\n * @notice Start a auction when there is not currently one active\n * @param comptroller Comptroller address of the pool\n * @custom:event Emits AuctionStarted event on success\n * @custom:event Errors if auctions are paused\n */\n function startAuction(address comptroller) external nonReentrant {\n require(!auctionsPaused, \"Auctions are paused\");\n _startAuction(comptroller);\n }\n\n /**\n * @notice Restart an auction\n * @param comptroller Address of the pool\n * @custom:event Emits AuctionRestarted event on successful restart\n */\n function restartAuction(address comptroller) external nonReentrant {\n Auction storage auction = auctions[comptroller];\n\n require(!auctionsPaused, \"auctions are paused\");\n require(_isStarted(auction), \"no on-going auction\");\n require(_isStale(auction), \"you need to wait for more time for first bidder\");\n\n auction.status = AuctionStatus.ENDED;\n\n emit AuctionRestarted(comptroller, auction.startBlock);\n _startAuction(comptroller);\n }\n\n /**\n * @notice Update next bidder block limit which is used determine when an auction can be closed\n * @param _nextBidderBlockLimit New next bidder block limit\n * @custom:event Emits NextBidderBlockLimitUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateNextBidderBlockLimit(uint256 _nextBidderBlockLimit) external {\n _checkAccessAllowed(\"updateNextBidderBlockLimit(uint256)\");\n require(_nextBidderBlockLimit != 0, \"_nextBidderBlockLimit must not be 0\");\n uint256 oldNextBidderBlockLimit = nextBidderBlockLimit;\n nextBidderBlockLimit = _nextBidderBlockLimit;\n emit NextBidderBlockLimitUpdated(oldNextBidderBlockLimit, _nextBidderBlockLimit);\n }\n\n /**\n * @notice Updates the incentive BPS\n * @param _incentiveBps New incentive BPS\n * @custom:event Emits IncentiveBpsUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateIncentiveBps(uint256 _incentiveBps) external {\n _checkAccessAllowed(\"updateIncentiveBps(uint256)\");\n require(_incentiveBps != 0, \"incentiveBps must not be 0\");\n uint256 oldIncentiveBps = incentiveBps;\n incentiveBps = _incentiveBps;\n emit IncentiveBpsUpdated(oldIncentiveBps, _incentiveBps);\n }\n\n /**\n * @notice Update minimum pool bad debt to start auction\n * @param _minimumPoolBadDebt Minimum bad debt in BUSD for a pool to start auction\n * @custom:event Emits MinimumPoolBadDebtUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateMinimumPoolBadDebt(uint256 _minimumPoolBadDebt) external {\n _checkAccessAllowed(\"updateMinimumPoolBadDebt(uint256)\");\n uint256 oldMinimumPoolBadDebt = minimumPoolBadDebt;\n minimumPoolBadDebt = _minimumPoolBadDebt;\n emit MinimumPoolBadDebtUpdated(oldMinimumPoolBadDebt, _minimumPoolBadDebt);\n }\n\n /**\n * @notice Update wait for first bidder block count. If the first bid is not made within this limit, the auction is closed and needs to be restarted\n * @param _waitForFirstBidder New wait for first bidder block count\n * @custom:event Emits WaitForFirstBidderUpdated on success\n * @custom:access Restricted by ACM\n */\n function updateWaitForFirstBidder(uint256 _waitForFirstBidder) external {\n _checkAccessAllowed(\"updateWaitForFirstBidder(uint256)\");\n uint256 oldWaitForFirstBidder = waitForFirstBidder;\n waitForFirstBidder = _waitForFirstBidder;\n emit WaitForFirstBidderUpdated(oldWaitForFirstBidder, _waitForFirstBidder);\n }\n\n /**\n * @notice Update the pool registry this shortfall supports\n * @dev After Pool Registry is deployed we need to set the pool registry address\n * @param poolRegistry_ Address of pool registry contract\n * @custom:event Emits PoolRegistryUpdated on success\n * @custom:access Restricted to owner\n * @custom:error ZeroAddressNotAllowed is thrown when pool registry address is zero\n */\n function updatePoolRegistry(address poolRegistry_) external onlyOwner {\n ensureNonzeroAddress(poolRegistry_);\n address oldPoolRegistry = poolRegistry;\n poolRegistry = poolRegistry_;\n emit PoolRegistryUpdated(oldPoolRegistry, poolRegistry_);\n }\n\n /**\n * @notice Pause auctions. This disables starting new auctions but lets the current auction finishes\n * @custom:event Emits AuctionsPaused on success\n * @custom:error Errors is auctions are paused\n * @custom:access Restricted by ACM\n */\n function pauseAuctions() external {\n _checkAccessAllowed(\"pauseAuctions()\");\n require(!auctionsPaused, \"Auctions are already paused\");\n auctionsPaused = true;\n emit AuctionsPaused(msg.sender);\n }\n\n /**\n * @notice Resume paused auctions.\n * @custom:event Emits AuctionsResumed on success\n * @custom:error Errors is auctions are active\n * @custom:access Restricted by ACM\n */\n function resumeAuctions() external {\n _checkAccessAllowed(\"resumeAuctions()\");\n require(auctionsPaused, \"Auctions are not paused\");\n auctionsPaused = false;\n emit AuctionsResumed(msg.sender);\n }\n\n /**\n * @notice Start a auction when there is not currently one active\n * @param comptroller Comptroller address of the pool\n */\n function _startAuction(address comptroller) internal {\n PoolRegistryInterface.VenusPool memory pool = PoolRegistry(poolRegistry).getPoolByComptroller(comptroller);\n require(pool.comptroller == comptroller, \"comptroller doesn't exist pool registry\");\n\n Auction storage auction = auctions[comptroller];\n require(\n auction.status == AuctionStatus.NOT_STARTED || auction.status == AuctionStatus.ENDED,\n \"auction is on-going\"\n );\n\n auction.highestBidBps = 0;\n auction.highestBidBlock = 0;\n\n uint256 marketsCount = auction.markets.length;\n for (uint256 i; i < marketsCount; ++i) {\n VToken vToken = auction.markets[i];\n auction.marketDebt[vToken] = 0;\n }\n\n delete auction.markets;\n\n VToken[] memory vTokens = _getAllMarkets(comptroller);\n marketsCount = vTokens.length;\n ResilientOracleInterface priceOracle = _getPriceOracle(comptroller);\n uint256 poolBadDebt;\n\n uint256[] memory marketsDebt = new uint256[](marketsCount);\n auction.markets = new VToken[](marketsCount);\n\n for (uint256 i; i < marketsCount; ++i) {\n uint256 marketBadDebt = vTokens[i].badDebt();\n\n priceOracle.updatePrice(address(vTokens[i]));\n uint256 usdValue = (priceOracle.getUnderlyingPrice(address(vTokens[i])) * marketBadDebt) / EXP_SCALE;\n\n poolBadDebt = poolBadDebt + usdValue;\n auction.markets[i] = vTokens[i];\n auction.marketDebt[vTokens[i]] = marketBadDebt;\n marketsDebt[i] = marketBadDebt;\n }\n\n require(poolBadDebt >= minimumPoolBadDebt, \"pool bad debt is too low\");\n\n priceOracle.updateAssetPrice(riskFund.convertibleBaseAsset());\n uint256 riskFundBalance = (priceOracle.getPrice(riskFund.convertibleBaseAsset()) *\n riskFund.getPoolsBaseAssetReserves(comptroller)) / EXP_SCALE;\n uint256 remainingRiskFundBalance = riskFundBalance;\n uint256 badDebtPlusIncentive = poolBadDebt + ((poolBadDebt * incentiveBps) / MAX_BPS);\n if (badDebtPlusIncentive >= riskFundBalance) {\n auction.startBidBps =\n (MAX_BPS * MAX_BPS * remainingRiskFundBalance) /\n (poolBadDebt * (MAX_BPS + incentiveBps));\n remainingRiskFundBalance = 0;\n auction.auctionType = AuctionType.LARGE_POOL_DEBT;\n } else {\n uint256 maxSeizeableRiskFundBalance = badDebtPlusIncentive;\n\n remainingRiskFundBalance = remainingRiskFundBalance - maxSeizeableRiskFundBalance;\n auction.auctionType = AuctionType.LARGE_RISK_FUND;\n auction.startBidBps = MAX_BPS;\n }\n\n auction.seizedRiskFund = riskFundBalance - remainingRiskFundBalance;\n auction.startBlock = block.number;\n auction.status = AuctionStatus.STARTED;\n auction.highestBidder = address(0);\n\n emit AuctionStarted(\n comptroller,\n auction.startBlock,\n auction.auctionType,\n auction.markets,\n marketsDebt,\n auction.seizedRiskFund,\n auction.startBidBps\n );\n }\n\n /**\n * @dev Returns the price oracle of the pool\n * @param comptroller Address of the pool's comptroller\n * @return oracle The pool's price oracle\n */\n function _getPriceOracle(address comptroller) internal view returns (ResilientOracleInterface) {\n return ResilientOracleInterface(ComptrollerViewInterface(comptroller).oracle());\n }\n\n /**\n * @dev Returns all markets of the pool\n * @param comptroller Address of the pool's comptroller\n * @return markets The pool's markets as VToken array\n */\n function _getAllMarkets(address comptroller) internal view returns (VToken[] memory) {\n return ComptrollerInterface(comptroller).getAllMarkets();\n }\n\n /**\n * @dev Checks if the auction has started\n * @param auction The auction to query the status for\n * @return True if the auction has started\n */\n function _isStarted(Auction storage auction) internal view returns (bool) {\n return auction.status == AuctionStatus.STARTED;\n }\n\n /**\n * @dev Checks if the auction is stale, i.e. there's no bidder and the auction\n * was started more than waitForFirstBidder blocks ago.\n * @param auction The auction to query the status for\n * @return True if the auction is stale\n */\n function _isStale(Auction storage auction) internal view returns (bool) {\n bool noBidder = auction.highestBidder == address(0);\n return noBidder && (block.number > auction.startBlock + waitForFirstBidder);\n }\n}\n" + }, + "contracts/test/ComptrollerHarness.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { Comptroller } from \"../Comptroller.sol\";\n\ncontract ComptrollerHarness is Comptroller {\n uint256 public blockNumber;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n function harnessFastForward(uint256 blocks) public returns (uint256) {\n blockNumber += blocks;\n return blockNumber;\n }\n\n function setBlockNumber(uint256 number) public {\n blockNumber = number;\n }\n}\n\ncontract EchoTypesComptroller {\n function stringy(string memory s) public pure returns (string memory) {\n return s;\n }\n\n function addresses(address a) public pure returns (address) {\n return a;\n }\n\n function booly(bool b) public pure returns (bool) {\n return b;\n }\n\n function listOInts(uint256[] memory u) public pure returns (uint256[] memory) {\n return u;\n }\n\n function reverty() public pure {\n require(false, \"gotcha sucka\");\n }\n}\n" + }, + "contracts/test/ComptrollerScenario.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { Comptroller } from \"../Comptroller.sol\";\nimport { VToken } from \"../VToken.sol\";\n\ncontract ComptrollerScenario is Comptroller {\n uint256 public blockNumber;\n\n // solhint-disable-next-line no-empty-blocks\n constructor(address _poolRegistry) Comptroller(_poolRegistry) {}\n\n function fastForward(uint256 blocks) public returns (uint256) {\n blockNumber += blocks;\n return blockNumber;\n }\n\n function setBlockNumber(uint256 number) public {\n blockNumber = number;\n }\n\n function unlist(VToken vToken) public {\n markets[address(vToken)].isListed = false;\n }\n\n function membershipLength(VToken vToken) public view returns (uint256) {\n return accountAssets[address(vToken)].length;\n }\n}\n" + }, + "contracts/test/ERC20.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { SafeMath } from \"./SafeMath.sol\";\n\ninterface ERC20Base {\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n function approve(address spender, uint256 value) external returns (bool);\n\n function totalSupply() external view returns (uint256);\n\n function allowance(address owner, address spender) external view returns (uint256);\n\n function balanceOf(address who) external view returns (uint256);\n}\n\nabstract contract ERC20 is ERC20Base {\n function transfer(address to, uint256 value) external virtual returns (bool);\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external virtual returns (bool);\n}\n\nabstract contract ERC20NS is ERC20Base {\n function transfer(address to, uint256 value) external virtual;\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external virtual;\n}\n\n/**\n * @title Standard ERC20 token\n * @dev Implementation of the basic standard token.\n * See https://github.com/ethereum/EIPs/issues/20\n */\ncontract StandardToken is ERC20 {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external virtual override returns (bool) {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external virtual override returns (bool) {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function approve(address _spender, uint256 amount) external virtual override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\n/**\n * @title Non-Standard ERC20 token\n * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`\n * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca\n */\ncontract NonStandardToken is ERC20NS {\n using SafeMath for uint256;\n\n string public name;\n uint8 public decimals;\n string public symbol;\n uint256 public override totalSupply;\n mapping(address => mapping(address => uint256)) public override allowance;\n mapping(address => uint256) public override balanceOf;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) {\n totalSupply = _initialAmount;\n balanceOf[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n }\n\n function transfer(address dst, uint256 amount) external override {\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override {\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n }\n\n function approve(address _spender, uint256 amount) external override returns (bool) {\n allowance[msg.sender][_spender] = amount;\n emit Approval(msg.sender, _spender, amount);\n return true;\n }\n}\n\ncontract ERC20Harness is StandardToken {\n using SafeMath for uint256;\n // To support testing, we can specify addresses for which transferFrom should fail and return false\n mapping(address => bool) public failTransferFromAddresses;\n\n // To support testing, we allow the contract to always fail `transfer`.\n mapping(address => bool) public failTransferToAddresses;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferToAddresses[dst]) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override returns (bool success) {\n // Added for testing purposes\n if (failTransferFromAddresses[src]) {\n return false;\n }\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount, \"Insufficient allowance\");\n balanceOf[src] = balanceOf[src].sub(amount, \"Insufficient balance\");\n balanceOf[dst] = balanceOf[dst].add(amount, \"Balance overflow\");\n emit Transfer(src, dst, amount);\n return true;\n }\n\n function harnessSetFailTransferFromAddress(address src, bool _fail) public {\n failTransferFromAddresses[src] = _fail;\n }\n\n function harnessSetFailTransferToAddress(address dst, bool _fail) public {\n failTransferToAddresses[dst] = _fail;\n }\n\n function harnessSetBalance(address _account, uint256 _amount) public {\n balanceOf[_account] = _amount;\n }\n}\n" + }, + "contracts/test/EvilToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { FaucetToken } from \"./FaucetToken.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title The Compound Evil Test Token\n * @author Compound\n * @notice A simple test token that fails certain operations\n */\ncontract EvilToken is FaucetToken {\n using SafeMath for uint256;\n\n bool public fail;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n ) FaucetToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {\n fail = true;\n }\n\n function setFail(bool _fail) external {\n fail = _fail;\n }\n\n function transfer(address dst, uint256 amount) external override returns (bool) {\n if (fail) {\n return false;\n }\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(amount);\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override returns (bool) {\n if (fail) {\n return false;\n }\n balanceOf[src] = balanceOf[src].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(amount);\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" + }, + "contracts/test/FaucetToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { StandardToken, NonStandardToken } from \"./ERC20.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title The Compound Faucet Test Token\n * @author Compound\n * @notice A simple test token that lets anyone get more of it.\n */\ncontract FaucetToken is StandardToken {\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n StandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf[_owner] += value;\n totalSupply += value;\n emit Transfer(address(this), _owner, value);\n }\n}\n\n/**\n * @title The Compound Faucet Test Token (non-standard)\n * @author Compound\n * @notice A simple test token that lets anyone get more of it.\n */\ncontract FaucetNonStandardToken is NonStandardToken {\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol\n )\n NonStandardToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)\n /* solhint-disable-next-line no-empty-blocks */\n {\n\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf[_owner] += value;\n totalSupply += value;\n emit Transfer(address(this), _owner, value);\n }\n}\n\n/**\n * @title The Compound Faucet Re-Entrant Test Token\n * @author Compound\n * @notice A test token that is malicious and tries to re-enter callers\n */\ncontract FaucetTokenReEntrantHarness {\n using SafeMath for uint256;\n\n string public name;\n string public symbol;\n uint8 public decimals;\n uint256 private totalSupply_;\n mapping(address => mapping(address => uint256)) private allowance_;\n mapping(address => uint256) private balanceOf_;\n\n bytes public reEntryCallData;\n string public reEntryFun;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n modifier reEnter(string memory funName) {\n string memory _reEntryFun = reEntryFun;\n if (compareStrings(_reEntryFun, funName)) {\n reEntryFun = \"\"; // Clear re-entry fun\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = msg.sender.call(reEntryCallData);\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 0) {\n revert(add(returndata, 0x20), returndatasize())\n }\n }\n }\n\n _;\n }\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol,\n bytes memory _reEntryCallData,\n string memory _reEntryFun\n ) {\n totalSupply_ = _initialAmount;\n balanceOf_[msg.sender] = _initialAmount;\n name = _tokenName;\n symbol = _tokenSymbol;\n decimals = _decimalUnits;\n reEntryCallData = _reEntryCallData;\n reEntryFun = _reEntryFun;\n }\n\n function allocateTo(address _owner, uint256 value) public {\n balanceOf_[_owner] += value;\n totalSupply_ += value;\n emit Transfer(address(this), _owner, value);\n }\n\n function totalSupply() public reEnter(\"totalSupply\") returns (uint256) {\n return totalSupply_;\n }\n\n function allowance(address owner, address spender) public reEnter(\"allowance\") returns (uint256 remaining) {\n return allowance_[owner][spender];\n }\n\n function approve(address spender, uint256 amount) public reEnter(\"approve\") returns (bool success) {\n _approve(msg.sender, spender, amount);\n return true;\n }\n\n function balanceOf(address owner) public reEnter(\"balanceOf\") returns (uint256 balance) {\n return balanceOf_[owner];\n }\n\n function transfer(address dst, uint256 amount) public reEnter(\"transfer\") returns (bool success) {\n _transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) public reEnter(\"transferFrom\") returns (bool success) {\n _transfer(src, dst, amount);\n _approve(src, msg.sender, allowance_[src][msg.sender].sub(amount));\n return true;\n }\n\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(spender != address(0), \"FaucetToken: approve to the zero address\");\n require(owner != address(0), \"FaucetToken: approve from the zero address\");\n allowance_[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n function _transfer(\n address src,\n address dst,\n uint256 amount\n ) internal {\n require(dst != address(0), \"FaucetToken: transfer to the zero address\");\n balanceOf_[src] = balanceOf_[src].sub(amount);\n balanceOf_[dst] = balanceOf_[dst].add(amount);\n emit Transfer(src, dst, amount);\n }\n\n function compareStrings(string memory a, string memory b) internal pure returns (bool) {\n return keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)));\n }\n}\n" + }, + "contracts/test/FeeToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { FaucetToken } from \"./FaucetToken.sol\";\nimport { SafeMath } from \"./SafeMath.sol\";\n\n/**\n * @title Fee Token\n * @author Compound\n * @notice A simple test token that charges fees on transfer. Used to mock USDT.\n */\ncontract FeeToken is FaucetToken {\n using SafeMath for uint256;\n\n uint256 public basisPointFee;\n address public owner;\n\n constructor(\n uint256 _initialAmount,\n string memory _tokenName,\n uint8 _decimalUnits,\n string memory _tokenSymbol,\n uint256 _basisPointFee,\n address _owner\n ) FaucetToken(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol) {\n basisPointFee = _basisPointFee;\n owner = _owner;\n }\n\n function transfer(address dst, uint256 amount) public override returns (bool) {\n uint256 fee = amount.mul(basisPointFee).div(10000);\n uint256 net = amount.sub(fee);\n balanceOf[owner] = balanceOf[owner].add(fee);\n balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(net);\n emit Transfer(msg.sender, dst, amount);\n return true;\n }\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) public override returns (bool) {\n uint256 fee = amount.mul(basisPointFee).div(10000);\n uint256 net = amount.sub(fee);\n balanceOf[owner] = balanceOf[owner].add(fee);\n balanceOf[src] = balanceOf[src].sub(amount);\n balanceOf[dst] = balanceOf[dst].add(net);\n allowance[src][msg.sender] = allowance[src][msg.sender].sub(amount);\n emit Transfer(src, dst, amount);\n return true;\n }\n}\n" + }, + "contracts/test/HarnessMaxLoopsLimitHelper.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { MaxLoopsLimitHelper } from \"../MaxLoopsLimitHelper.sol\";\n\ncontract HarnessMaxLoopsLimitHelper is MaxLoopsLimitHelper {\n function setMaxLoopsLimit(uint256 limit) external {\n _setMaxLoopsLimit(limit);\n }\n\n function ensureMaxLoops(uint256 limit) external view {\n _ensureMaxLoops(limit);\n }\n}\n" + }, + "contracts/test/lib/ApproveOrRevertHarness.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ApproveOrRevert } from \"../../lib/ApproveOrRevert.sol\";\n\ncontract ApproveOrRevertHarness {\n using ApproveOrRevert for IERC20Upgradeable;\n\n function approve(\n IERC20Upgradeable token,\n address spender,\n uint256 amount\n ) external {\n token.approveOrRevert(spender, amount);\n }\n}\n" + }, + "contracts/test/lib/TokenDebtTrackerHarness.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { TokenDebtTracker } from \"../../lib/TokenDebtTracker.sol\";\n\ncontract TokenDebtTrackerHarness is TokenDebtTracker {\n function initialize() external initializer {\n __TokenDebtTracker_init();\n }\n\n function addTokenDebt(\n IERC20Upgradeable token,\n address user,\n uint256 amount\n ) external {\n tokenDebt[token][user] += amount;\n totalTokenDebt[token] += amount;\n }\n\n function transferOutOrTrackDebt(\n IERC20Upgradeable token,\n address user,\n uint256 amount\n ) external {\n _transferOutOrTrackDebt(token, user, amount);\n }\n\n function transferOutOrTrackDebtSkippingBalanceCheck(\n IERC20Upgradeable token,\n address user,\n uint256 amount\n ) external {\n _transferOutOrTrackDebtSkippingBalanceCheck(token, user, amount);\n }\n}\n" + }, + "contracts/test/MockDeflationaryToken.sol": { + "content": "pragma solidity 0.8.13;\n\ncontract MockDeflatingToken {\n string public constant NAME = \"Deflating Test Token\";\n string public constant SYMBOL = \"DTT\";\n uint8 public constant DECIMALS = 18;\n uint256 public totalSupply;\n mapping(address => uint256) public balanceOf;\n mapping(address => mapping(address => uint256)) public allowance;\n\n bytes32 public DOMAIN_SEPARATOR;\n // keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n mapping(address => uint256) public nonces;\n\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n constructor(uint256 _totalSupply) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n DOMAIN_SEPARATOR = keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string NAME,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(NAME)),\n keccak256(bytes(\"1\")),\n chainId,\n address(this)\n )\n );\n _mint(msg.sender, _totalSupply);\n }\n\n function approve(address spender, uint256 value) external returns (bool) {\n _approve(msg.sender, spender, value);\n return true;\n }\n\n function transfer(address to, uint256 value) external returns (bool) {\n _transfer(msg.sender, to, value);\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 value\n ) external returns (bool) {\n if (allowance[from][msg.sender] != type(uint256).max) {\n allowance[from][msg.sender] = allowance[from][msg.sender] - value;\n }\n _transfer(from, to, value);\n return true;\n }\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n require(deadline >= block.timestamp, \"EXPIRED\");\n bytes32 digest = keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR,\n keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))\n )\n );\n address recoveredAddress = ecrecover(digest, v, r, s);\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNATURE\");\n _approve(owner, spender, value);\n }\n\n function _mint(address to, uint256 value) internal {\n totalSupply = totalSupply + value;\n balanceOf[to] = balanceOf[to] + value;\n emit Transfer(address(0), to, value);\n }\n\n function _burn(address from, uint256 value) internal {\n balanceOf[from] = balanceOf[from] - value;\n totalSupply = totalSupply - value;\n emit Transfer(from, address(0), value);\n }\n\n function _approve(\n address owner,\n address spender,\n uint256 value\n ) private {\n allowance[owner][spender] = value;\n emit Approval(owner, spender, value);\n }\n\n function _transfer(\n address from,\n address to,\n uint256 value\n ) private {\n uint256 burnAmount = value / 100;\n _burn(from, burnAmount);\n uint256 transferAmount = value - burnAmount;\n balanceOf[from] = balanceOf[from] - transferAmount;\n balanceOf[to] = balanceOf[to] + transferAmount;\n emit Transfer(from, to, transferAmount);\n }\n}\n" + }, + "contracts/test/Mocks/MockPriceOracle.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\nimport { BinanceOracle } from \"@venusprotocol/oracle/contracts/oracles/BinanceOracle.sol\";\nimport { ChainlinkOracle } from \"@venusprotocol/oracle/contracts/oracles/ChainlinkOracle.sol\";\n\nimport { VToken } from \"../../VToken.sol\";\n\ncontract MockPriceOracle is ResilientOracleInterface {\n mapping(address => uint256) public assetPrices;\n\n //set price in 6 decimal precision\n // solhint-disable-next-line no-empty-blocks\n constructor() {}\n\n function setPrice(address asset, uint256 price) external {\n assetPrices[asset] = price;\n }\n\n // solhint-disable-next-line no-empty-blocks\n function updatePrice(address vToken) external override {}\n\n // solhint-disable-next-line no-empty-blocks\n function updateAssetPrice(address asset) external override {}\n\n function getPrice(address asset) external view returns (uint256) {\n return assetPrices[asset];\n }\n\n //https://compound.finance/docs/prices\n function getUnderlyingPrice(address vToken) public view override returns (uint256) {\n return assetPrices[VToken(vToken).underlying()];\n }\n}\n" + }, + "contracts/test/Mocks/MockToken.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockToken is ERC20 {\n uint8 private immutable _decimals;\n\n constructor(\n string memory name_,\n string memory symbol_,\n uint8 decimals_\n ) ERC20(name_, symbol_) {\n _decimals = decimals_;\n }\n\n function faucet(uint256 amount) external {\n _mint(msg.sender, amount);\n }\n\n function decimals() public view virtual override returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/test/SafeMath.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol\n// Subject to the MIT license.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n uint256 c;\n unchecked {\n c = a + b;\n }\n require(c >= a, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction underflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot underflow.\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c;\n unchecked {\n c = a * b;\n }\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers.\n * Reverts with custom message on division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n}\n" + }, + "contracts/test/UpgradedVToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { ComptrollerInterface } from \"../ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\n/**\n * @title Venus's VToken Contract\n * @notice VTokens which wrap an EIP-20 underlying and are immutable\n * @author Venus\n */\ncontract UpgradedVToken is VToken {\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param riskManagement Addresses of risk fund contracts\n */\n\n /// @notice We added this new function to test contract upgrade\n function version() external pure returns (uint256) {\n return 2;\n }\n\n function initializeV2(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address payable admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) public reinitializer(2) {\n super._initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_,\n admin_,\n accessControlManager_,\n riskManagement,\n reserveFactorMantissa_\n );\n }\n\n function getTokenUnderlying() public view returns (address) {\n return underlying;\n }\n}\n" + }, + "contracts/test/VTokenHarness.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport { AccessControlManager } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol\";\n\nimport { VToken } from \"../VToken.sol\";\nimport { InterestRateModel } from \"../InterestRateModel.sol\";\n\ncontract VTokenHarness is VToken {\n uint256 public blockNumber;\n uint256 public harnessExchangeRate;\n bool public harnessExchangeRateStored;\n\n mapping(address => bool) public failTransferToAddresses;\n\n function harnessSetAccrualBlockNumber(uint256 accrualBlockNumber_) external {\n accrualBlockNumber = accrualBlockNumber_;\n }\n\n function harnessSetBlockNumber(uint256 newBlockNumber) external {\n blockNumber = newBlockNumber;\n }\n\n function harnessFastForward(uint256 blocks) external {\n blockNumber += blocks;\n }\n\n function harnessSetBalance(address account, uint256 amount) external {\n accountTokens[account] = amount;\n }\n\n function harnessSetTotalSupply(uint256 totalSupply_) external {\n totalSupply = totalSupply_;\n }\n\n function harnessSetTotalBorrows(uint256 totalBorrows_) external {\n totalBorrows = totalBorrows_;\n }\n\n function harnessSetTotalReserves(uint256 totalReserves_) external {\n totalReserves = totalReserves_;\n }\n\n function harnessExchangeRateDetails(\n uint256 totalSupply_,\n uint256 totalBorrows_,\n uint256 totalReserves_\n ) external {\n totalSupply = totalSupply_;\n totalBorrows = totalBorrows_;\n totalReserves = totalReserves_;\n }\n\n function harnessSetExchangeRate(uint256 exchangeRate) external {\n harnessExchangeRate = exchangeRate;\n harnessExchangeRateStored = true;\n }\n\n function harnessSetFailTransferToAddress(address to_, bool fail_) external {\n failTransferToAddresses[to_] = fail_;\n }\n\n function harnessMintFresh(address account, uint256 mintAmount) external {\n super._mintFresh(account, account, mintAmount);\n }\n\n function harnessRedeemFresh(\n address payable account,\n uint256 vTokenAmount,\n uint256 underlyingAmount\n ) external {\n super._redeemFresh(account, vTokenAmount, underlyingAmount);\n }\n\n function harnessSetAccountBorrows(\n address account,\n uint256 principal,\n uint256 interestIndex\n ) external {\n accountBorrows[account] = BorrowSnapshot({ principal: principal, interestIndex: interestIndex });\n }\n\n function harnessSetBorrowIndex(uint256 borrowIndex_) external {\n borrowIndex = borrowIndex_;\n }\n\n function harnessBorrowFresh(address payable account, uint256 borrowAmount) external {\n _borrowFresh(account, borrowAmount);\n }\n\n function harnessRepayBorrowFresh(\n address payer,\n address account,\n uint256 repayAmount\n ) external {\n _repayBorrowFresh(payer, account, repayAmount);\n }\n\n function harnessLiquidateBorrowFresh(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VToken vTokenCollateral,\n bool skipLiquidityCheck\n ) external {\n _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n function harnessReduceReservesFresh(uint256 amount) external {\n return _reduceReservesFresh(amount);\n }\n\n function harnessSetReserveFactorFresh(uint256 newReserveFactorMantissa) external {\n _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n function harnessSetInterestRateModelFresh(InterestRateModel newInterestRateModel) external {\n _setInterestRateModelFresh(newInterestRateModel);\n }\n\n function harnessAccountBorrows(address account) external view returns (uint256 principal, uint256 interestIndex) {\n BorrowSnapshot memory snapshot = accountBorrows[account];\n return (snapshot.principal, snapshot.interestIndex);\n }\n\n function getBorrowRateMaxMantissa() external pure returns (uint256) {\n return MAX_BORROW_RATE_MANTISSA;\n }\n\n function harnessSetInterestRateModel(address newInterestRateModelAddress) public {\n interestRateModel = InterestRateModel(newInterestRateModelAddress);\n }\n\n function harnessCallPreBorrowHook(uint256 amount) public {\n comptroller.preBorrowHook(address(this), msg.sender, amount);\n }\n\n function _doTransferOut(address to, uint256 amount) internal override {\n require(failTransferToAddresses[to] == false, \"HARNESS_TOKEN_TRANSFER_OUT_FAILED\");\n return super._doTransferOut(to, amount);\n }\n\n function _exchangeRateStored() internal view override returns (uint256) {\n if (harnessExchangeRateStored) {\n return harnessExchangeRate;\n }\n return super._exchangeRateStored();\n }\n\n function _getBlockNumber() internal view override returns (uint256) {\n return blockNumber;\n }\n}\n" + }, + "contracts/VToken.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { Ownable2StepUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\nimport { AccessControlledV8 } from \"@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol\";\n\nimport { VTokenInterface } from \"./VTokenInterfaces.sol\";\nimport { ComptrollerInterface, ComptrollerViewInterface } from \"./ComptrollerInterface.sol\";\nimport { TokenErrorReporter } from \"./ErrorReporter.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { ExponentialNoError } from \"./ExponentialNoError.sol\";\nimport { IProtocolShareReserve } from \"./RiskFund/IProtocolShareReserve.sol\";\nimport { ensureNonzeroAddress } from \"./lib/validators.sol\";\n\n/**\n * @title VToken\n * @author Venus\n * @notice Each asset that is supported by a pool is integrated through an instance of the `VToken` contract. As outlined in the protocol overview,\n * each isolated pool creates its own `vToken` corresponding to an asset. Within a given pool, each included `vToken` is referred to as a market of\n * the pool. The main actions a user regularly interacts with in a market are:\n\n- mint/redeem of vTokens;\n- transfer of vTokens;\n- borrow/repay a loan on an underlying asset;\n- liquidate a borrow or liquidate/heal an account.\n\n * A user supplies the underlying asset to a pool by minting `vTokens`, where the corresponding `vToken` amount is determined by the `exchangeRate`.\n * The `exchangeRate` will change over time, dependent on a number of factors, some of which accrue interest. Additionally, once users have minted\n * `vToken` in a pool, they can borrow any asset in the isolated pool by using their `vToken` as collateral. In order to borrow an asset or use a `vToken`\n * as collateral, the user must be entered into each corresponding market (else, the `vToken` will not be considered collateral for a borrow). Note that\n * a user may borrow up to a portion of their collateral determined by the market’s collateral factor. However, if their borrowed amount exceeds an amount\n * calculated using the market’s corresponding liquidation threshold, the borrow is eligible for liquidation. When a user repays a borrow, they must also\n * pay off interest accrued on the borrow.\n * \n * The Venus protocol includes unique mechanisms for healing an account and liquidating an account. These actions are performed in the `Comptroller`\n * and consider all borrows and collateral for which a given account is entered within a market. These functions may only be called on an account with a\n * total collateral amount that is no larger than a universal `minLiquidatableCollateral` value, which is used for all markets within a `Comptroller`.\n * Both functions settle all of an account’s borrows, but `healAccount()` may add `badDebt` to a vToken. For more detail, see the description of\n * `healAccount()` and `liquidateAccount()` in the `Comptroller` summary section below.\n */\ncontract VToken is\n Ownable2StepUpgradeable,\n AccessControlledV8,\n VTokenInterface,\n ExponentialNoError,\n TokenErrorReporter\n{\n using SafeERC20Upgradeable for IERC20Upgradeable;\n\n uint256 internal constant DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA = 5e16; // 5%\n\n /*** Reentrancy Guard ***/\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n */\n modifier nonReentrant() {\n require(_notEntered, \"re-entered\");\n _notEntered = false;\n _;\n _notEntered = true; // get a gas-refund post-Istanbul\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n // Note that the contract is upgradeable. Use initialize() or reinitializers\n // to set the state variables.\n _disableInitializers();\n }\n\n /**\n * @notice Construct a new money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param accessControlManager_ AccessControlManager contract address\n * @param riskManagement Addresses of risk & income related contracts\n * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n * @custom:error ZeroAddressNotAllowed is thrown when admin address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n */\n function initialize(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) external initializer {\n ensureNonzeroAddress(admin_);\n\n // Initialize the market\n _initialize(\n underlying_,\n comptroller_,\n interestRateModel_,\n initialExchangeRateMantissa_,\n name_,\n symbol_,\n decimals_,\n admin_,\n accessControlManager_,\n riskManagement,\n reserveFactorMantissa_\n );\n }\n\n /**\n * @notice Transfer `amount` tokens from `msg.sender` to `dst`\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return success True if the transfer succeeded, reverts otherwise\n * @custom:event Emits Transfer event on success\n * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n * @custom:access Not restricted\n */\n function transfer(address dst, uint256 amount) external override nonReentrant returns (bool) {\n _transferTokens(msg.sender, msg.sender, dst, amount);\n return true;\n }\n\n /**\n * @notice Transfer `amount` tokens from `src` to `dst`\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param amount The number of tokens to transfer\n * @return success True if the transfer succeeded, reverts otherwise\n * @custom:event Emits Transfer event on success\n * @custom:error TransferNotAllowed is thrown if trying to transfer to self\n * @custom:access Not restricted\n */\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external override nonReentrant returns (bool) {\n _transferTokens(msg.sender, src, dst, amount);\n return true;\n }\n\n /**\n * @notice Approve `spender` to transfer up to `amount` from `src`\n * @dev This will overwrite the approval amount for `spender`\n * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)\n * @param spender The address of the account which may transfer tokens\n * @param amount The number of tokens that are approved (uint256.max means infinite)\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function approve(address spender, uint256 amount) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n transferAllowances[src][spender] = amount;\n emit Approval(src, spender, amount);\n return true;\n }\n\n /**\n * @notice Increase approval for `spender`\n * @param spender The address of the account which may transfer tokens\n * @param addedValue The number of additional tokens spender can transfer\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function increaseAllowance(address spender, uint256 addedValue) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n uint256 newAllowance = transferAllowances[src][spender];\n newAllowance += addedValue;\n transferAllowances[src][spender] = newAllowance;\n\n emit Approval(src, spender, newAllowance);\n return true;\n }\n\n /**\n * @notice Decreases approval for `spender`\n * @param spender The address of the account which may transfer tokens\n * @param subtractedValue The number of tokens to remove from total approval\n * @return success Whether or not the approval succeeded\n * @custom:event Emits Approval event\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when spender address is zero\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) external override returns (bool) {\n ensureNonzeroAddress(spender);\n\n address src = msg.sender;\n uint256 currentAllowance = transferAllowances[src][spender];\n require(currentAllowance >= subtractedValue, \"decreased allowance below zero\");\n unchecked {\n currentAllowance -= subtractedValue;\n }\n\n transferAllowances[src][spender] = currentAllowance;\n\n emit Approval(src, spender, currentAllowance);\n return true;\n }\n\n /**\n * @notice Get the underlying balance of the `owner`\n * @dev This also accrues interest in a transaction\n * @param owner The address of the account to query\n * @return amount The amount of underlying owned by `owner`\n */\n function balanceOfUnderlying(address owner) external override returns (uint256) {\n Exp memory exchangeRate = Exp({ mantissa: exchangeRateCurrent() });\n return mul_ScalarTruncate(exchangeRate, accountTokens[owner]);\n }\n\n /**\n * @notice Returns the current total borrows plus accrued interest\n * @return totalBorrows The total borrows with interest\n */\n function totalBorrowsCurrent() external override nonReentrant returns (uint256) {\n accrueInterest();\n return totalBorrows;\n }\n\n /**\n * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex\n * @param account The address whose balance should be calculated after updating borrowIndex\n * @return borrowBalance The calculated balance\n */\n function borrowBalanceCurrent(address account) external override nonReentrant returns (uint256) {\n accrueInterest();\n return _borrowBalanceStored(account);\n }\n\n /**\n * @notice Sender supplies assets into the market and receives vTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param mintAmount The amount of the underlying asset to supply\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function mint(uint256 mintAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n _mintFresh(msg.sender, msg.sender, mintAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender calls on-behalf of minter. minter supplies assets into the market and receives vTokens in exchange\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param minter User whom the supply will be attributed to\n * @param mintAmount The amount of the underlying asset to supply\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Mint and Transfer events; may emit AccrueInterest\n * @custom:access Not restricted\n * @custom:error ZeroAddressNotAllowed is thrown when minter address is zero\n */\n function mintBehalf(address minter, uint256 mintAmount) external override nonReentrant returns (uint256) {\n ensureNonzeroAddress(minter);\n\n accrueInterest();\n // _mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to\n _mintFresh(msg.sender, minter, mintAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender redeems vTokens in exchange for the underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemTokens The number of vTokens to redeem into underlying\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Redeem and Transfer events; may emit AccrueInterest\n * @custom:error RedeemTransferOutNotPossible is thrown when the protocol has insufficient cash\n * @custom:access Not restricted\n */\n function redeem(uint256 redeemTokens) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _redeemFresh emits redeem-specific logs on errors, so we don't need to\n _redeemFresh(msg.sender, redeemTokens, 0);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender redeems vTokens in exchange for a specified amount of underlying asset\n * @dev Accrues interest whether or not the operation succeeds, unless reverted\n * @param redeemAmount The amount of underlying to receive from redeeming vTokens\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n */\n function redeemUnderlying(uint256 redeemAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _redeemFresh emits redeem-specific logs on errors, so we don't need to\n _redeemFresh(msg.sender, 0, redeemAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender borrows assets from the protocol to their own address\n * @param borrowAmount The amount of the underlying asset to borrow\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits Borrow event; may emit AccrueInterest\n * @custom:error BorrowCashNotAvailable is thrown when the protocol has insufficient cash\n * @custom:access Not restricted\n */\n function borrow(uint256 borrowAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // borrowFresh emits borrow-specific logs on errors, so we don't need to\n _borrowFresh(msg.sender, borrowAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender repays their own borrow\n * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function repayBorrow(uint256 repayAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n _repayBorrowFresh(msg.sender, msg.sender, repayAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice Sender repays a borrow belonging to borrower\n * @param borrower the account with the debt being payed off\n * @param repayAmount The amount to repay, or type(uint256).max for the full outstanding amount\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits RepayBorrow event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external override nonReentrant returns (uint256) {\n accrueInterest();\n // _repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to\n _repayBorrowFresh(msg.sender, borrower, repayAmount);\n return NO_ERROR;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param borrower The borrower of this vToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n * @custom:access Not restricted\n */\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral\n ) external override returns (uint256) {\n _liquidateBorrow(msg.sender, borrower, repayAmount, vTokenCollateral, false);\n return NO_ERROR;\n }\n\n /**\n * @notice sets protocol share accumulated from liquidations\n * @dev must be equal or less than liquidation incentive - 1\n * @param newProtocolSeizeShareMantissa_ new protocol share mantissa\n * @custom:event Emits NewProtocolSeizeShare event on success\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:error ProtocolSeizeShareTooBig is thrown when the new seize share is too high\n * @custom:access Controlled by AccessControlManager\n */\n function setProtocolSeizeShare(uint256 newProtocolSeizeShareMantissa_) external {\n _checkAccessAllowed(\"setProtocolSeizeShare(uint256)\");\n uint256 liquidationIncentive = ComptrollerViewInterface(address(comptroller)).liquidationIncentiveMantissa();\n if (newProtocolSeizeShareMantissa_ + MANTISSA_ONE > liquidationIncentive) {\n revert ProtocolSeizeShareTooBig();\n }\n\n uint256 oldProtocolSeizeShareMantissa = protocolSeizeShareMantissa;\n protocolSeizeShareMantissa = newProtocolSeizeShareMantissa_;\n emit NewProtocolSeizeShare(oldProtocolSeizeShareMantissa, newProtocolSeizeShareMantissa_);\n }\n\n /**\n * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh\n * @dev Admin function to accrue interest and set a new reserve factor\n * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n * @custom:event Emits NewReserveFactor event; may emit AccrueInterest\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:error SetReserveFactorBoundsCheck is thrown when the new reserve factor is too high\n * @custom:access Controlled by AccessControlManager\n */\n function setReserveFactor(uint256 newReserveFactorMantissa) external override nonReentrant {\n _checkAccessAllowed(\"setReserveFactor(uint256)\");\n\n accrueInterest();\n _setReserveFactorFresh(newReserveFactorMantissa);\n }\n\n /**\n * @notice Accrues interest and reduces reserves by transferring to the protocol reserve contract\n * @param reduceAmount Amount of reduction to reserves\n * @custom:event Emits ReservesReduced event; may emit AccrueInterest\n * @custom:error ReduceReservesCashNotAvailable is thrown when the vToken does not have sufficient cash\n * @custom:error ReduceReservesCashValidation is thrown when trying to withdraw more cash than the reserves have\n * @custom:access Not restricted\n */\n function reduceReserves(uint256 reduceAmount) external override nonReentrant {\n accrueInterest();\n _reduceReservesFresh(reduceAmount);\n }\n\n /**\n * @notice The sender adds to reserves.\n * @param addAmount The amount of underlying token to add as reserves\n * @custom:event Emits ReservesAdded event; may emit AccrueInterest\n * @custom:access Not restricted\n */\n function addReserves(uint256 addAmount) external override nonReentrant {\n accrueInterest();\n _addReservesFresh(addAmount);\n }\n\n /**\n * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh\n * @dev Admin function to accrue interest and update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n * @custom:event Emits NewMarketInterestRateModel event; may emit AccrueInterest\n * @custom:error Unauthorized error is thrown when the call is not authorized by AccessControlManager\n * @custom:access Controlled by AccessControlManager\n */\n function setInterestRateModel(InterestRateModel newInterestRateModel) external override {\n _checkAccessAllowed(\"setInterestRateModel(address)\");\n\n accrueInterest();\n _setInterestRateModelFresh(newInterestRateModel);\n }\n\n /**\n * @notice Repays a certain amount of debt, treats the rest of the borrow as bad debt, essentially\n * \"forgiving\" the borrower. Healing is a situation that should rarely happen. However, some pools\n * may list risky assets or be configured improperly – we want to still handle such cases gracefully.\n * We assume that Comptroller does the seizing, so this function is only available to Comptroller.\n * @dev This function does not call any Comptroller hooks (like \"healAllowed\"), because we assume\n * the Comptroller does all the necessary checks before calling this function.\n * @param payer account who repays the debt\n * @param borrower account to heal\n * @param repayAmount amount to repay\n * @custom:event Emits RepayBorrow, BadDebtIncreased events; may emit AccrueInterest\n * @custom:error HealBorrowUnauthorized is thrown when the request does not come from Comptroller\n * @custom:access Only Comptroller\n */\n function healBorrow(\n address payer,\n address borrower,\n uint256 repayAmount\n ) external override nonReentrant {\n if (repayAmount != 0) {\n comptroller.preRepayHook(address(this), borrower);\n }\n\n if (msg.sender != address(comptroller)) {\n revert HealBorrowUnauthorized();\n }\n\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n uint256 totalBorrowsNew = totalBorrows;\n\n uint256 actualRepayAmount;\n if (repayAmount != 0) {\n // _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n // We violate checks-effects-interactions here to account for tokens that take transfer fees\n actualRepayAmount = _doTransferIn(payer, repayAmount);\n totalBorrowsNew = totalBorrowsNew - actualRepayAmount;\n emit RepayBorrow(\n payer,\n borrower,\n actualRepayAmount,\n accountBorrowsPrev - actualRepayAmount,\n totalBorrowsNew\n );\n }\n\n // The transaction will fail if trying to repay too much\n uint256 badDebtDelta = accountBorrowsPrev - actualRepayAmount;\n if (badDebtDelta != 0) {\n uint256 badDebtOld = badDebt;\n uint256 badDebtNew = badDebtOld + badDebtDelta;\n totalBorrowsNew = totalBorrowsNew - badDebtDelta;\n badDebt = badDebtNew;\n\n // We treat healing as \"repayment\", where vToken is the payer\n emit RepayBorrow(address(this), borrower, badDebtDelta, 0, totalBorrowsNew);\n emit BadDebtIncreased(borrower, badDebtDelta, badDebtOld, badDebtNew);\n }\n\n accountBorrows[borrower].principal = 0;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n emit HealBorrow(payer, borrower, repayAmount);\n }\n\n /**\n * @notice The extended version of liquidations, callable only by Comptroller. May skip\n * the close factor check. The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n * @custom:event Emits LiquidateBorrow event; may emit AccrueInterest\n * @custom:error ForceLiquidateBorrowUnauthorized is thrown when the request does not come from Comptroller\n * @custom:error LiquidateAccrueCollateralInterestFailed is thrown when it is not possible to accrue interest on the collateral vToken\n * @custom:error LiquidateCollateralFreshnessCheck is thrown when interest has not been accrued on the collateral vToken\n * @custom:error LiquidateLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:error LiquidateCloseAmountIsZero is thrown when repayment amount is zero\n * @custom:error LiquidateCloseAmountIsUintMax is thrown when repayment amount is UINT_MAX\n * @custom:access Only Comptroller\n */\n function forceLiquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) external override {\n if (msg.sender != address(comptroller)) {\n revert ForceLiquidateBorrowUnauthorized();\n }\n _liquidateBorrow(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Will fail unless called by another vToken during the process of liquidation.\n * It's absolutely critical to use msg.sender as the borrowed vToken and not a parameter.\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of vTokens to seize\n * @custom:event Emits Transfer, ReservesAdded events\n * @custom:error LiquidateSeizeLiquidatorIsBorrower is thrown when trying to liquidate self\n * @custom:access Not restricted\n */\n function seize(\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external override nonReentrant {\n _seize(msg.sender, liquidator, borrower, seizeTokens);\n }\n\n /**\n * @notice Updates bad debt\n * @dev Called only when bad debt is recovered from auction\n * @param recoveredAmount_ The amount of bad debt recovered\n * @custom:event Emits BadDebtRecovered event\n * @custom:access Only Shortfall contract\n */\n function badDebtRecovered(uint256 recoveredAmount_) external {\n require(msg.sender == shortfall, \"only shortfall contract can update bad debt\");\n require(recoveredAmount_ <= badDebt, \"more than bad debt recovered from auction\");\n\n uint256 badDebtOld = badDebt;\n uint256 badDebtNew = badDebtOld - recoveredAmount_;\n badDebt = badDebtNew;\n\n emit BadDebtRecovered(badDebtOld, badDebtNew);\n }\n\n /**\n * @notice Sets protocol share reserve contract address\n * @param protocolShareReserve_ The address of the protocol share reserve contract\n * @custom:error ZeroAddressNotAllowed is thrown when protocol share reserve address is zero\n * @custom:access Only Governance\n */\n function setProtocolShareReserve(address payable protocolShareReserve_) external onlyOwner {\n _setProtocolShareReserve(protocolShareReserve_);\n }\n\n /**\n * @notice Sets shortfall contract address\n * @param shortfall_ The address of the shortfall contract\n * @custom:error ZeroAddressNotAllowed is thrown when shortfall contract address is zero\n * @custom:access Only Governance\n */\n function setShortfallContract(address shortfall_) external onlyOwner {\n _setShortfallContract(shortfall_);\n }\n\n /**\n * @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)\n * @param token The address of the ERC-20 token to sweep\n * @custom:access Only Governance\n */\n function sweepToken(IERC20Upgradeable token) external override {\n require(msg.sender == owner(), \"VToken::sweepToken: only admin can sweep tokens\");\n require(address(token) != underlying, \"VToken::sweepToken: can not sweep underlying token\");\n uint256 balance = token.balanceOf(address(this));\n token.safeTransfer(owner(), balance);\n\n emit SweepToken(address(token));\n }\n\n /**\n * @notice Get the current allowance from `owner` for `spender`\n * @param owner The address of the account which owns the tokens to be spent\n * @param spender The address of the account which may transfer tokens\n * @return amount The number of tokens allowed to be spent (type(uint256).max means infinite)\n */\n function allowance(address owner, address spender) external view override returns (uint256) {\n return transferAllowances[owner][spender];\n }\n\n /**\n * @notice Get the token balance of the `owner`\n * @param owner The address of the account to query\n * @return amount The number of tokens owned by `owner`\n */\n function balanceOf(address owner) external view override returns (uint256) {\n return accountTokens[owner];\n }\n\n /**\n * @notice Get a snapshot of the account's balances, and the cached exchange rate\n * @dev This is used by comptroller to more efficiently perform liquidity checks.\n * @param account Address of the account to snapshot\n * @return error Always NO_ERROR for compatibility with Venus core tooling\n * @return vTokenBalance User's balance of vTokens\n * @return borrowBalance Amount owed in terms of underlying\n * @return exchangeRate Stored exchange rate\n */\n function getAccountSnapshot(address account)\n external\n view\n override\n returns (\n uint256 error,\n uint256 vTokenBalance,\n uint256 borrowBalance,\n uint256 exchangeRate\n )\n {\n return (NO_ERROR, accountTokens[account], _borrowBalanceStored(account), _exchangeRateStored());\n }\n\n /**\n * @notice Get cash balance of this vToken in the underlying asset\n * @return cash The quantity of underlying asset owned by this contract\n */\n function getCash() external view override returns (uint256) {\n return _getCashPrior();\n }\n\n /**\n * @notice Returns the current per-block borrow interest rate for this vToken\n * @return rate The borrow interest rate per block, scaled by 1e18\n */\n function borrowRatePerBlock() external view override returns (uint256) {\n return interestRateModel.getBorrowRate(_getCashPrior(), totalBorrows, totalReserves, badDebt);\n }\n\n /**\n * @notice Returns the current per-block supply interest rate for this v\n * @return rate The supply interest rate per block, scaled by 1e18\n */\n function supplyRatePerBlock() external view override returns (uint256) {\n return\n interestRateModel.getSupplyRate(\n _getCashPrior(),\n totalBorrows,\n totalReserves,\n reserveFactorMantissa,\n badDebt\n );\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return borrowBalance The calculated balance\n */\n function borrowBalanceStored(address account) external view override returns (uint256) {\n return _borrowBalanceStored(account);\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the VToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function exchangeRateStored() external view override returns (uint256) {\n return _exchangeRateStored();\n }\n\n /**\n * @notice Accrue interest then return the up-to-date exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function exchangeRateCurrent() public override nonReentrant returns (uint256) {\n accrueInterest();\n return _exchangeRateStored();\n }\n\n /**\n * @notice Applies accrued interest to total borrows and reserves\n * @dev This calculates interest accrued from the last checkpointed block\n * up to the current block and writes new checkpoint to storage.\n * @return Always NO_ERROR\n * @custom:event Emits AccrueInterest event on success\n * @custom:access Not restricted\n */\n function accrueInterest() public virtual override returns (uint256) {\n /* Remember the initial block number */\n uint256 currentBlockNumber = _getBlockNumber();\n uint256 accrualBlockNumberPrior = accrualBlockNumber;\n\n /* Short-circuit accumulating 0 interest */\n if (accrualBlockNumberPrior == currentBlockNumber) {\n return NO_ERROR;\n }\n\n /* Read the previous values out of storage */\n uint256 cashPrior = _getCashPrior();\n uint256 borrowsPrior = totalBorrows;\n uint256 reservesPrior = totalReserves;\n uint256 borrowIndexPrior = borrowIndex;\n\n /* Calculate the current borrow interest rate */\n uint256 borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior, badDebt);\n require(borrowRateMantissa <= MAX_BORROW_RATE_MANTISSA, \"borrow rate is absurdly high\");\n\n /* Calculate the number of blocks elapsed since the last accrual */\n uint256 blockDelta = currentBlockNumber - accrualBlockNumberPrior;\n\n /*\n * Calculate the interest accumulated into borrows and reserves and the new index:\n * simpleInterestFactor = borrowRate * blockDelta\n * interestAccumulated = simpleInterestFactor * totalBorrows\n * totalBorrowsNew = interestAccumulated + totalBorrows\n * totalReservesNew = interestAccumulated * reserveFactor + totalReserves\n * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex\n */\n\n Exp memory simpleInterestFactor = mul_(Exp({ mantissa: borrowRateMantissa }), blockDelta);\n uint256 interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior);\n uint256 totalBorrowsNew = interestAccumulated + borrowsPrior;\n uint256 totalReservesNew = mul_ScalarTruncateAddUInt(\n Exp({ mantissa: reserveFactorMantissa }),\n interestAccumulated,\n reservesPrior\n );\n uint256 borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the previously calculated values into storage */\n accrualBlockNumber = currentBlockNumber;\n borrowIndex = borrowIndexNew;\n totalBorrows = totalBorrowsNew;\n totalReserves = totalReservesNew;\n\n /* We emit an AccrueInterest event */\n emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);\n\n return NO_ERROR;\n }\n\n /**\n * @notice User supplies assets into the market and receives vTokens in exchange\n * @dev Assumes interest has already been accrued up to the current block\n * @param payer The address of the account which is sending the assets for supply\n * @param minter The address of the account which is supplying the assets\n * @param mintAmount The amount of the underlying asset to supply\n */\n function _mintFresh(\n address payer,\n address minter,\n uint256 mintAmount\n ) internal {\n /* Fail if mint not allowed */\n comptroller.preMintHook(address(this), minter, mintAmount);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert MintFreshnessCheck();\n }\n\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call `_doTransferIn` for the minter and the mintAmount.\n * `_doTransferIn` reverts if anything goes wrong, since we can't be sure if\n * side-effects occurred. The function returns the amount actually transferred,\n * in case of a fee. On success, the vToken holds an additional `actualMintAmount`\n * of cash.\n */\n uint256 actualMintAmount = _doTransferIn(payer, mintAmount);\n\n /*\n * We get the current exchange rate and calculate the number of vTokens to be minted:\n * mintTokens = actualMintAmount / exchangeRate\n */\n\n uint256 mintTokens = div_(actualMintAmount, exchangeRate);\n\n /*\n * We calculate the new total supply of vTokens and minter token balance, checking for overflow:\n * totalSupplyNew = totalSupply + mintTokens\n * accountTokensNew = accountTokens[minter] + mintTokens\n * And write them into storage\n */\n totalSupply = totalSupply + mintTokens;\n uint256 balanceAfter = accountTokens[minter] + mintTokens;\n accountTokens[minter] = balanceAfter;\n\n /* We emit a Mint event, and a Transfer event */\n emit Mint(minter, actualMintAmount, mintTokens, balanceAfter);\n emit Transfer(address(0), minter, mintTokens);\n }\n\n /**\n * @notice User redeems vTokens in exchange for the underlying asset\n * @dev Assumes interest has already been accrued up to the current block\n * @param redeemer The address of the account which is redeeming the tokens\n * @param redeemTokensIn The number of vTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n * @param redeemAmountIn The number of underlying tokens to receive from redeeming vTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)\n */\n function _redeemFresh(\n address redeemer,\n uint256 redeemTokensIn,\n uint256 redeemAmountIn\n ) internal {\n require(redeemTokensIn == 0 || redeemAmountIn == 0, \"one of redeemTokensIn or redeemAmountIn must be zero\");\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert RedeemFreshnessCheck();\n }\n\n /* exchangeRate = invoke Exchange Rate Stored() */\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n\n uint256 redeemTokens;\n uint256 redeemAmount;\n\n /* If redeemTokensIn > 0: */\n if (redeemTokensIn > 0) {\n /*\n * We calculate the exchange rate and the amount of underlying to be redeemed:\n * redeemTokens = redeemTokensIn\n */\n redeemTokens = redeemTokensIn;\n } else {\n /*\n * We get the current exchange rate and calculate the amount to be redeemed:\n * redeemTokens = redeemAmountIn / exchangeRate\n */\n redeemTokens = div_(redeemAmountIn, exchangeRate);\n\n uint256 _redeemAmount = mul_(redeemTokens, exchangeRate);\n if (_redeemAmount != 0 && _redeemAmount != redeemAmountIn) redeemTokens++; // round up\n }\n\n // redeemAmount = exchangeRate * redeemTokens\n redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokens);\n\n // Revert if amount is zero\n if (redeemAmount == 0) {\n revert(\"redeemAmount is zero\");\n }\n\n /* Fail if redeem not allowed */\n comptroller.preRedeemHook(address(this), redeemer, redeemTokens);\n\n /* Fail gracefully if protocol has insufficient cash */\n if (_getCashPrior() - totalReserves < redeemAmount) {\n revert RedeemTransferOutNotPossible();\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We write the previously calculated values into storage.\n * Note: Avoid token reentrancy attacks by writing reduced supply before external transfer.\n */\n totalSupply = totalSupply - redeemTokens;\n uint256 balanceAfter = accountTokens[redeemer] - redeemTokens;\n accountTokens[redeemer] = balanceAfter;\n\n /*\n * We invoke _doTransferOut for the redeemer and the redeemAmount.\n * On success, the vToken has redeemAmount less of cash.\n * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n _doTransferOut(redeemer, redeemAmount);\n\n /* We emit a Transfer event, and a Redeem event */\n emit Transfer(redeemer, address(this), redeemTokens);\n emit Redeem(redeemer, redeemAmount, redeemTokens, balanceAfter);\n }\n\n /**\n * @notice Users borrow assets from the protocol to their own address\n * @param borrower User who borrows the assets\n * @param borrowAmount The amount of the underlying asset to borrow\n */\n function _borrowFresh(address borrower, uint256 borrowAmount) internal {\n /* Fail if borrow not allowed */\n comptroller.preBorrowHook(address(this), borrower, borrowAmount);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert BorrowFreshnessCheck();\n }\n\n /* Fail gracefully if protocol has insufficient underlying cash */\n if (_getCashPrior() - totalReserves < borrowAmount) {\n revert BorrowCashNotAvailable();\n }\n\n /*\n * We calculate the new borrower and total borrow balances, failing on overflow:\n * accountBorrowNew = accountBorrow + borrowAmount\n * totalBorrowsNew = totalBorrows + borrowAmount\n */\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n uint256 accountBorrowsNew = accountBorrowsPrev + borrowAmount;\n uint256 totalBorrowsNew = totalBorrows + borrowAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We write the previously calculated values into storage.\n * Note: Avoid token reentrancy attacks by writing increased borrow before external transfer.\n `*/\n accountBorrows[borrower].principal = accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n /*\n * We invoke _doTransferOut for the borrower and the borrowAmount.\n * On success, the vToken borrowAmount less of cash.\n * _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n */\n _doTransferOut(borrower, borrowAmount);\n\n /* We emit a Borrow event */\n emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);\n }\n\n /**\n * @notice Borrows are repaid by another user (possibly the borrower).\n * @param payer the account paying off the borrow\n * @param borrower the account with the debt being payed off\n * @param repayAmount the amount of underlying tokens being returned, or type(uint256).max for the full outstanding amount\n * @return (uint) the actual repayment amount.\n */\n function _repayBorrowFresh(\n address payer,\n address borrower,\n uint256 repayAmount\n ) internal returns (uint256) {\n /* Fail if repayBorrow not allowed */\n comptroller.preRepayHook(address(this), borrower);\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert RepayBorrowFreshnessCheck();\n }\n\n /* We fetch the amount the borrower owes, with accumulated interest */\n uint256 accountBorrowsPrev = _borrowBalanceStored(borrower);\n\n uint256 repayAmountFinal = repayAmount >= accountBorrowsPrev ? accountBorrowsPrev : repayAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /*\n * We call _doTransferIn for the payer and the repayAmount\n * On success, the vToken holds an additional repayAmount of cash.\n * _doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.\n * it returns the amount actually transferred, in case of a fee.\n */\n uint256 actualRepayAmount = _doTransferIn(payer, repayAmountFinal);\n\n /*\n * We calculate the new borrower and total borrow balances, failing on underflow:\n * accountBorrowsNew = accountBorrows - actualRepayAmount\n * totalBorrowsNew = totalBorrows - actualRepayAmount\n */\n uint256 accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;\n uint256 totalBorrowsNew = totalBorrows - actualRepayAmount;\n\n /* We write the previously calculated values into storage */\n accountBorrows[borrower].principal = accountBorrowsNew;\n accountBorrows[borrower].interestIndex = borrowIndex;\n totalBorrows = totalBorrowsNew;\n\n /* We emit a RepayBorrow event */\n emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew);\n\n return actualRepayAmount;\n }\n\n /**\n * @notice The sender liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n */\n function _liquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) internal nonReentrant {\n accrueInterest();\n\n uint256 error = vTokenCollateral.accrueInterest();\n if (error != NO_ERROR) {\n // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed\n revert LiquidateAccrueCollateralInterestFailed(error);\n }\n\n // _liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to\n _liquidateBorrowFresh(liquidator, borrower, repayAmount, vTokenCollateral, skipLiquidityCheck);\n }\n\n /**\n * @notice The liquidator liquidates the borrowers collateral.\n * The collateral seized is transferred to the liquidator.\n * @param liquidator The address repaying the borrow and seizing collateral\n * @param borrower The borrower of this vToken to be liquidated\n * @param vTokenCollateral The market in which to seize collateral from the borrower\n * @param repayAmount The amount of the underlying borrowed asset to repay\n * @param skipLiquidityCheck If set to true, allows to liquidate up to 100% of the borrow\n * regardless of the account liquidity\n */\n function _liquidateBorrowFresh(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipLiquidityCheck\n ) internal {\n /* Fail if liquidate not allowed */\n comptroller.preLiquidateHook(\n address(this),\n address(vTokenCollateral),\n borrower,\n repayAmount,\n skipLiquidityCheck\n );\n\n /* Verify market's block number equals current block number */\n if (accrualBlockNumber != _getBlockNumber()) {\n revert LiquidateFreshnessCheck();\n }\n\n /* Verify vTokenCollateral market's block number equals current block number */\n if (vTokenCollateral.accrualBlockNumber() != _getBlockNumber()) {\n revert LiquidateCollateralFreshnessCheck();\n }\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n revert LiquidateLiquidatorIsBorrower();\n }\n\n /* Fail if repayAmount = 0 */\n if (repayAmount == 0) {\n revert LiquidateCloseAmountIsZero();\n }\n\n /* Fail if repayAmount = type(uint256).max */\n if (repayAmount == type(uint256).max) {\n revert LiquidateCloseAmountIsUintMax();\n }\n\n /* Fail if repayBorrow fails */\n uint256 actualRepayAmount = _repayBorrowFresh(liquidator, borrower, repayAmount);\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We calculate the number of collateral tokens that will be seized */\n (uint256 amountSeizeError, uint256 seizeTokens) = comptroller.liquidateCalculateSeizeTokens(\n address(this),\n address(vTokenCollateral),\n actualRepayAmount\n );\n require(amountSeizeError == NO_ERROR, \"LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED\");\n\n /* Revert if borrower collateral token balance < seizeTokens */\n require(vTokenCollateral.balanceOf(borrower) >= seizeTokens, \"LIQUIDATE_SEIZE_TOO_MUCH\");\n\n // If this is also the collateral, call _seize internally to avoid re-entrancy, otherwise make an external call\n if (address(vTokenCollateral) == address(this)) {\n _seize(address(this), liquidator, borrower, seizeTokens);\n } else {\n vTokenCollateral.seize(liquidator, borrower, seizeTokens);\n }\n\n /* We emit a LiquidateBorrow event */\n emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(vTokenCollateral), seizeTokens);\n }\n\n /**\n * @notice Transfers collateral tokens (this market) to the liquidator.\n * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another VToken.\n * It's absolutely critical to use msg.sender as the seizer vToken and not a parameter.\n * @param seizerContract The contract seizing the collateral (either borrowed vToken or Comptroller)\n * @param liquidator The account receiving seized collateral\n * @param borrower The account having collateral seized\n * @param seizeTokens The number of vTokens to seize\n */\n function _seize(\n address seizerContract,\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) internal {\n /* Fail if seize not allowed */\n comptroller.preSeizeHook(address(this), seizerContract, liquidator, borrower);\n\n /* Fail if borrower = liquidator */\n if (borrower == liquidator) {\n revert LiquidateSeizeLiquidatorIsBorrower();\n }\n\n /*\n * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:\n * borrowerTokensNew = accountTokens[borrower] - seizeTokens\n * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens\n */\n uint256 liquidationIncentiveMantissa = ComptrollerViewInterface(address(comptroller))\n .liquidationIncentiveMantissa();\n uint256 numerator = mul_(seizeTokens, Exp({ mantissa: protocolSeizeShareMantissa }));\n uint256 protocolSeizeTokens = div_(numerator, Exp({ mantissa: liquidationIncentiveMantissa }));\n uint256 liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;\n Exp memory exchangeRate = Exp({ mantissa: _exchangeRateStored() });\n uint256 protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens);\n uint256 totalReservesNew = totalReserves + protocolSeizeAmount;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n /* We write the calculated values into storage */\n totalReserves = totalReservesNew;\n totalSupply = totalSupply - protocolSeizeTokens;\n accountTokens[borrower] = accountTokens[borrower] - seizeTokens;\n accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens;\n\n /* Emit a Transfer event */\n emit Transfer(borrower, liquidator, liquidatorSeizeTokens);\n emit Transfer(borrower, address(this), protocolSeizeTokens);\n emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew);\n }\n\n function _setComptroller(ComptrollerInterface newComptroller) internal {\n ComptrollerInterface oldComptroller = comptroller;\n // Ensure invoke comptroller.isComptroller() returns true\n require(newComptroller.isComptroller(), \"marker method returned false\");\n\n // Set market's comptroller to newComptroller\n comptroller = newComptroller;\n\n // Emit NewComptroller(oldComptroller, newComptroller)\n emit NewComptroller(oldComptroller, newComptroller);\n }\n\n /**\n * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)\n * @dev Admin function to set a new reserve factor\n * @param newReserveFactorMantissa New reserve factor (from 0 to 1e18)\n */\n function _setReserveFactorFresh(uint256 newReserveFactorMantissa) internal {\n // Verify market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert SetReserveFactorFreshCheck();\n }\n\n // Check newReserveFactor ≤ maxReserveFactor\n if (newReserveFactorMantissa > MAX_RESERVE_FACTOR_MANTISSA) {\n revert SetReserveFactorBoundsCheck();\n }\n\n uint256 oldReserveFactorMantissa = reserveFactorMantissa;\n reserveFactorMantissa = newReserveFactorMantissa;\n\n emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);\n }\n\n /**\n * @notice Add reserves by transferring from caller\n * @dev Requires fresh interest accrual\n * @param addAmount Amount of addition to reserves\n * @return actualAddAmount The actual amount added, excluding the potential token fees\n */\n function _addReservesFresh(uint256 addAmount) internal returns (uint256) {\n // totalReserves + actualAddAmount\n uint256 totalReservesNew;\n uint256 actualAddAmount;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert AddReservesFactorFreshCheck(actualAddAmount);\n }\n\n actualAddAmount = _doTransferIn(msg.sender, addAmount);\n totalReservesNew = totalReserves + actualAddAmount;\n totalReserves = totalReservesNew;\n emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);\n\n return actualAddAmount;\n }\n\n /**\n * @notice Reduces reserves by transferring to the protocol reserve contract\n * @dev Requires fresh interest accrual\n * @param reduceAmount Amount of reduction to reserves\n */\n function _reduceReservesFresh(uint256 reduceAmount) internal {\n // totalReserves - reduceAmount\n uint256 totalReservesNew;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert ReduceReservesFreshCheck();\n }\n\n // Fail gracefully if protocol has insufficient underlying cash\n if (_getCashPrior() < reduceAmount) {\n revert ReduceReservesCashNotAvailable();\n }\n\n // Check reduceAmount ≤ reserves[n] (totalReserves)\n if (reduceAmount > totalReserves) {\n revert ReduceReservesCashValidation();\n }\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n // (No safe failures beyond this point)\n\n totalReservesNew = totalReserves - reduceAmount;\n\n // Store reserves[n+1] = reserves[n] - reduceAmount\n totalReserves = totalReservesNew;\n\n // _doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.\n // Transferring an underlying asset to the protocolShareReserve contract to channel the funds for different use.\n _doTransferOut(protocolShareReserve, reduceAmount);\n\n // Update the pool asset's state in the protocol share reserve for the above transfer.\n IProtocolShareReserve(protocolShareReserve).updateAssetsState(address(comptroller), underlying);\n\n emit ReservesReduced(protocolShareReserve, reduceAmount, totalReservesNew);\n }\n\n /**\n * @notice updates the interest rate model (*requires fresh interest accrual)\n * @dev Admin function to update the interest rate model\n * @param newInterestRateModel the new interest rate model to use\n */\n function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal {\n // Used to store old model for use in the event that is emitted on success\n InterestRateModel oldInterestRateModel;\n\n // We fail gracefully unless market's block number equals current block number\n if (accrualBlockNumber != _getBlockNumber()) {\n revert SetInterestRateModelFreshCheck();\n }\n\n // Track the market's current interest rate model\n oldInterestRateModel = interestRateModel;\n\n // Ensure invoke newInterestRateModel.isInterestRateModel() returns true\n require(newInterestRateModel.isInterestRateModel(), \"marker method returned false\");\n\n // Set the interest rate model to newInterestRateModel\n interestRateModel = newInterestRateModel;\n\n // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)\n emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);\n }\n\n /*** Safe Token ***/\n\n /**\n * @dev Similar to ERC-20 transfer, but handles tokens that have transfer fees.\n * This function returns the actual amount received,\n * which may be less than `amount` if there is a fee attached to the transfer.\n * @param from Sender of the underlying tokens\n * @param amount Amount of underlying to transfer\n * @return Actual amount received\n */\n function _doTransferIn(address from, uint256 amount) internal virtual returns (uint256) {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n uint256 balanceBefore = token.balanceOf(address(this));\n token.safeTransferFrom(from, address(this), amount);\n uint256 balanceAfter = token.balanceOf(address(this));\n // Return the amount that was *actually* transferred\n return balanceAfter - balanceBefore;\n }\n\n /**\n * @dev Just a regular ERC-20 transfer, reverts on failure\n * @param to Receiver of the underlying tokens\n * @param amount Amount of underlying to transfer\n */\n function _doTransferOut(address to, uint256 amount) internal virtual {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n token.safeTransfer(to, amount);\n }\n\n /**\n * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`\n * @dev Called by both `transfer` and `transferFrom` internally\n * @param spender The address of the account performing the transfer\n * @param src The address of the source account\n * @param dst The address of the destination account\n * @param tokens The number of tokens to transfer\n */\n function _transferTokens(\n address spender,\n address src,\n address dst,\n uint256 tokens\n ) internal {\n /* Fail if transfer not allowed */\n comptroller.preTransferHook(address(this), src, dst, tokens);\n\n /* Do not allow self-transfers */\n if (src == dst) {\n revert TransferNotAllowed();\n }\n\n /* Get the allowance, infinite for the account owner */\n uint256 startingAllowance;\n if (spender == src) {\n startingAllowance = type(uint256).max;\n } else {\n startingAllowance = transferAllowances[src][spender];\n }\n\n /* Do the calculations, checking for {under,over}flow */\n uint256 allowanceNew = startingAllowance - tokens;\n uint256 srcTokensNew = accountTokens[src] - tokens;\n uint256 dstTokensNew = accountTokens[dst] + tokens;\n\n /////////////////////////\n // EFFECTS & INTERACTIONS\n\n accountTokens[src] = srcTokensNew;\n accountTokens[dst] = dstTokensNew;\n\n /* Eat some of the allowance (if necessary) */\n if (startingAllowance != type(uint256).max) {\n transferAllowances[src][spender] = allowanceNew;\n }\n\n /* We emit a Transfer event */\n emit Transfer(src, dst, tokens);\n }\n\n /**\n * @notice Initialize the money market\n * @param underlying_ The address of the underlying asset\n * @param comptroller_ The address of the Comptroller\n * @param interestRateModel_ The address of the interest rate model\n * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18\n * @param name_ ERC-20 name of this token\n * @param symbol_ ERC-20 symbol of this token\n * @param decimals_ ERC-20 decimal precision of this token\n * @param admin_ Address of the administrator of this token\n * @param accessControlManager_ AccessControlManager contract address\n * @param riskManagement Addresses of risk & income related contracts\n * @param reserveFactorMantissa_ Percentage of borrow interest that goes to reserves (from 0 to 1e18)\n */\n function _initialize(\n address underlying_,\n ComptrollerInterface comptroller_,\n InterestRateModel interestRateModel_,\n uint256 initialExchangeRateMantissa_,\n string memory name_,\n string memory symbol_,\n uint8 decimals_,\n address admin_,\n address accessControlManager_,\n RiskManagementInit memory riskManagement,\n uint256 reserveFactorMantissa_\n ) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n require(accrualBlockNumber == 0 && borrowIndex == 0, \"market may only be initialized once\");\n\n // Set initial exchange rate\n initialExchangeRateMantissa = initialExchangeRateMantissa_;\n require(initialExchangeRateMantissa > 0, \"initial exchange rate must be greater than zero.\");\n\n _setComptroller(comptroller_);\n\n // Initialize block number and borrow index (block number mocks depend on comptroller being set)\n accrualBlockNumber = _getBlockNumber();\n borrowIndex = MANTISSA_ONE;\n\n // Set the interest rate model (depends on block number / borrow index)\n _setInterestRateModelFresh(interestRateModel_);\n\n _setReserveFactorFresh(reserveFactorMantissa_);\n\n name = name_;\n symbol = symbol_;\n decimals = decimals_;\n _setShortfallContract(riskManagement.shortfall);\n _setProtocolShareReserve(riskManagement.protocolShareReserve);\n protocolSeizeShareMantissa = DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA;\n\n // Set underlying and sanity check it\n underlying = underlying_;\n IERC20Upgradeable(underlying).totalSupply();\n\n // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)\n _notEntered = true;\n _transferOwnership(admin_);\n }\n\n function _setShortfallContract(address shortfall_) internal {\n ensureNonzeroAddress(shortfall_);\n address oldShortfall = shortfall;\n shortfall = shortfall_;\n emit NewShortfallContract(oldShortfall, shortfall_);\n }\n\n function _setProtocolShareReserve(address payable protocolShareReserve_) internal {\n ensureNonzeroAddress(protocolShareReserve_);\n address oldProtocolShareReserve = address(protocolShareReserve);\n protocolShareReserve = protocolShareReserve_;\n emit NewProtocolShareReserve(oldProtocolShareReserve, address(protocolShareReserve_));\n }\n\n /**\n * @notice Gets balance of this contract in terms of the underlying\n * @dev This excludes the value of the current message, if any\n * @return The quantity of underlying tokens owned by this contract\n */\n function _getCashPrior() internal view virtual returns (uint256) {\n IERC20Upgradeable token = IERC20Upgradeable(underlying);\n return token.balanceOf(address(this));\n }\n\n /**\n * @dev Function to simply retrieve block number\n * This exists mainly for inheriting test contracts to stub this result.\n * @return Current block number\n */\n function _getBlockNumber() internal view virtual returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Return the borrow balance of account based on stored data\n * @param account The address whose balance should be calculated\n * @return borrowBalance the calculated balance\n */\n function _borrowBalanceStored(address account) internal view returns (uint256) {\n /* Get borrowBalance and borrowIndex */\n BorrowSnapshot memory borrowSnapshot = accountBorrows[account];\n\n /* If borrowBalance = 0 then borrowIndex is likely also 0.\n * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.\n */\n if (borrowSnapshot.principal == 0) {\n return 0;\n }\n\n /* Calculate new borrow balance using the interest index:\n * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex\n */\n uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex;\n\n return principalTimesIndex / borrowSnapshot.interestIndex;\n }\n\n /**\n * @notice Calculates the exchange rate from the underlying to the VToken\n * @dev This function does not accrue interest before calculating the exchange rate\n * @return exchangeRate Calculated exchange rate scaled by 1e18\n */\n function _exchangeRateStored() internal view virtual returns (uint256) {\n uint256 _totalSupply = totalSupply;\n if (_totalSupply == 0) {\n /*\n * If there are no tokens minted:\n * exchangeRate = initialExchangeRate\n */\n return initialExchangeRateMantissa;\n }\n /*\n * Otherwise:\n * exchangeRate = (totalCash + totalBorrows + badDebt - totalReserves) / totalSupply\n */\n uint256 totalCash = _getCashPrior();\n uint256 cashPlusBorrowsMinusReserves = totalCash + totalBorrows + badDebt - totalReserves;\n uint256 exchangeRate = (cashPlusBorrowsMinusReserves * EXP_SCALE) / _totalSupply;\n\n return exchangeRate;\n }\n}\n" + }, + "contracts/VTokenInterfaces.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { ResilientOracleInterface } from \"@venusprotocol/oracle/contracts/interfaces/OracleInterface.sol\";\n\nimport { ComptrollerInterface } from \"./ComptrollerInterface.sol\";\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\n\n/**\n * @title VTokenStorage\n * @author Venus\n * @notice Storage layout used by the `VToken` contract\n */\n// solhint-disable-next-line max-states-count\ncontract VTokenStorage {\n /**\n * @notice Container for borrow balance information\n * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action\n * @member interestIndex Global borrowIndex as of the most recent balance-changing action\n */\n struct BorrowSnapshot {\n uint256 principal;\n uint256 interestIndex;\n }\n\n /**\n * @dev Guard variable for re-entrancy checks\n */\n bool internal _notEntered;\n\n /**\n * @notice Underlying asset for this VToken\n */\n address public underlying;\n\n /**\n * @notice EIP-20 token name for this token\n */\n string public name;\n\n /**\n * @notice EIP-20 token symbol for this token\n */\n string public symbol;\n\n /**\n * @notice EIP-20 token decimals for this token\n */\n uint8 public decimals;\n\n /**\n * @notice Protocol share Reserve contract address\n */\n address payable public protocolShareReserve;\n\n // Maximum borrow rate that can ever be applied (.0005% / block)\n uint256 internal constant MAX_BORROW_RATE_MANTISSA = 0.0005e16;\n\n // Maximum fraction of interest that can be set aside for reserves\n uint256 internal constant MAX_RESERVE_FACTOR_MANTISSA = 1e18;\n\n /**\n * @notice Contract which oversees inter-vToken operations\n */\n ComptrollerInterface public comptroller;\n\n /**\n * @notice Model which tells what the current interest rate should be\n */\n InterestRateModel public interestRateModel;\n\n // Initial exchange rate used when minting the first VTokens (used when totalSupply = 0)\n uint256 internal initialExchangeRateMantissa;\n\n /**\n * @notice Fraction of interest currently set aside for reserves\n */\n uint256 public reserveFactorMantissa;\n\n /**\n * @notice Block number that interest was last accrued at\n */\n uint256 public accrualBlockNumber;\n\n /**\n * @notice Accumulator of the total earned interest rate since the opening of the market\n */\n uint256 public borrowIndex;\n\n /**\n * @notice Total amount of outstanding borrows of the underlying in this market\n */\n uint256 public totalBorrows;\n\n /**\n * @notice Total amount of reserves of the underlying held in this market\n */\n uint256 public totalReserves;\n\n /**\n * @notice Total number of tokens in circulation\n */\n uint256 public totalSupply;\n\n /**\n * @notice Total bad debt of the market\n */\n uint256 public badDebt;\n\n // Official record of token balances for each account\n mapping(address => uint256) internal accountTokens;\n\n // Approved token transfer amounts on behalf of others\n mapping(address => mapping(address => uint256)) internal transferAllowances;\n\n // Mapping of account addresses to outstanding borrow balances\n mapping(address => BorrowSnapshot) internal accountBorrows;\n\n /**\n * @notice Share of seized collateral that is added to reserves\n */\n uint256 public protocolSeizeShareMantissa;\n\n /**\n * @notice Storage of Shortfall contract address\n */\n address public shortfall;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n\n/**\n * @title VTokenInterface\n * @author Venus\n * @notice Interface implemented by the `VToken` contract\n */\nabstract contract VTokenInterface is VTokenStorage {\n struct RiskManagementInit {\n address shortfall;\n address payable protocolShareReserve;\n }\n\n /*** Market Events ***/\n\n /**\n * @notice Event emitted when interest is accrued\n */\n event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when tokens are minted\n */\n event Mint(address indexed minter, uint256 mintAmount, uint256 mintTokens, uint256 accountBalance);\n\n /**\n * @notice Event emitted when tokens are redeemed\n */\n event Redeem(address indexed redeemer, uint256 redeemAmount, uint256 redeemTokens, uint256 accountBalance);\n\n /**\n * @notice Event emitted when underlying is borrowed\n */\n event Borrow(address indexed borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);\n\n /**\n * @notice Event emitted when a borrow is repaid\n */\n event RepayBorrow(\n address indexed payer,\n address indexed borrower,\n uint256 repayAmount,\n uint256 accountBorrows,\n uint256 totalBorrows\n );\n\n /**\n * @notice Event emitted when bad debt is accumulated on a market\n * @param borrower borrower to \"forgive\"\n * @param badDebtDelta amount of new bad debt recorded\n * @param badDebtOld previous bad debt value\n * @param badDebtNew new bad debt value\n */\n event BadDebtIncreased(address indexed borrower, uint256 badDebtDelta, uint256 badDebtOld, uint256 badDebtNew);\n\n /**\n * @notice Event emitted when bad debt is recovered via an auction\n * @param badDebtOld previous bad debt value\n * @param badDebtNew new bad debt value\n */\n event BadDebtRecovered(uint256 badDebtOld, uint256 badDebtNew);\n\n /**\n * @notice Event emitted when a borrow is liquidated\n */\n event LiquidateBorrow(\n address indexed liquidator,\n address indexed borrower,\n uint256 repayAmount,\n address indexed vTokenCollateral,\n uint256 seizeTokens\n );\n\n /*** Admin Events ***/\n\n /**\n * @notice Event emitted when comptroller is changed\n */\n event NewComptroller(ComptrollerInterface indexed oldComptroller, ComptrollerInterface indexed newComptroller);\n\n /**\n * @notice Event emitted when shortfall contract address is changed\n */\n event NewShortfallContract(address indexed oldShortfall, address indexed newShortfall);\n\n /**\n * @notice Event emitted when protocol share reserve contract address is changed\n */\n event NewProtocolShareReserve(address indexed oldProtocolShareReserve, address indexed newProtocolShareReserve);\n\n /**\n * @notice Event emitted when interestRateModel is changed\n */\n event NewMarketInterestRateModel(\n InterestRateModel indexed oldInterestRateModel,\n InterestRateModel indexed newInterestRateModel\n );\n\n /**\n * @notice Event emitted when protocol seize share is changed\n */\n event NewProtocolSeizeShare(uint256 oldProtocolSeizeShareMantissa, uint256 newProtocolSeizeShareMantissa);\n\n /**\n * @notice Event emitted when the reserve factor is changed\n */\n event NewReserveFactor(uint256 oldReserveFactorMantissa, uint256 newReserveFactorMantissa);\n\n /**\n * @notice Event emitted when the reserves are added\n */\n event ReservesAdded(address indexed benefactor, uint256 addAmount, uint256 newTotalReserves);\n\n /**\n * @notice Event emitted when the reserves are reduced\n */\n event ReservesReduced(address indexed admin, uint256 reduceAmount, uint256 newTotalReserves);\n\n /**\n * @notice EIP20 Transfer event\n */\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n /**\n * @notice EIP20 Approval event\n */\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /**\n * @notice Event emitted when healing the borrow\n */\n event HealBorrow(address indexed payer, address indexed borrower, uint256 repayAmount);\n\n /**\n * @notice Event emitted when tokens are swept\n */\n event SweepToken(address indexed token);\n\n /*** User Interface ***/\n\n function mint(uint256 mintAmount) external virtual returns (uint256);\n\n function mintBehalf(address minter, uint256 mintAllowed) external virtual returns (uint256);\n\n function redeem(uint256 redeemTokens) external virtual returns (uint256);\n\n function redeemUnderlying(uint256 redeemAmount) external virtual returns (uint256);\n\n function borrow(uint256 borrowAmount) external virtual returns (uint256);\n\n function repayBorrow(uint256 repayAmount) external virtual returns (uint256);\n\n function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256);\n\n function liquidateBorrow(\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral\n ) external virtual returns (uint256);\n\n function healBorrow(\n address payer,\n address borrower,\n uint256 repayAmount\n ) external virtual;\n\n function forceLiquidateBorrow(\n address liquidator,\n address borrower,\n uint256 repayAmount,\n VTokenInterface vTokenCollateral,\n bool skipCloseFactorCheck\n ) external virtual;\n\n function seize(\n address liquidator,\n address borrower,\n uint256 seizeTokens\n ) external virtual;\n\n function transfer(address dst, uint256 amount) external virtual returns (bool);\n\n function transferFrom(\n address src,\n address dst,\n uint256 amount\n ) external virtual returns (bool);\n\n function accrueInterest() external virtual returns (uint256);\n\n function sweepToken(IERC20Upgradeable token) external virtual;\n\n /*** Admin Functions ***/\n\n function setReserveFactor(uint256 newReserveFactorMantissa) external virtual;\n\n function reduceReserves(uint256 reduceAmount) external virtual;\n\n function exchangeRateCurrent() external virtual returns (uint256);\n\n function borrowBalanceCurrent(address account) external virtual returns (uint256);\n\n function setInterestRateModel(InterestRateModel newInterestRateModel) external virtual;\n\n function addReserves(uint256 addAmount) external virtual;\n\n function totalBorrowsCurrent() external virtual returns (uint256);\n\n function balanceOfUnderlying(address owner) external virtual returns (uint256);\n\n function approve(address spender, uint256 amount) external virtual returns (bool);\n\n function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool);\n\n function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool);\n\n function allowance(address owner, address spender) external view virtual returns (uint256);\n\n function balanceOf(address owner) external view virtual returns (uint256);\n\n function getAccountSnapshot(address account)\n external\n view\n virtual\n returns (\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function borrowRatePerBlock() external view virtual returns (uint256);\n\n function supplyRatePerBlock() external view virtual returns (uint256);\n\n function borrowBalanceStored(address account) external view virtual returns (uint256);\n\n function exchangeRateStored() external view virtual returns (uint256);\n\n function getCash() external view virtual returns (uint256);\n\n /**\n * @notice Indicator that this is a VToken contract (for inspection)\n * @return Always true\n */\n function isVToken() external pure virtual returns (bool) {\n return true;\n }\n}\n" + }, + "contracts/WhitePaperInterestRateModel.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.13;\n\nimport { InterestRateModel } from \"./InterestRateModel.sol\";\nimport { BLOCKS_PER_YEAR, EXP_SCALE, MANTISSA_ONE } from \"./lib/constants.sol\";\n\n/**\n * @title Compound's WhitePaperInterestRateModel Contract\n * @author Compound\n * @notice The parameterized model described in section 2.4 of the original Compound Protocol whitepaper\n */\ncontract WhitePaperInterestRateModel is InterestRateModel {\n /**\n * @notice The multiplier of utilization rate that gives the slope of the interest rate\n */\n uint256 public immutable multiplierPerBlock;\n\n /**\n * @notice The base interest rate which is the y-intercept when utilization rate is 0\n */\n uint256 public immutable baseRatePerBlock;\n\n event NewInterestParams(uint256 baseRatePerBlock, uint256 multiplierPerBlock);\n\n /**\n * @notice Construct an interest rate model\n * @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by EXP_SCALE)\n * @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by EXP_SCALE)\n */\n constructor(uint256 baseRatePerYear, uint256 multiplierPerYear) {\n baseRatePerBlock = baseRatePerYear / BLOCKS_PER_YEAR;\n multiplierPerBlock = multiplierPerYear / BLOCKS_PER_YEAR;\n\n emit NewInterestParams(baseRatePerBlock, multiplierPerBlock);\n }\n\n /**\n * @notice Calculates the current borrow rate per block, with the error code expected by the market\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param badDebt The amount of badDebt in the market\n * @return The borrow rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getBorrowRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public view override returns (uint256) {\n uint256 ur = utilizationRate(cash, borrows, reserves, badDebt);\n return ((ur * multiplierPerBlock) / EXP_SCALE) + baseRatePerBlock;\n }\n\n /**\n * @notice Calculates the current supply rate per block\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market\n * @param reserveFactorMantissa The current reserve factor for the market\n * @param badDebt The amount of badDebt in the market\n * @return The supply rate percentage per block as a mantissa (scaled by EXP_SCALE)\n */\n function getSupplyRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 reserveFactorMantissa,\n uint256 badDebt\n ) public view override returns (uint256) {\n uint256 oneMinusReserveFactor = MANTISSA_ONE - reserveFactorMantissa;\n uint256 borrowRate = getBorrowRate(cash, borrows, reserves, badDebt);\n uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / EXP_SCALE;\n uint256 incomeToDistribute = borrows * rateToPool;\n uint256 supply = cash + borrows + badDebt - reserves;\n return incomeToDistribute / supply;\n }\n\n /**\n * @notice Calculates the utilization rate of the market: `(borrows + badDebt) / (cash + borrows + badDebt - reserves)`\n * @param cash The amount of cash in the market\n * @param borrows The amount of borrows in the market\n * @param reserves The amount of reserves in the market (currently unused)\n * @param badDebt The amount of badDebt in the market\n * @return The utilization rate as a mantissa between [0, MANTISSA_ONE]\n */\n function utilizationRate(\n uint256 cash,\n uint256 borrows,\n uint256 reserves,\n uint256 badDebt\n ) public pure returns (uint256) {\n // Utilization rate is 0 when there are no borrows and badDebt\n if ((borrows + badDebt) == 0) {\n return 0;\n }\n\n uint256 rate = ((borrows + badDebt) * EXP_SCALE) / (cash + borrows + badDebt - reserves);\n\n if (rate > EXP_SCALE) {\n rate = EXP_SCALE;\n }\n\n return rate;\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200, + "details": { + "yul": true + } + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/bsctestnet_addresses.json b/deployments/bsctestnet_addresses.json index 2e6d1a199..b4f6f764a 100644 --- a/deployments/bsctestnet_addresses.json +++ b/deployments/bsctestnet_addresses.json @@ -32,6 +32,8 @@ "MockRACA": "0xD60cC803d888A3e743F21D0bdE4bF2cAfdEA1F26", "MockSD": "0xac7D6B77EBD1DB8C5a9f0896e5eB5d485CB677b3", "MockSnBNB": "0xd2aF6A916Bc77764dc63742BC30f71AF4cF423F4", + "MockTHE": "0xB1cbD28Cb101c87b5F94a14A8EF081EA7F985593", + "MockTWT": "0xb99c6b26fdf3678c6e2aff8466e3625a0e7182f8", "MockUSDD": "0x2E2466e22FcbE0732Be385ee2FBb9C59a1098382", "MockWIN": "0x2E6Af3f3F059F43D764060968658c9F3c8f9479D", "MockWOO": "0x65B849A4Fc306AF413E341D44dF8482F963fBB91", @@ -102,6 +104,7 @@ "VToken_vRACA_GameFi": "0x1958035231E125830bA5d17D168cEa07Bb42184a", "VToken_vSnBNB_LiquidStakedBNB": "0xeffE7874C345aE877c1D893cd5160DDD359b24dA", "VToken_vTRX_Tron": "0x410286c43a525E1DCC7468a9B091C111C8324cd1", + "VToken_vTWT_DeFi": "0x4C94e67d239aD585275Fdd3246Ab82c8a2668564", "VToken_vUSDD_DeFi": "0xa109DE0abaeefC521Ec29D89eA42E64F37A6882E", "VToken_vUSDD_GameFi": "0xdeDf3B2bcF25d0023115fd71a0F8221C91C92B1a", "VToken_vUSDD_LiquidStakedBNB": "0xD5b20708d8f0FcA52cb609938D0594C4e32E5DaD", diff --git a/helpers/deploymentConfig.ts b/helpers/deploymentConfig.ts index 35a8ca7af..248b804c4 100644 --- a/helpers/deploymentConfig.ts +++ b/helpers/deploymentConfig.ts @@ -737,6 +737,13 @@ export const globalConfig: NetworkConfig = { decimals: 18, tokenAddress: ethers.constants.AddressZero, }, + { + isMock: false, + name: "Trust Wallet", + symbol: "TWT", + decimals: 18, + tokenAddress: "0xb99c6b26fdf3678c6e2aff8466e3625a0e7182f8", + }, { isMock: false, name: "agEUR", @@ -1001,6 +1008,24 @@ export const globalConfig: NetworkConfig = { vTokenReceiver: "0x0554d6079eBc222AD12405E52b264Bdb5B65D1cf", reduceReservesBlockDelta: "100", }, + { + name: "Venus TWT (DeFi)", + asset: "TWT", + symbol: "vTWT_DeFi", + rateModel: InterestRateModels.JumpRate.toString(), + baseRatePerYear: convertToUnit("0.02", 18), + multiplierPerYear: convertToUnit("0.2", 18), + jumpMultiplierPerYear: convertToUnit("3", 18), + kink_: convertToUnit("0.5", 18), + collateralFactor: convertToUnit("0.5", 18), + liquidationThreshold: convertToUnit("0.6", 18), + reserveFactor: convertToUnit("0.25", 18), + initialSupply: convertToUnit("10000", 18), + supplyCap: convertToUnit("1000000", 18), + borrowCap: convertToUnit("500000", 18), + vTokenReceiver: "0x0848dB7cB495E7b9aDA1D4dC972b9A526D014D84", + reduceReservesBlockDelta: "100", + }, ], rewards: [ { @@ -1565,6 +1590,13 @@ export const globalConfig: NetworkConfig = { decimals: 18, tokenAddress: "0x3BC5AC0dFdC871B365d159f728dd1B9A0B5481E8", }, + { + isMock: false, + name: "Trust Wallet", + symbol: "TWT", + decimals: 18, + tokenAddress: "0x4b0f1812e5df2a09796481ff14017e6005508003", + }, { isMock: false, name: "agEUR", @@ -1830,6 +1862,24 @@ export const globalConfig: NetworkConfig = { vTokenReceiver: "0x0554d6079eBc222AD12405E52b264Bdb5B65D1cf", reduceReservesBlockDelta: "28800", }, + { + name: "Venus TWT (DeFi)", + asset: "TWT", + symbol: "vTWT_DeFi", + rateModel: InterestRateModels.JumpRate.toString(), + baseRatePerYear: convertToUnit("0.02", 18), + multiplierPerYear: convertToUnit("0.2", 18), + jumpMultiplierPerYear: convertToUnit("3", 18), + kink_: convertToUnit("0.5", 18), + collateralFactor: convertToUnit("0.5", 18), + liquidationThreshold: convertToUnit("0.6", 18), + reserveFactor: convertToUnit("0.25", 18), + initialSupply: convertToUnit("10000", 18), + supplyCap: convertToUnit("1000000", 18), + borrowCap: convertToUnit("500000", 18), + vTokenReceiver: "0x0848dB7cB495E7b9aDA1D4dC972b9A526D014D84", + reduceReservesBlockDelta: "28800", + }, ], rewards: [ {