From 06307aca490b37d1fb1d39c30ebb52d4a83bd9d3 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Tue, 3 Feb 2026 14:16:23 +0530 Subject: [PATCH 1/9] feat: add VIP-900 DeviationSentinel configuration for BSC testnet and mainnet Configure DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle on BSC mainnet and testnet. Grants keeper and governance timelock permissions for price monitoring and market protection actions. --- .../vip-900/abi/AccessControlManager.json | 126 + .../vip-900/abi/DeviationSentinel.json | 657 +++ simulations/vip-900/abi/DexOracle.json | 299 ++ simulations/vip-900/abi/ERC20.json | 134 + simulations/vip-900/abi/ResilientOracle.json | 750 ++++ simulations/vip-900/abi/SentinelOracle.json | 331 ++ simulations/vip-900/abi/comptroller.json | 3979 +++++++++++++++++ simulations/vip-900/bscmainnet.ts | 274 ++ simulations/vip-900/bsctestnet-addendum-2.ts | 130 + simulations/vip-900/bsctestnet-addendum.ts | 46 + simulations/vip-900/bsctestnet.ts | 170 + vips/vip-900/bscmainnet.ts | 209 + vips/vip-900/bsctestnet-addendum-2.ts | 58 + vips/vip-900/bsctestnet-addendum.ts | 50 + vips/vip-900/bsctestnet.ts | 157 + 15 files changed, 7370 insertions(+) create mode 100644 simulations/vip-900/abi/AccessControlManager.json create mode 100644 simulations/vip-900/abi/DeviationSentinel.json create mode 100644 simulations/vip-900/abi/DexOracle.json create mode 100644 simulations/vip-900/abi/ERC20.json create mode 100644 simulations/vip-900/abi/ResilientOracle.json create mode 100644 simulations/vip-900/abi/SentinelOracle.json create mode 100644 simulations/vip-900/abi/comptroller.json create mode 100644 simulations/vip-900/bscmainnet.ts create mode 100644 simulations/vip-900/bsctestnet-addendum-2.ts create mode 100644 simulations/vip-900/bsctestnet-addendum.ts create mode 100644 simulations/vip-900/bsctestnet.ts create mode 100644 vips/vip-900/bscmainnet.ts create mode 100644 vips/vip-900/bsctestnet-addendum-2.ts create mode 100644 vips/vip-900/bsctestnet-addendum.ts create mode 100644 vips/vip-900/bsctestnet.ts diff --git a/simulations/vip-900/abi/AccessControlManager.json b/simulations/vip-900/abi/AccessControlManager.json new file mode 100644 index 000000000..687d32137 --- /dev/null +++ b/simulations/vip-900/abi/AccessControlManager.json @@ -0,0 +1,126 @@ +[ + { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32" }, + { "indexed": true, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32" } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "address", "name": "account", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "indexed": true, "internalType": "address", "name": "account", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "sender", "type": "address" } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes32", "name": "role", "type": "bytes32" }], + "name": "getRoleAdmin", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" }, + { "internalType": "address", "name": "accountToPermit", "type": "address" } + ], + "name": "giveCallPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "hasRole", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" } + ], + "name": "isAllowedToCall", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" }, + { "internalType": "address", "name": "accountToRevoke", "type": "address" } + ], + "name": "revokeCallPermission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes32", "name": "role", "type": "bytes32" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-900/abi/DeviationSentinel.json b/simulations/vip-900/abi/DeviationSentinel.json new file mode 100644 index 000000000..394c9d7d8 --- /dev/null +++ b/simulations/vip-900/abi/DeviationSentinel.json @@ -0,0 +1,657 @@ +[ + { + "inputs": [ + { + "internalType": "contract ICorePoolComptroller", + "name": "corePoolComptroller_", + "type": "address" + }, + { + "internalType": "contract ResilientOracleInterface", + "name": "resilientOracle_", + "type": "address" + }, + { + "internalType": "contract OracleInterface", + "name": "sentinelOracle_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "errorCode", + "type": "uint256" + } + ], + "name": "ComptrollerError", + "type": "error" + }, + { + "inputs": [], + "name": "ExceedsMaxDeviation", + "type": "error" + }, + { + "inputs": [], + "name": "MarketNotConfigured", + "type": "error" + }, + { + "inputs": [], + "name": "TokenMonitoringDisabled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "calledContract", + "type": "address" + }, + { + "internalType": "string", + "name": "methodSignature", + "type": "string" + } + ], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [], + "name": "UnauthorizedKeeper", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroDeviation", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "BorrowPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "BorrowUnpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldCF", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newCF", + "type": "uint256" + } + ], + "name": "CollateralFactorUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "MarketStateReset", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlManager", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlManager", + "type": "address" + } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "SupplyPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "SupplyUnpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "deviation", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct DeviationSentinel.DeviationConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "TokenConfigUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "TokenMonitoringStatusChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "keeper", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isTrusted", + "type": "bool" + } + ], + "name": "TrustedKeeperUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "CORE_POOL_COMPTROLLER", + "outputs": [ + { + "internalType": "contract ICorePoolComptroller", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_DEVIATION", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RESILIENT_ORACLE", + "outputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SENTINEL_ORACLE", + "outputs": [ + { + "internalType": "contract OracleInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IVToken", + "name": "market", + "type": "address" + } + ], + "name": "checkPriceDeviation", + "outputs": [ + { + "internalType": "bool", + "name": "hasDeviation", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "oraclePrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sentinelPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deviationPercent", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IVToken", + "name": "market", + "type": "address" + } + ], + "name": "handleDeviation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "marketStates", + "outputs": [ + { + "internalType": "bool", + "name": "borrowPaused", + "type": "bool" + }, + { + "internalType": "bool", + "name": "cfModifiedAndSupplyPaused", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IVToken", + "name": "market", + "type": "address" + } + ], + "name": "resetMarketState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "deviation", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "internalType": "struct DeviationSentinel.DeviationConfig", + "name": "config", + "type": "tuple" + } + ], + "name": "setTokenConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "setTokenMonitoringEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "keeper", + "type": "address" + }, + { + "internalType": "bool", + "name": "isTrusted", + "type": "bool" + } + ], + "name": "setTrustedKeeper", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "tokenConfigs", + "outputs": [ + { + "internalType": "uint8", + "name": "deviation", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "trustedKeepers", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-900/abi/DexOracle.json b/simulations/vip-900/abi/DexOracle.json new file mode 100644 index 000000000..66770c861 --- /dev/null +++ b/simulations/vip-900/abi/DexOracle.json @@ -0,0 +1,299 @@ +[ + { + "inputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "resilientOracle_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "InvalidPool", + "type": "error" + }, + { + "inputs": [], + "name": "TokenNotConfigured", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "calledContract", + "type": "address" + }, + { + "internalType": "string", + "name": "methodSignature", + "type": "string" + } + ], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlManager", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlManager", + "type": "address" + } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolConfigUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "RESILIENT_ORACLE", + "outputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "setPoolConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "tokenPools", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/simulations/vip-900/abi/ERC20.json b/simulations/vip-900/abi/ERC20.json new file mode 100644 index 000000000..3a509c9c4 --- /dev/null +++ b/simulations/vip-900/abi/ERC20.json @@ -0,0 +1,134 @@ +[ + { + "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" + } +] diff --git a/simulations/vip-900/abi/ResilientOracle.json b/simulations/vip-900/abi/ResilientOracle.json new file mode 100644 index 000000000..04fb2fe79 --- /dev/null +++ b/simulations/vip-900/abi/ResilientOracle.json @@ -0,0 +1,750 @@ +[ + { + "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" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "admin_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "calledContract", + "type": "address" + }, + { + "internalType": "string", + "name": "methodSignature", + "type": "string" + } + ], + "name": "Unauthorized", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlManager", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlManager", + "type": "address" + } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "role", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "OracleEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "oracle", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "role", + "type": "uint256" + } + ], + "name": "OracleSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "mainOracle", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "pivotOracle", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "fallbackOracle", + "type": "address" + } + ], + "name": "TokenConfigAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "BNB_ADDR", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INVALID_PRICE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "boundValidator", + "outputs": [ + { + "internalType": "contract BoundValidatorInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "internalType": "enum ResilientOracle.OracleRole", + "name": "role", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "enableOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "internalType": "enum ResilientOracle.OracleRole", + "name": "role", + "type": "uint8" + } + ], + "name": "getOracle", + "outputs": [ + { + "internalType": "address", + "name": "oracle", + "type": "address" + }, + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getTokenConfig", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "internalType": "address[3]", + "name": "oracles", + "type": "address[3]" + }, + { + "internalType": "bool[3]", + "name": "enableFlagsForOracles", + "type": "bool[3]" + } + ], + "internalType": "struct ResilientOracle.TokenConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "internalType": "address", + "name": "oracle", + "type": "address" + }, + { + "internalType": "enum ResilientOracle.OracleRole", + "name": "role", + "type": "uint8" + } + ], + "name": "setOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "internalType": "address[3]", + "name": "oracles", + "type": "address[3]" + }, + { + "internalType": "bool[3]", + "name": "enableFlagsForOracles", + "type": "bool[3]" + } + ], + "internalType": "struct ResilientOracle.TokenConfig", + "name": "tokenConfig", + "type": "tuple" + } + ], + "name": "setTokenConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "internalType": "address[3]", + "name": "oracles", + "type": "address[3]" + }, + { + "internalType": "bool[3]", + "name": "enableFlagsForOracles", + "type": "bool[3]" + } + ], + "internalType": "struct ResilientOracle.TokenConfig[]", + "name": "tokenConfigs_", + "type": "tuple[]" + } + ], + "name": "setTokenConfigs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "updateAssetPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "updatePrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "vBnb", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vai", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "admin_", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + } +] diff --git a/simulations/vip-900/abi/SentinelOracle.json b/simulations/vip-900/abi/SentinelOracle.json new file mode 100644 index 000000000..7c9930f95 --- /dev/null +++ b/simulations/vip-900/abi/SentinelOracle.json @@ -0,0 +1,331 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "TokenNotConfigured", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "calledContract", + "type": "address" + }, + { + "internalType": "string", + "name": "methodSignature", + "type": "string" + } + ], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "DirectPriceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlManager", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlManager", + "type": "address" + } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "oracle", + "type": "address" + } + ], + "name": "TokenOracleConfigUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "directPrices", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "name": "getPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "setDirectPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "oracle", + "type": "address" + } + ], + "name": "setTokenOracleConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "tokenConfigs", + "outputs": [ + { + "internalType": "address", + "name": "oracle", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/simulations/vip-900/abi/comptroller.json b/simulations/vip-900/abi/comptroller.json new file mode 100644 index 000000000..f2cb3ea37 --- /dev/null +++ b/simulations/vip-900/abi/comptroller.json @@ -0,0 +1,3979 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AlreadyInSelectedPool", + "type": "error" + }, + { + "inputs": [], + "name": "ArrayLengthMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "BorrowNotAllowedInPool", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyPoolLabel", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + } + ], + "name": "InactivePool", + "type": "error" + }, + { + "inputs": [], + "name": "IncompatibleBorrowedAssets", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidOperationForCorePool", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum WeightFunction", + "name": "strategy", + "type": "uint8" + } + ], + "name": "InvalidWeightingStrategy", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "errorCode", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "shortfall", + "type": "uint256" + } + ], + "name": "LiquidityCheckFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "MarketAlreadyListed", + "type": "error" + }, + { + "inputs": [], + "name": "MarketConfigNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "MarketNotListedInCorePool", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + } + ], + "name": "PoolDoesNotExist", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "PoolMarketNotFound", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "enum Action", + "name": "action", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bool", + "name": "pauseState", + "type": "bool" + } + ], + "name": "ActionPausedMarket", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "state", + "type": "bool" + } + ], + "name": "ActionProtocolPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "oldStatus", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "newStatus", + "type": "bool" + } + ], + "name": "BorrowAllowedUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "approver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "DelegateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "venusDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "venusBorrowIndex", + "type": "uint256" + } + ], + "name": "DistributedBorrowerVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "supplier", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "venusDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "venusSupplyIndex", + "type": "uint256" + } + ], + "name": "DistributedSupplierVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DistributedVAIVaultVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "IsForcedLiquidationEnabledForUserUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "IsForcedLiquidationEnabledUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "MarketUnlisted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlAddress", + "type": "address" + } + ], + "name": "NewAccessControl", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newBorrowCap", + "type": "uint256" + } + ], + "name": "NewBorrowCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldComptrollerLens", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newComptrollerLens", + "type": "address" + } + ], + "name": "NewComptrollerLens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldLiquidationThresholdMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newLiquidationThresholdMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationThreshold", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldLiquidatorContract", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newLiquidatorContract", + "type": "address" + } + ], + "name": "NewLiquidatorContract", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldPauseGuardian", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newPauseGuardian", + "type": "address" + } + ], + "name": "NewPauseGuardian", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract ResilientOracleInterface", + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract ResilientOracleInterface", + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IPrime", + "name": "oldPrimeToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IPrime", + "name": "newPrimeToken", + "type": "address" + } + ], + "name": "NewPrimeToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newSupplyCap", + "type": "uint256" + } + ], + "name": "NewSupplyCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldTreasuryAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newTreasuryAddress", + "type": "address" + } + ], + "name": "NewTreasuryAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldTreasuryGuardian", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newTreasuryGuardian", + "type": "address" + } + ], + "name": "NewTreasuryGuardian", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldTreasuryPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTreasuryPercent", + "type": "uint256" + } + ], + "name": "NewTreasuryPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract VAIControllerInterface", + "name": "oldVAIController", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract VAIControllerInterface", + "name": "newVAIController", + "type": "address" + } + ], + "name": "NewVAIController", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldVAIMintRate", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newVAIMintRate", + "type": "uint256" + } + ], + "name": "NewVAIMintRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vault_", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "releaseStartBlock_", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "releaseInterval_", + "type": "uint256" + } + ], + "name": "NewVAIVaultInfo", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldVenusVAIVaultRate", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newVenusVAIVaultRate", + "type": "uint256" + } + ], + "name": "NewVenusVAIVaultRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldXVS", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newXVS", + "type": "address" + } + ], + "name": "NewXVSToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldXVSVToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newXVSVToken", + "type": "address" + } + ], + "name": "NewXVSVToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "bool", + "name": "oldStatus", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "newStatus", + "type": "bool" + } + ], + "name": "PoolActiveStatusUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "bool", + "name": "oldStatus", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "newStatus", + "type": "bool" + } + ], + "name": "PoolFallbackStatusUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": false, + "internalType": "string", + "name": "oldLabel", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "newLabel", + "type": "string" + } + ], + "name": "PoolLabelUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "PoolMarketInitialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "PoolMarketRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint96", + "name": "previousPoolId", + "type": "uint96" + }, + { + "indexed": true, + "internalType": "uint96", + "name": "newPoolId", + "type": "uint96" + } + ], + "name": "PoolSelected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newSpeed", + "type": "uint256" + } + ], + "name": "VenusBorrowSpeedUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "VenusGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "VenusSeized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newSpeed", + "type": "uint256" + } + ], + "name": "VenusSupplySpeedUpdated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "contract Unitroller", + "name": "unitroller", + "type": "address" + } + ], + "name": "_become", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "_grantXVS", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAccessControlAddress", + "type": "address" + } + ], + "name": "_setAccessControl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "markets_", + "type": "address[]" + }, + { + "internalType": "enum Action[]", + "name": "actions_", + "type": "uint8[]" + }, + { + "internalType": "bool", + "name": "paused_", + "type": "bool" + } + ], + "name": "_setActionsPaused", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ComptrollerLensInterface", + "name": "comptrollerLens_", + "type": "address" + } + ], + "name": "_setComptrollerLens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "_setForcedLiquidation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "_setForcedLiquidationForUser", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newLiquidatorContract_", + "type": "address" + } + ], + "name": "_setLiquidatorContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newBorrowCaps", + "type": "uint256[]" + } + ], + "name": "_setMarketBorrowCaps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newSupplyCaps", + "type": "uint256[]" + } + ], + "name": "_setMarketSupplyCaps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newPauseGuardian", + "type": "address" + } + ], + "name": "_setPauseGuardian", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IPrime", + "name": "_prime", + "type": "address" + } + ], + "name": "_setPrimeToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "state", + "type": "bool" + } + ], + "name": "_setProtocolPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newTreasuryGuardian", + "type": "address" + }, + { + "internalType": "address", + "name": "newTreasuryAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "newTreasuryPercent", + "type": "uint256" + } + ], + "name": "_setTreasuryData", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VAIControllerInterface", + "name": "vaiController_", + "type": "address" + } + ], + "name": "_setVAIController", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newVAIMintRate", + "type": "uint256" + } + ], + "name": "_setVAIMintRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vault_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "releaseStartBlock_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minReleaseAmount_", + "type": "uint256" + } + ], + "name": "_setVAIVaultInfo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "supplySpeeds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "borrowSpeeds", + "type": "uint256[]" + } + ], + "name": "_setVenusSpeeds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "venusVAIVaultRate_", + "type": "uint256" + } + ], + "name": "_setVenusVAIVaultRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "xvs_", + "type": "address" + } + ], + "name": "_setXVSToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "xvsVToken_", + "type": "address" + } + ], + "name": "_setXVSVToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "internalType": "contract VToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "enum Action", + "name": "action", + "type": "uint8" + } + ], + "name": "actionPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96[]", + "name": "poolIds", + "type": "uint96[]" + }, + { + "internalType": "address[]", + "name": "vTokens", + "type": "address[]" + } + ], + "name": "addPoolMarkets", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "allMarkets", + "outputs": [ + { + "internalType": "contract VToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "approvedDelegates", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "borrowCapGuardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "borrowCaps", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "holders", + "type": "address[]" + }, + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "borrowers", + "type": "bool" + }, + { + "internalType": "bool", + "name": "suppliers", + "type": "bool" + }, + { + "internalType": "bool", + "name": "collateral", + "type": "bool" + } + ], + "name": "claimVenus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + } + ], + "name": "claimVenus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + } + ], + "name": "claimVenus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "holders", + "type": "address[]" + }, + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "borrowers", + "type": "bool" + }, + { + "internalType": "bool", + "name": "suppliers", + "type": "bool" + } + ], + "name": "claimVenus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + } + ], + "name": "claimVenusAsCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "comptrollerLens", + "outputs": [ + { + "internalType": "contract ComptrollerLensInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "corePoolId", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "label", + "type": "string" + } + ], + "name": "createPool", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "vTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + } + ], + "name": "enterPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAllMarkets", + "outputs": [ + { + "internalType": "contract VToken[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "internalType": "contract VToken[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getBorrowingPower", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "getCollateralFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "getEffectiveLiquidationIncentive", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "enum WeightFunction", + "name": "weightingStrategy", + "type": "uint8" + } + ], + "name": "getEffectiveLtvFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenModify", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "getHypotheticalAccountLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "getLiquidationIncentive", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "getLiquidationThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "getPoolMarketIndex", + "outputs": [ + { + "internalType": "PoolMarketId", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + } + ], + "name": "getPoolVTokens", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getXVSAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getXVSVTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint96", + "name": "targetPoolId", + "type": "uint96" + } + ], + "name": "hasValidPoolBorrows", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isForcedLiquidationEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "isForcedLiquidationEnabledForUser", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "isMarketListed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastPoolId", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + } + ], + "name": "liquidateVAICalculateSeizeTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquidatorContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "internalType": "bool", + "name": "isListed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "collateralFactorMantissa", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isVenus", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "liquidationThresholdMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationIncentiveMantissa", + "type": "uint256" + }, + { + "internalType": "uint96", + "name": "marketPoolId", + "type": "uint96" + }, + { + "internalType": "bool", + "name": "isBorrowAllowed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minReleaseAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "mintVAIGuardianPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualMintAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mintedVAIs", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "oracle", + "outputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pauseGuardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "poolMarkets", + "outputs": [ + { + "internalType": "bool", + "name": "isListed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "collateralFactorMantissa", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isVenus", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "liquidationThresholdMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationIncentiveMantissa", + "type": "uint256" + }, + { + "internalType": "uint96", + "name": "marketPoolId", + "type": "uint96" + }, + { + "internalType": "bool", + "name": "isBorrowAllowed", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "name": "pools", + "outputs": [ + { + "internalType": "string", + "name": "label", + "type": "string" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "bool", + "name": "allowCorePoolFallback", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prime", + "outputs": [ + { + "internalType": "contract IPrime", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "protocolPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "releaseStartBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "removePoolMarket", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "repayVAIGuardianPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "holders", + "type": "address[]" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "seizeVenus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "markets_", + "type": "address[]" + }, + { + "internalType": "enum Action[]", + "name": "actions_", + "type": "uint8[]" + }, + { + "internalType": "bool", + "name": "paused_", + "type": "bool" + } + ], + "name": "setActionsPaused", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "bool", + "name": "allowFallback", + "type": "bool" + } + ], + "name": "setAllowCorePoolFallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "setCloseFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "newCollateralFactorMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newLiquidationThresholdMantissa", + "type": "uint256" + } + ], + "name": "setCollateralFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "newCollateralFactorMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newLiquidationThresholdMantissa", + "type": "uint256" + } + ], + "name": "setCollateralFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "setForcedLiquidation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "borrowAllowed", + "type": "bool" + } + ], + "name": "setIsBorrowAllowed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "setLiquidationIncentive", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "setLiquidationIncentive", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newBorrowCaps", + "type": "uint256[]" + } + ], + "name": "setMarketBorrowCaps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newSupplyCaps", + "type": "uint256[]" + } + ], + "name": "setMarketSupplyCaps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "setMintedVAIOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "bool", + "name": "active", + "type": "bool" + } + ], + "name": "setPoolActive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "string", + "name": "newLabel", + "type": "string" + } + ], + "name": "setPoolLabel", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "newOracle", + "type": "address" + } + ], + "name": "setPriceOracle", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IPrime", + "name": "_prime", + "type": "address" + } + ], + "name": "setPrimeToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "supplyCaps", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "supportMarket", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "treasuryAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "treasuryGuardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "treasuryPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "unlistMarket", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "updateDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "userPoolId", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaiController", + "outputs": [ + { + "internalType": "contract VAIControllerInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaiMintRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vaiVaultAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusAccrued", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusBorrowSpeeds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusBorrowState", + "outputs": [ + { + "internalType": "uint224", + "name": "index", + "type": "uint224" + }, + { + "internalType": "uint32", + "name": "block", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusBorrowerIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "venusInitialIndex", + "outputs": [ + { + "internalType": "uint224", + "name": "", + "type": "uint224" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusSupplierIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusSupplySpeeds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusSupplyState", + "outputs": [ + { + "internalType": "uint224", + "name": "index", + "type": "uint224" + }, + { + "internalType": "uint32", + "name": "block", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "venusVAIVaultRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-900/bscmainnet.ts b/simulations/vip-900/bscmainnet.ts new file mode 100644 index 000000000..93c38ff03 --- /dev/null +++ b/simulations/vip-900/bscmainnet.ts @@ -0,0 +1,274 @@ +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents, initMainnetUser } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import vip900, { + ACM, + DEVIATION_SENTINEL, + GOVERNANCE_TIMELOCKS, + KEEPER_ADDRESS, + PANCAKESWAP_ORACLE, + SENTINEL_ORACLE, + UNISWAP_ORACLE, +} from "../../vips/vip-900/bscmainnet"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import DEVIATION_SENTINEL_ABI from "./abi/DeviationSentinel.json"; +import DEX_ORACLE_ABI from "./abi/DexOracle.json"; +import SENTINEL_ORACLE_ABI from "./abi/SentinelOracle.json"; + +const { bscmainnet } = NETWORK_ADDRESSES; + +forking(78835203, async () => { + let accessControlManager: Contract; + let deviationSentinel: Contract; + let sentinelOracle: Contract; + let uniswapOracle: Contract; + let pancakeSwapOracle: Contract; + + let impersonatedDeviationSentinel: SignerWithAddress; + let impersonatedSentinelOracle: SignerWithAddress; + let impersonatedUniswapOracle: SignerWithAddress; + let impersonatedPancakeSwapOracle: SignerWithAddress; + + before(async () => { + accessControlManager = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, ACM); + deviationSentinel = await ethers.getContractAt(DEVIATION_SENTINEL_ABI, DEVIATION_SENTINEL); + sentinelOracle = await ethers.getContractAt(SENTINEL_ORACLE_ABI, SENTINEL_ORACLE); + uniswapOracle = await ethers.getContractAt(DEX_ORACLE_ABI, UNISWAP_ORACLE); + pancakeSwapOracle = await ethers.getContractAt(DEX_ORACLE_ABI, PANCAKESWAP_ORACLE); + + impersonatedDeviationSentinel = await initMainnetUser(DEVIATION_SENTINEL, ethers.utils.parseEther("1")); + impersonatedSentinelOracle = await initMainnetUser(SENTINEL_ORACLE, ethers.utils.parseEther("1")); + impersonatedUniswapOracle = await initMainnetUser(UNISWAP_ORACLE, ethers.utils.parseEther("1")); + impersonatedPancakeSwapOracle = await initMainnetUser(PANCAKESWAP_ORACLE, ethers.utils.parseEther("1")); + }); + + describe("Pre-VIP behavior", () => { + // ======================================== + // Pending ownership checks + // ======================================== + + it("DeviationSentinel should have timelock as pending owner", async () => { + expect(await deviationSentinel.pendingOwner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + it("SentinelOracle should have timelock as pending owner", async () => { + expect(await sentinelOracle.pendingOwner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + it("UniswapOracle should have timelock as pending owner", async () => { + expect(await uniswapOracle.pendingOwner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + it("PancakeSwapOracle should have timelock as pending owner", async () => { + expect(await pancakeSwapOracle.pendingOwner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + // ======================================== + // Keeper should not have permissions + // ======================================== + + it("Keeper should not have permissions on DeviationSentinel", async () => { + const acm = accessControlManager.connect(impersonatedDeviationSentinel); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTrustedKeeper(address,bool)")).to.equal(false); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenConfig(address,(uint8,bool))")).to.equal(false); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenMonitoringEnabled(address,bool)")).to.equal(false); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "resetMarketState(address)")).to.equal(false); + }); + + it("Keeper should not have permissions on SentinelOracle", async () => { + const acm = accessControlManager.connect(impersonatedSentinelOracle); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenOracleConfig(address,address)")).to.equal(false); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setDirectPrice(address,uint256)")).to.equal(false); + }); + + it("Keeper should not have permissions on UniswapOracle", async () => { + const acm = accessControlManager.connect(impersonatedUniswapOracle); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setPoolConfig(address,address)")).to.equal(false); + }); + + it("Keeper should not have permissions on PancakeSwapOracle", async () => { + const acm = accessControlManager.connect(impersonatedPancakeSwapOracle); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setPoolConfig(address,address)")).to.equal(false); + }); + + // ======================================== + // Governance timelocks should not have permissions + // ======================================== + + it("Governance timelocks should not have permissions on DeviationSentinel", async () => { + const acm = accessControlManager.connect(impersonatedDeviationSentinel); + for (const timelock of GOVERNANCE_TIMELOCKS) { + expect(await acm.isAllowedToCall(timelock, "setTrustedKeeper(address,bool)")).to.equal(false); + expect(await acm.isAllowedToCall(timelock, "setTokenMonitoringEnabled(address,bool)")).to.equal(false); + expect(await acm.isAllowedToCall(timelock, "resetMarketState(address)")).to.equal(false); + } + }); + + // ======================================== + // DeviationSentinel should not have comptroller permissions + // ======================================== + + it("DeviationSentinel should not have permissions on any comptroller", async () => { + expect( + await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "setActionsPaused(address[],uint8[],bool)"), + ).to.equal(false); + expect( + await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "setCollateralFactor(address,uint256,uint256)"), + ).to.equal(false); + expect( + await accessControlManager.isAllowedToCall( + DEVIATION_SENTINEL, + "setCollateralFactor(uint96,address,uint256,uint256)", + ), + ).to.equal(false); + }); + }); + + testVip("VIP-900 Configure DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle", await vip900(), { + callbackAfterExecution: async txResponse => { + // 4 contracts accept ownership + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["OwnershipTransferred"], [4]); + // Note: BSC mainnet ACM does not emit PermissionGranted events parseable via the standard ABI. + // Permission correctness is verified in the Post-VIP behavior tests below. + // 4 accounts (keeper and 3 timelocks) whitelisted as trusted keepers on DeviationSentinel + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TrustedKeeperUpdated"], [4]); + }, + }); + + describe("Post-VIP behavior", () => { + // ======================================== + // Ownership checks + // ======================================== + + it("DeviationSentinel should have Normal Timelock as owner", async () => { + expect(await deviationSentinel.owner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + it("SentinelOracle should have Normal Timelock as owner", async () => { + expect(await sentinelOracle.owner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + it("UniswapOracle should have Normal Timelock as owner", async () => { + expect(await uniswapOracle.owner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + it("PancakeSwapOracle should have Normal Timelock as owner", async () => { + expect(await pancakeSwapOracle.owner()).to.equal(bscmainnet.NORMAL_TIMELOCK); + }); + + it("All contracts should have AddressZero as pending owner", async () => { + expect(await deviationSentinel.pendingOwner()).to.equal(ethers.constants.AddressZero); + expect(await sentinelOracle.pendingOwner()).to.equal(ethers.constants.AddressZero); + expect(await uniswapOracle.pendingOwner()).to.equal(ethers.constants.AddressZero); + expect(await pancakeSwapOracle.pendingOwner()).to.equal(ethers.constants.AddressZero); + }); + + // ======================================== + // Keeper permissions on DeviationSentinel + // ======================================== + + it("Keeper should have all required permissions on DeviationSentinel", async () => { + const acm = accessControlManager.connect(impersonatedDeviationSentinel); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTrustedKeeper(address,bool)")).to.equal(true); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenConfig(address,(uint8,bool))")).to.equal(true); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenMonitoringEnabled(address,bool)")).to.equal(true); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "resetMarketState(address)")).to.equal(true); + }); + + // ============================================ + // Governance permissions on DeviationSentinel + // ============================================ + + it("Governance timelocks should have setTrustedKeeper permission on DeviationSentinel", async () => { + const acm = accessControlManager.connect(impersonatedDeviationSentinel); + for (const timelock of GOVERNANCE_TIMELOCKS) { + expect(await acm.isAllowedToCall(timelock, "setTrustedKeeper(address,bool)")).to.equal(true); + } + }); + + it("Governance timelocks should have setTokenMonitoringEnabled permission on DeviationSentinel", async () => { + const acm = accessControlManager.connect(impersonatedDeviationSentinel); + for (const timelock of GOVERNANCE_TIMELOCKS) { + expect(await acm.isAllowedToCall(timelock, "setTokenMonitoringEnabled(address,bool)")).to.equal(true); + } + }); + + it("Governance timelocks should have resetMarketState permission on DeviationSentinel", async () => { + const acm = accessControlManager.connect(impersonatedDeviationSentinel); + for (const timelock of GOVERNANCE_TIMELOCKS) { + expect(await acm.isAllowedToCall(timelock, "resetMarketState(address)")).to.equal(true); + } + }); + + // ============================================ + // Governance timelocks whitelisted as keepers + // ============================================ + + it("Governance timelocks should be whitelisted as trusted keepers on DeviationSentinel", async () => { + for (const timelock of GOVERNANCE_TIMELOCKS) { + expect(await deviationSentinel.trustedKeepers(timelock)).to.equal(true); + } + }); + + // ==================================== + // Keeper permissions on SentinelOracle + // ==================================== + + it("Keeper should have all required permissions on SentinelOracle", async () => { + const acm = accessControlManager.connect(impersonatedSentinelOracle); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenOracleConfig(address,address)")).to.equal(true); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setDirectPrice(address,uint256)")).to.equal(true); + }); + + // ==================================== + // Keeper permissions on UniswapOracle + // ==================================== + + it("Keeper should have setPoolConfig permission on UniswapOracle", async () => { + const acm = accessControlManager.connect(impersonatedUniswapOracle); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setPoolConfig(address,address)")).to.equal(true); + }); + + // ======================================== + // Keeper permissions on PancakeSwapOracle + // ======================================== + + it("Keeper should have setPoolConfig permission on PancakeSwapOracle", async () => { + const acm = accessControlManager.connect(impersonatedPancakeSwapOracle); + expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setPoolConfig(address,address)")).to.equal(true); + }); + + // ============================================ + // DeviationSentinel permissions on Comptrollers + // ============================================ + + it("DeviationSentinel should have setActionsPaused permission on any comptroller", async () => { + expect( + await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "setActionsPaused(address[],uint8[],bool)"), + ).to.equal(true); + expect( + await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "_setActionsPaused(address[],uint8[],bool)"), + ).to.equal(true); + }); + + it("DeviationSentinel should have setCollateralFactor (isolated) permission on any comptroller", async () => { + expect( + await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "setCollateralFactor(address,uint256,uint256)"), + ).to.equal(true); + }); + + it("DeviationSentinel should have setCollateralFactor (core pool) permission on any comptroller", async () => { + expect( + await accessControlManager.isAllowedToCall( + DEVIATION_SENTINEL, + "setCollateralFactor(uint96,address,uint256,uint256)", + ), + ).to.equal(true); + }); + }); +}); diff --git a/simulations/vip-900/bsctestnet-addendum-2.ts b/simulations/vip-900/bsctestnet-addendum-2.ts new file mode 100644 index 000000000..a07a6177e --- /dev/null +++ b/simulations/vip-900/bsctestnet-addendum-2.ts @@ -0,0 +1,130 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents, setMaxStalePeriod } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import { + COMPTROLLER, + LT, + NEW_CF, + VETH_CORE, + VWBNB_CORE, + vip900TestnetAddendum2, +} from "../../vips/vip-900/bsctestnet-addendum-2"; +import ERC20_ABI from "./abi/ERC20.json"; +import RESILIENT_ORACLE_ABI from "./abi/ResilientOracle.json"; +import COMPTROLLER_ABI from "./abi/comptroller.json"; + +const Action = { + MINT: 0, + BORROW: 2, +}; + +const ETH = "0x98f7A83361F7Ac8765CcEBAB1425da6b341958a7"; +const WBNB = "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd"; + +forking(84038082, async () => { + let comptroller: Contract; + let resilientOracle: Contract; + let eth: Contract; + let wbnb: Contract; + + before(async () => { + comptroller = await ethers.getContractAt(COMPTROLLER_ABI, COMPTROLLER); + resilientOracle = await ethers.getContractAt( + RESILIENT_ORACLE_ABI, + NETWORK_ADDRESSES["bsctestnet"].RESILIENT_ORACLE, + ); + + eth = await ethers.getContractAt(ERC20_ABI, ETH); + wbnb = await ethers.getContractAt(ERC20_ABI, WBNB); + + await setMaxStalePeriod( + resilientOracle, + eth, + 7 * 24 * 60 * 60, // 7 days in seconds + ); + + await setMaxStalePeriod( + resilientOracle, + wbnb, + 7 * 24 * 60 * 60, // 7 days in seconds + ); + }); + + describe("Pre-VIP behavior", () => { + it("vETH_Core mint should not be paused", async () => { + const paused = await comptroller.actionPaused(VETH_CORE, Action.MINT); + expect(paused).to.equal(false); + }); + + it("vWBNB_Core mint should be paused", async () => { + const paused = await comptroller.actionPaused(VWBNB_CORE, Action.MINT); + expect(paused).to.equal(true); + }); + + it("vETH_Core borrow should be paused", async () => { + const paused = await comptroller.actionPaused(VETH_CORE, Action.BORROW); + expect(paused).to.equal(true); + }); + + it("vWBNB_Core borrow should not be paused", async () => { + const paused = await comptroller.actionPaused(VWBNB_CORE, Action.BORROW); + expect(paused).to.equal(false); + }); + + it("vETH_Core should have collateral factor of 0", async () => { + const market = await comptroller.markets(VETH_CORE); + expect(market.collateralFactorMantissa).to.equal(0); + expect(market.liquidationThresholdMantissa).to.equal(LT); + }); + + it("vWBNB_Core should have collateral factor of 0", async () => { + const market = await comptroller.markets(VWBNB_CORE); + expect(market.collateralFactorMantissa).to.equal(0); + expect(market.liquidationThresholdMantissa).to.equal(LT); + }); + }); + + testVip("VIP-900 Addendum 2: Unpause Mint and Update CF", await vip900TestnetAddendum2(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [COMPTROLLER_ABI], ["ActionPausedMarket", "NewCollateralFactor"], [8, 2]); + }, + }); + + describe("Post-VIP behavior", () => { + it("vETH_Core mint should be unpaused", async () => { + const paused = await comptroller.actionPaused(VETH_CORE, Action.MINT); + expect(paused).to.equal(false); + }); + + it("vWBNB_Core mint should be unpaused", async () => { + const paused = await comptroller.actionPaused(VWBNB_CORE, Action.MINT); + expect(paused).to.equal(false); + }); + + it("vETH_Core borrow should be unpaused", async () => { + const paused = await comptroller.actionPaused(VETH_CORE, Action.BORROW); + expect(paused).to.equal(false); + }); + + it("vWBNB_Core borrow should be unpaused", async () => { + const paused = await comptroller.actionPaused(VWBNB_CORE, Action.BORROW); + expect(paused).to.equal(false); + }); + + it("vETH_Core should have new collateral factor", async () => { + const market = await comptroller.markets(VETH_CORE); + expect(market.collateralFactorMantissa).to.equal(NEW_CF); + expect(market.liquidationThresholdMantissa).to.equal(LT); + }); + + it("vWBNB_Core should have new collateral factor", async () => { + const market = await comptroller.markets(VWBNB_CORE); + expect(market.collateralFactorMantissa).to.equal(NEW_CF); + expect(market.liquidationThresholdMantissa).to.equal(LT); + }); + }); +}); diff --git a/simulations/vip-900/bsctestnet-addendum.ts b/simulations/vip-900/bsctestnet-addendum.ts new file mode 100644 index 000000000..f24554c5b --- /dev/null +++ b/simulations/vip-900/bsctestnet-addendum.ts @@ -0,0 +1,46 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { expectEvents } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import { ACM, DEVIATION_SENTINEL, vip900TestnetAddendum } from "../../vips/vip-900/bsctestnet-addendum"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; + +forking(82830213, async () => { + let accessControlManager: Contract; + + before(async () => { + accessControlManager = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, ACM); + }); + + describe("Pre-VIP behavior", () => { + it("DeviationSentinel should not have _setActionsPaused permission on any comptroller", async () => { + expect( + await accessControlManager.hasPermission( + DEVIATION_SENTINEL, + ethers.constants.AddressZero, + "_setActionsPaused(address[],uint8[],bool)", + ), + ).to.equal(false); + }); + }); + + testVip("VIP-900 Addendum: Grant _setActionsPaused permission", await vip900TestnetAddendum(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [1]); + }, + }); + + describe("Post-VIP behavior", () => { + it("DeviationSentinel should have _setActionsPaused permission on any comptroller", async () => { + expect( + await accessControlManager.hasPermission( + DEVIATION_SENTINEL, + ethers.constants.AddressZero, + "_setActionsPaused(address[],uint8[],bool)", + ), + ).to.equal(true); + }); + }); +}); diff --git a/simulations/vip-900/bsctestnet.ts b/simulations/vip-900/bsctestnet.ts new file mode 100644 index 000000000..5fcc7490a --- /dev/null +++ b/simulations/vip-900/bsctestnet.ts @@ -0,0 +1,170 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import { ACM, DEVIATION_SENTINEL, KEEPER_ADDRESS, SENTINEL_ORACLE, vip900Testnet } from "../../vips/vip-900/bsctestnet"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import DEVIATION_SENTINEL_ABI from "./abi/DeviationSentinel.json"; +import SENTINEL_ORACLE_ABI from "./abi/SentinelOracle.json"; + +forking(82830213, async () => { + let accessControlManager: Contract; + let deviationSentinel: Contract; + let sentinelOracle: Contract; + + before(async () => { + accessControlManager = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, ACM); + deviationSentinel = await ethers.getContractAt(DEVIATION_SENTINEL_ABI, DEVIATION_SENTINEL); + sentinelOracle = await ethers.getContractAt(SENTINEL_ORACLE_ABI, SENTINEL_ORACLE); + }); + + describe("Pre-VIP behavior", () => { + it("DeviationSentinel should have pending owner", async () => { + expect(await deviationSentinel.pendingOwner()).to.equal(NETWORK_ADDRESSES.bsctestnet.NORMAL_TIMELOCK); + }); + + it("SentinelOracle should have pending owner", async () => { + expect(await sentinelOracle.pendingOwner()).to.equal(NETWORK_ADDRESSES.bsctestnet.NORMAL_TIMELOCK); + }); + + it("Keeper should not have permissions on DeviationSentinel", async () => { + expect( + await accessControlManager.hasPermission(KEEPER_ADDRESS, DEVIATION_SENTINEL, "setTrustedKeeper(address,bool)"), + ).to.equal(false); + expect( + await accessControlManager.hasPermission( + KEEPER_ADDRESS, + DEVIATION_SENTINEL, + "setTokenConfig(address,(uint8,bool))", + ), + ).to.equal(false); + expect( + await accessControlManager.hasPermission( + KEEPER_ADDRESS, + DEVIATION_SENTINEL, + "setTokenMonitoringEnabled(address,bool)", + ), + ).to.equal(false); + expect( + await accessControlManager.hasPermission(KEEPER_ADDRESS, DEVIATION_SENTINEL, "resetMarketState(address)"), + ).to.equal(false); + }); + + it("Keeper should not have permissions on SentinelOracle", async () => { + expect( + await accessControlManager.hasPermission( + KEEPER_ADDRESS, + SENTINEL_ORACLE, + "setTokenOracleConfig(address,address)", + ), + ).to.equal(false); + expect( + await accessControlManager.hasPermission(KEEPER_ADDRESS, SENTINEL_ORACLE, "setDirectPrice(address,uint256)"), + ).to.equal(false); + }); + + it("DeviationSentinel should not have permissions on any comptroller", async () => { + expect( + await accessControlManager.hasPermission( + DEVIATION_SENTINEL, + ethers.constants.AddressZero, + "setActionsPaused(address[],uint8[],bool)", + ), + ).to.equal(false); + expect( + await accessControlManager.hasPermission( + DEVIATION_SENTINEL, + ethers.constants.AddressZero, + "setCollateralFactor(address,uint256,uint256)", + ), + ).to.equal(false); + expect( + await accessControlManager.hasPermission( + DEVIATION_SENTINEL, + ethers.constants.AddressZero, + "setCollateralFactor(uint96,address,uint256,uint256)", + ), + ).to.equal(false); + }); + }); + + testVip("VIP-900 Configure DeviationSentinel and SentinelOracle", await vip900Testnet(), { + callbackAfterExecution: async txResponse => { + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["OwnershipTransferred"], [2]); + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [9]); + }, + }); + + describe("Post-VIP behavior", () => { + it("DeviationSentinel should have Normal Timelock as owner", async () => { + expect(await deviationSentinel.owner()).to.equal(NETWORK_ADDRESSES.bsctestnet.NORMAL_TIMELOCK); + }); + + it("SentinelOracle should have Normal Timelock as owner", async () => { + expect(await sentinelOracle.owner()).to.equal(NETWORK_ADDRESSES.bsctestnet.NORMAL_TIMELOCK); + }); + + it("Keeper should have all required permissions on DeviationSentinel", async () => { + expect( + await accessControlManager.hasPermission(KEEPER_ADDRESS, DEVIATION_SENTINEL, "setTrustedKeeper(address,bool)"), + ).to.equal(true); + expect( + await accessControlManager.hasPermission( + KEEPER_ADDRESS, + DEVIATION_SENTINEL, + "setTokenConfig(address,(uint8,bool))", + ), + ).to.equal(true); + expect( + await accessControlManager.hasPermission( + KEEPER_ADDRESS, + DEVIATION_SENTINEL, + "setTokenMonitoringEnabled(address,bool)", + ), + ).to.equal(true); + expect( + await accessControlManager.hasPermission(KEEPER_ADDRESS, DEVIATION_SENTINEL, "resetMarketState(address)"), + ).to.equal(true); + }); + + it("Keeper should have all required permissions on SentinelOracle", async () => { + expect( + await accessControlManager.hasPermission( + KEEPER_ADDRESS, + SENTINEL_ORACLE, + "setTokenOracleConfig(address,address)", + ), + ).to.equal(true); + expect( + await accessControlManager.hasPermission(KEEPER_ADDRESS, SENTINEL_ORACLE, "setDirectPrice(address,uint256)"), + ).to.equal(true); + }); + + it("DeviationSentinel should have permissions on any comptroller", async () => { + expect( + await accessControlManager.hasPermission( + DEVIATION_SENTINEL, + ethers.constants.AddressZero, + "setActionsPaused(address[],uint8[],bool)", + ), + ).to.equal(true); + expect( + await accessControlManager.hasPermission( + DEVIATION_SENTINEL, + ethers.constants.AddressZero, + "setCollateralFactor(address,uint256,uint256)", + ), + ).to.equal(true); + expect( + await accessControlManager.hasPermission( + DEVIATION_SENTINEL, + ethers.constants.AddressZero, + "setCollateralFactor(uint96,address,uint256,uint256)", + ), + ).to.equal(true); + }); + }); +}); diff --git a/vips/vip-900/bscmainnet.ts b/vips/vip-900/bscmainnet.ts new file mode 100644 index 000000000..22b60f982 --- /dev/null +++ b/vips/vip-900/bscmainnet.ts @@ -0,0 +1,209 @@ +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +const { bscmainnet } = NETWORK_ADDRESSES; + +// Deployed contract addresses on BSC Mainnet +export const DEVIATION_SENTINEL = "0x6599C15cc8407046CD91E5c0F8B7f765fF914870"; +export const SENTINEL_ORACLE = "0x58eae0Cf4215590E19860b66b146C5d539cb6f14"; +export const UNISWAP_ORACLE = "0x8FD05458faf220B2324c4BFbb29DBC4B3CF6f23f"; +export const PANCAKESWAP_ORACLE = "0x44B72078240A3509979faF450085Fa818401D32E"; + +// Keeper address that can call functions in the contracts +export const KEEPER_ADDRESS = "0x24c30C9C84b8a3C71A521ad30007ED47372331b3"; // TODO: Replace with actual keeper address + +// Access Control Manager +export const ACM = bscmainnet.ACCESS_CONTROL_MANAGER; + +export const GOVERNANCE_TIMELOCKS = [ + bscmainnet.NORMAL_TIMELOCK, + bscmainnet.FAST_TRACK_TIMELOCK, + bscmainnet.CRITICAL_TIMELOCK, +]; + +export const vip900 = () => { + const meta = { + version: "v2", + title: "VIP-900 Configure DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle on BSC Mainnet", + description: `#### Summary + +This VIP configures the DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle contracts on BSC Mainnet by: + +1. Accepting ownership of all four contracts +2. Granting permissions for the keeper address and governance timelocks to call functions on DeviationSentinel +3. Granting permissions for the keeper address to call functions on SentinelOracle, UniswapOracle, and PancakeSwapOracle +4. Granting permissions for DeviationSentinel to call required functions on all comptrollers (both isolated pools and core pool) +5. Whitelisting governance timelocks as trusted keepers on DeviationSentinel + +#### Description + +**DeviationSentinel** monitors price deviations between the ResilientOracle and SentinelOracle. When significant deviations are detected, it can pause specific market actions (borrow, mint) and adjust collateral factors to protect the protocol. + +**SentinelOracle** is an aggregator oracle that routes price requests to appropriate DEX oracles and supports direct price overrides. + +**UniswapOracle** and **PancakeSwapOracle** are DEX-based oracles that provide TWAP prices from Uniswap V3 and PancakeSwap V3 pools respectively. + +**Permissions being granted:** + +For the keeper address and governance timelocks on DeviationSentinel: +- setTrustedKeeper(address,bool) +- setTokenConfig(address,(uint8,bool)) +- setTokenMonitoringEnabled(address,bool) +- resetMarketState(address) + +For the keeper address on SentinelOracle: +- setTokenOracleConfig(address,address) +- setDirectPrice(address,uint256) + +For the keeper address on UniswapOracle: +- setPoolConfig(address,address) + +For the keeper address on PancakeSwapOracle: +- setPoolConfig(address,address) + +For DeviationSentinel on any Comptroller: +- setActionsPaused(address[],uint8[],bool) - to pause/unpause borrow and mint actions +- setCollateralFactor(address,uint256,uint256) - for isolated pools +- setCollateralFactor(uint96,address,uint256,uint256) - for core pool with emode groups + +#### References + +- [VIP Pull Request](https://github.com/VenusProtocol/vips/pull/658) +- [DeviationSentinel Contract](https://bscscan.com/address/${DEVIATION_SENTINEL}) +- [SentinelOracle Contract](https://bscscan.com/address/${SENTINEL_ORACLE}) +- [UniswapOracle Contract](https://bscscan.com/address/${UNISWAP_ORACLE}) +- [PancakeSwapOracle Contract](https://bscscan.com/address/${PANCAKESWAP_ORACLE}) +- [Keeper Address](https://bscscan.com/address/${KEEPER_ADDRESS})`, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + + return makeProposal( + [ + // ======================================== + // Accept ownership of all contracts + // ======================================== + + // Accept ownership of DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle + ...[DEVIATION_SENTINEL, SENTINEL_ORACLE, UNISWAP_ORACLE, PANCAKESWAP_ORACLE].map((contract: string) => ({ + target: contract, + signature: "acceptOwnership()", + params: [], + })), + + // ======================================== + // Grant permissions for DeviationSentinel + // ======================================== + + // Grant keeper permission to configure token deviation thresholds on DeviationSentinel + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [DEVIATION_SENTINEL, "setTokenConfig(address,(uint8,bool))", KEEPER_ADDRESS], + }, + + // Grant keeper and governance timelocks permissions to manage keepers, monitoring, and market state on DeviationSentinel + ...[KEEPER_ADDRESS, ...GOVERNANCE_TIMELOCKS].flatMap((account: string) => [ + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [DEVIATION_SENTINEL, "setTrustedKeeper(address,bool)", account], + }, + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [DEVIATION_SENTINEL, "setTokenMonitoringEnabled(address,bool)", account], + }, + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [DEVIATION_SENTINEL, "resetMarketState(address)", account], + }, + ]), + + // Whitelist keeper and governance timelocks as trusted keepers so VIPs can call handleDeviation after parameter changes + ...[KEEPER_ADDRESS, ...GOVERNANCE_TIMELOCKS].flatMap((timelock: string) => ({ + target: DEVIATION_SENTINEL, + signature: "setTrustedKeeper(address,bool)", + params: [timelock, true], + })), + + // ======================================== + // Grant permissions for SentinelOracle + // ======================================== + + // Grant keeper permission to configure token-to-oracle mappings on SentinelOracle + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [SENTINEL_ORACLE, "setTokenOracleConfig(address,address)", KEEPER_ADDRESS], + }, + + // Grant keeper permission to set direct prices on SentinelOracle + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [SENTINEL_ORACLE, "setDirectPrice(address,uint256)", KEEPER_ADDRESS], + }, + + // ======================================== + // Grant permissions for DEX Oracles + // ======================================== + + // Grant keeper permission to configure TWAP pool settings on UniswapOracle + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [UNISWAP_ORACLE, "setPoolConfig(address,address)", KEEPER_ADDRESS], + }, + + // Grant keeper permission to configure TWAP pool settings on PancakeSwapOracle + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [PANCAKESWAP_ORACLE, "setPoolConfig(address,address)", KEEPER_ADDRESS], + }, + + // ======================================== + // Grant DeviationSentinel permissions on Comptrollers + // ======================================== + + // Grant DeviationSentinel permission to pause/unpause borrow and mint actions on any comptroller + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [ethers.constants.AddressZero, "setActionsPaused(address[],uint8[],bool)", DEVIATION_SENTINEL], + }, + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [ethers.constants.AddressZero, "_setActionsPaused(address[],uint8[],bool)", DEVIATION_SENTINEL], + }, + + // Grant DeviationSentinel permission to set collateral factor on isolated pool comptrollers + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [ethers.constants.AddressZero, "setCollateralFactor(address,uint256,uint256)", DEVIATION_SENTINEL], + }, + + // Grant DeviationSentinel permission to set collateral factor on core pool comptroller (with emode poolId) + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [ + ethers.constants.AddressZero, + "setCollateralFactor(uint96,address,uint256,uint256)", + DEVIATION_SENTINEL, + ], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip900; diff --git a/vips/vip-900/bsctestnet-addendum-2.ts b/vips/vip-900/bsctestnet-addendum-2.ts new file mode 100644 index 000000000..0fe740b03 --- /dev/null +++ b/vips/vip-900/bsctestnet-addendum-2.ts @@ -0,0 +1,58 @@ +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +export const COMPTROLLER = "0x94d1820b2D1c7c7452A163983Dc888CEC546b77D"; +export const DEVIATION_SENTINEL = "0x9245d72712548707809D66848e63B8E2B169F3c1"; +export const VETH_CORE = "0x162D005F0Fff510E54958Cfc5CF32A3180A84aab"; +export const VWBNB_CORE = "0xd9E77847ec815E56ae2B9E69596C69b6972b0B1C"; + +const Action = { + MINT: 0, + BORROW: 2, +}; + +export const NEW_CF = "800000000000000000"; +export const LT = "800000000000000000"; + +export const vip900TestnetAddendum2 = () => { + const meta = { + version: "v2", + title: "VIP-900 Addendum 2: Unpause Mint and Update CF for vETH_Core and vWBNB_Core on BSC Testnet", + description: ``, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + + return makeProposal( + [ + { + target: COMPTROLLER, + signature: "_setActionsPaused(address[],uint8[],bool)", + params: [[VETH_CORE, VWBNB_CORE], [Action.MINT, Action.MINT], false], + }, + + { + target: COMPTROLLER, + signature: "_setActionsPaused(address[],uint8[],bool)", + params: [[VETH_CORE, VWBNB_CORE], [Action.BORROW, Action.BORROW], false], + }, + + { + target: COMPTROLLER, + signature: "setCollateralFactor(address,uint256,uint256)", + params: [VETH_CORE, NEW_CF, LT], + }, + + { + target: COMPTROLLER, + signature: "setCollateralFactor(address,uint256,uint256)", + params: [VWBNB_CORE, NEW_CF, LT], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip900TestnetAddendum2; diff --git a/vips/vip-900/bsctestnet-addendum.ts b/vips/vip-900/bsctestnet-addendum.ts new file mode 100644 index 000000000..29cbf4bd1 --- /dev/null +++ b/vips/vip-900/bsctestnet-addendum.ts @@ -0,0 +1,50 @@ +import { ethers } from "hardhat"; +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +// Deployed contract addresses on BSC Testnet +export const DEVIATION_SENTINEL = "0x9245d72712548707809D66848e63B8E2B169F3c1"; + +// Access Control Manager +export const ACM = "0x45f8a08F534f34A97187626E05d4b6648Eeaa9AA"; + +export const vip900TestnetAddendum = () => { + const meta = { + version: "v2", + title: "VIP-900 Addendum: Grant _setActionsPaused permission to DeviationSentinel on BSC Testnet", + description: `#### Summary + +This addendum to VIP-900 grants the missing \`_setActionsPaused(address[],uint8[],bool)\` permission to the DeviationSentinel contract on BSC Testnet. + +#### Description + +The original VIP-900 granted the \`setActionsPaused(address[],uint8[],bool)\` permission but missed the underscore-prefixed version \`_setActionsPaused(address[],uint8[],bool)\` which is the actual internal function signature used by comptrollers. + +This addendum grants: +- \`_setActionsPaused(address[],uint8[],bool)\` permission to DeviationSentinel on any comptroller (address zero pattern) + +This allows DeviationSentinel to properly pause/unpause market actions when price deviations are detected. + +#### References + +- [DeviationSentinel Contract](https://testnet.bscscan.com/address/${DEVIATION_SENTINEL})`, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + + return makeProposal( + [ + // Allow DeviationSentinel to pause/unpause actions on any comptroller (underscore version) + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [ethers.constants.AddressZero, "_setActionsPaused(address[],uint8[],bool)", DEVIATION_SENTINEL], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip900TestnetAddendum; diff --git a/vips/vip-900/bsctestnet.ts b/vips/vip-900/bsctestnet.ts new file mode 100644 index 000000000..f9bb6f86e --- /dev/null +++ b/vips/vip-900/bsctestnet.ts @@ -0,0 +1,157 @@ +import { ethers } from "hardhat"; +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +// Deployed contract addresses on BSC Testnet +export const DEVIATION_SENTINEL = " 0x9245d72712548707809D66848e63B8E2B169F3c1"; +export const SENTINEL_ORACLE = "0xa4f2B03919BAAdCA80C31406412C7Ee059A579D3"; + +// Access Control Manager +export const ACM = "0x45f8a08F534f34A97187626E05d4b6648Eeaa9AA"; + +// Keeper address that can call functions in the contracts +export const KEEPER_ADDRESS = "0x2Ce1d0ffD7E869D9DF33e28552b12DdDed326706"; + +export const vip900Testnet = () => { + const meta = { + version: "v2", + title: "VIP-900 Configure DeviationSentinel and SentinelOracle on BSC Testnet", + description: `#### Summary + +This VIP configures the DeviationSentinel and SentinelOracle contracts on BSC Testnet by: + +1. Accepting ownership of both contracts +2. Granting permissions for the keeper address (${KEEPER_ADDRESS}) to call functions in both contracts +3. Granting permissions for DeviationSentinel to call required functions on all comptrollers (both isolated pools and core pool) + +#### Description + +**DeviationSentinel** monitors price deviations between the ResilientOracle and SentinelOracle. When significant deviations are detected, it can pause specific market actions (borrow, mint) and adjust collateral factors to protect the protocol. + +**SentinelOracle** is an aggregator oracle that routes price requests to appropriate DEX oracles and supports direct price overrides. + +**Permissions being granted:** + +For the keeper address on DeviationSentinel: +- setTrustedKeeper(address,bool) +- setTokenConfig(address,(uint8,bool)) +- setTokenMonitoringEnabled(address,bool) +- resetMarketState(address) + +For the keeper address on SentinelOracle: +- setTokenOracleConfig(address,address) +- setDirectPrice(address,uint256) + +For DeviationSentinel on any Comptroller: +- setActionsPaused(address[],uint8[],bool) - to pause/unpause borrow and mint actions +- setCollateralFactor(address,uint256,uint256) - for isolated pools +- setCollateralFactor(uint96,address,uint256,uint256) - for core pool with emode groups + +#### References + +- [VIP Pull Request](https://github.com/VenusProtocol/vips/pull/658) +- [DeviationSentinel Contract](https://testnet.bscscan.com/address/${DEVIATION_SENTINEL}) +- [SentinelOracle Contract](https://testnet.bscscan.com/address/${SENTINEL_ORACLE}) +- [Keeper Address](https://testnet.bscscan.com/address/${KEEPER_ADDRESS})`, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + + return makeProposal( + [ + // ======================================== + // Accept ownership of all contracts + // ======================================== + + // Accept ownership of DeviationSentinel + { + target: DEVIATION_SENTINEL, + signature: "acceptOwnership()", + params: [], + }, + + // Accept ownership of SentinelOracle + { + target: SENTINEL_ORACLE, + signature: "acceptOwnership()", + params: [], + }, + + // ======================================== + // Grant permissions for DeviationSentinel + // ======================================== + + // Keeper permissions on DeviationSentinel + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [DEVIATION_SENTINEL, "setTrustedKeeper(address,bool)", KEEPER_ADDRESS], + }, + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [DEVIATION_SENTINEL, "setTokenConfig(address,(uint8,bool))", KEEPER_ADDRESS], + }, + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [DEVIATION_SENTINEL, "setTokenMonitoringEnabled(address,bool)", KEEPER_ADDRESS], + }, + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [DEVIATION_SENTINEL, "resetMarketState(address)", KEEPER_ADDRESS], + }, + + // ======================================== + // Grant permissions for SentinelOracle + // ======================================== + + // Keeper permissions on SentinelOracle + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [SENTINEL_ORACLE, "setTokenOracleConfig(address,address)", KEEPER_ADDRESS], + }, + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [SENTINEL_ORACLE, "setDirectPrice(address,uint256)", KEEPER_ADDRESS], + }, + + // ======================================== + // Grant DeviationSentinel permissions on Comptrollers + // ======================================== + + // Allow DeviationSentinel to pause/unpause actions on any comptroller + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [ethers.constants.AddressZero, "setActionsPaused(address[],uint8[],bool)", DEVIATION_SENTINEL], + }, + + // Allow DeviationSentinel to set collateral factor on any comptroller (isolated pools) + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [ethers.constants.AddressZero, "setCollateralFactor(address,uint256,uint256)", DEVIATION_SENTINEL], + }, + + // Allow DeviationSentinel to set collateral factor on any comptroller (core pool with poolId) + { + target: ACM, + signature: "giveCallPermission(address,string,address)", + params: [ + ethers.constants.AddressZero, + "setCollateralFactor(uint96,address,uint256,uint256)", + DEVIATION_SENTINEL, + ], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip900Testnet; From 18fc4539465db3c223e4fc236b5f56e0c8f15350 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Wed, 4 Feb 2026 14:19:04 +0530 Subject: [PATCH 2/9] refactor: update VIP-900 permissions to use GUARDIAN instead of KEEPER_ADDRESS Replace KEEPER_ADDRESS with GUARDIAN wallet for ACM permissions on DeviationSentinel, SentinelOracle, and DEX oracles. KEEPER_ADDRESS is now only whitelisted as a trusted keeper alongside GUARDIAN and governance timelocks. --- simulations/vip-900/bscmainnet.ts | 129 +++++++++++++----------------- vips/vip-900/bscmainnet.ts | 72 +++++++++-------- 2 files changed, 94 insertions(+), 107 deletions(-) diff --git a/simulations/vip-900/bscmainnet.ts b/simulations/vip-900/bscmainnet.ts index 93c38ff03..6fe8c114a 100644 --- a/simulations/vip-900/bscmainnet.ts +++ b/simulations/vip-900/bscmainnet.ts @@ -10,6 +10,7 @@ import vip900, { ACM, DEVIATION_SENTINEL, GOVERNANCE_TIMELOCKS, + GUARDIAN, KEEPER_ADDRESS, PANCAKESWAP_ORACLE, SENTINEL_ORACLE, @@ -22,6 +23,12 @@ import SENTINEL_ORACLE_ABI from "./abi/SentinelOracle.json"; const { bscmainnet } = NETWORK_ADDRESSES; +// Accounts that should have ACM permissions (GUARDIAN + governance timelocks) +const PERMISSION_ACCOUNTS = [GUARDIAN, ...GOVERNANCE_TIMELOCKS]; + +// Accounts that should be whitelisted as trusted keepers (keeper + GUARDIAN + governance timelocks) +const TRUSTED_KEEPER_ACCOUNTS = [KEEPER_ADDRESS, GUARDIAN, ...GOVERNANCE_TIMELOCKS]; + forking(78835203, async () => { let accessControlManager: Contract; let deviationSentinel: Contract; @@ -69,43 +76,38 @@ forking(78835203, async () => { }); // ======================================== - // Keeper should not have permissions + // GUARDIAN and timelocks should not have permissions // ======================================== - it("Keeper should not have permissions on DeviationSentinel", async () => { + it("GUARDIAN and governance timelocks should not have permissions on DeviationSentinel", async () => { const acm = accessControlManager.connect(impersonatedDeviationSentinel); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTrustedKeeper(address,bool)")).to.equal(false); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenConfig(address,(uint8,bool))")).to.equal(false); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenMonitoringEnabled(address,bool)")).to.equal(false); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "resetMarketState(address)")).to.equal(false); + for (const account of PERMISSION_ACCOUNTS) { + expect(await acm.isAllowedToCall(account, "setTrustedKeeper(address,bool)")).to.equal(false); + expect(await acm.isAllowedToCall(account, "setTokenConfig(address,(uint8,bool))")).to.equal(false); + expect(await acm.isAllowedToCall(account, "setTokenMonitoringEnabled(address,bool)")).to.equal(false); + expect(await acm.isAllowedToCall(account, "resetMarketState(address)")).to.equal(false); + } }); - it("Keeper should not have permissions on SentinelOracle", async () => { + it("GUARDIAN and governance timelocks should not have permissions on SentinelOracle", async () => { const acm = accessControlManager.connect(impersonatedSentinelOracle); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenOracleConfig(address,address)")).to.equal(false); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setDirectPrice(address,uint256)")).to.equal(false); + for (const account of PERMISSION_ACCOUNTS) { + expect(await acm.isAllowedToCall(account, "setTokenOracleConfig(address,address)")).to.equal(false); + expect(await acm.isAllowedToCall(account, "setDirectPrice(address,uint256)")).to.equal(false); + } }); - it("Keeper should not have permissions on UniswapOracle", async () => { + it("GUARDIAN and governance timelocks should not have permissions on UniswapOracle", async () => { const acm = accessControlManager.connect(impersonatedUniswapOracle); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setPoolConfig(address,address)")).to.equal(false); + for (const account of PERMISSION_ACCOUNTS) { + expect(await acm.isAllowedToCall(account, "setPoolConfig(address,address)")).to.equal(false); + } }); - it("Keeper should not have permissions on PancakeSwapOracle", async () => { + it("GUARDIAN and governance timelocks should not have permissions on PancakeSwapOracle", async () => { const acm = accessControlManager.connect(impersonatedPancakeSwapOracle); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setPoolConfig(address,address)")).to.equal(false); - }); - - // ======================================== - // Governance timelocks should not have permissions - // ======================================== - - it("Governance timelocks should not have permissions on DeviationSentinel", async () => { - const acm = accessControlManager.connect(impersonatedDeviationSentinel); - for (const timelock of GOVERNANCE_TIMELOCKS) { - expect(await acm.isAllowedToCall(timelock, "setTrustedKeeper(address,bool)")).to.equal(false); - expect(await acm.isAllowedToCall(timelock, "setTokenMonitoringEnabled(address,bool)")).to.equal(false); - expect(await acm.isAllowedToCall(timelock, "resetMarketState(address)")).to.equal(false); + for (const account of PERMISSION_ACCOUNTS) { + expect(await acm.isAllowedToCall(account, "setPoolConfig(address,address)")).to.equal(false); } }); @@ -129,14 +131,14 @@ forking(78835203, async () => { }); }); - testVip("VIP-900 Configure DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle", await vip900(), { + testVip("VIP-900", await vip900(), { callbackAfterExecution: async txResponse => { // 4 contracts accept ownership await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["OwnershipTransferred"], [4]); // Note: BSC mainnet ACM does not emit PermissionGranted events parseable via the standard ABI. // Permission correctness is verified in the Post-VIP behavior tests below. - // 4 accounts (keeper and 3 timelocks) whitelisted as trusted keepers on DeviationSentinel - await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TrustedKeeperUpdated"], [4]); + // 5 accounts (keeper, GUARDIAN, and 3 timelocks) whitelisted as trusted keepers on DeviationSentinel + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TrustedKeeperUpdated"], [5]); }, }); @@ -169,78 +171,61 @@ forking(78835203, async () => { }); // ======================================== - // Keeper permissions on DeviationSentinel + // GUARDIAN and timelocks permissions on DeviationSentinel // ======================================== - it("Keeper should have all required permissions on DeviationSentinel", async () => { - const acm = accessControlManager.connect(impersonatedDeviationSentinel); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTrustedKeeper(address,bool)")).to.equal(true); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenConfig(address,(uint8,bool))")).to.equal(true); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenMonitoringEnabled(address,bool)")).to.equal(true); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "resetMarketState(address)")).to.equal(true); - }); - - // ============================================ - // Governance permissions on DeviationSentinel - // ============================================ - - it("Governance timelocks should have setTrustedKeeper permission on DeviationSentinel", async () => { - const acm = accessControlManager.connect(impersonatedDeviationSentinel); - for (const timelock of GOVERNANCE_TIMELOCKS) { - expect(await acm.isAllowedToCall(timelock, "setTrustedKeeper(address,bool)")).to.equal(true); - } - }); - - it("Governance timelocks should have setTokenMonitoringEnabled permission on DeviationSentinel", async () => { + it("GUARDIAN and governance timelocks should have all required permissions on DeviationSentinel", async () => { const acm = accessControlManager.connect(impersonatedDeviationSentinel); - for (const timelock of GOVERNANCE_TIMELOCKS) { - expect(await acm.isAllowedToCall(timelock, "setTokenMonitoringEnabled(address,bool)")).to.equal(true); - } - }); - - it("Governance timelocks should have resetMarketState permission on DeviationSentinel", async () => { - const acm = accessControlManager.connect(impersonatedDeviationSentinel); - for (const timelock of GOVERNANCE_TIMELOCKS) { - expect(await acm.isAllowedToCall(timelock, "resetMarketState(address)")).to.equal(true); + for (const account of PERMISSION_ACCOUNTS) { + expect(await acm.isAllowedToCall(account, "setTrustedKeeper(address,bool)")).to.equal(true); + expect(await acm.isAllowedToCall(account, "setTokenConfig(address,(uint8,bool))")).to.equal(true); + expect(await acm.isAllowedToCall(account, "setTokenMonitoringEnabled(address,bool)")).to.equal(true); + expect(await acm.isAllowedToCall(account, "resetMarketState(address)")).to.equal(true); } }); // ============================================ - // Governance timelocks whitelisted as keepers + // Trusted keepers whitelisted // ============================================ - it("Governance timelocks should be whitelisted as trusted keepers on DeviationSentinel", async () => { - for (const timelock of GOVERNANCE_TIMELOCKS) { - expect(await deviationSentinel.trustedKeepers(timelock)).to.equal(true); + it("Keeper, GUARDIAN, and governance timelocks should be whitelisted as trusted keepers on DeviationSentinel", async () => { + for (const account of TRUSTED_KEEPER_ACCOUNTS) { + expect(await deviationSentinel.trustedKeepers(account)).to.equal(true); } }); // ==================================== - // Keeper permissions on SentinelOracle + // GUARDIAN and timelocks permissions on SentinelOracle // ==================================== - it("Keeper should have all required permissions on SentinelOracle", async () => { + it("GUARDIAN and governance timelocks should have all required permissions on SentinelOracle", async () => { const acm = accessControlManager.connect(impersonatedSentinelOracle); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setTokenOracleConfig(address,address)")).to.equal(true); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setDirectPrice(address,uint256)")).to.equal(true); + for (const account of PERMISSION_ACCOUNTS) { + expect(await acm.isAllowedToCall(account, "setTokenOracleConfig(address,address)")).to.equal(true); + expect(await acm.isAllowedToCall(account, "setDirectPrice(address,uint256)")).to.equal(true); + } }); // ==================================== - // Keeper permissions on UniswapOracle + // GUARDIAN and timelocks permissions on UniswapOracle // ==================================== - it("Keeper should have setPoolConfig permission on UniswapOracle", async () => { + it("GUARDIAN and governance timelocks should have setPoolConfig permission on UniswapOracle", async () => { const acm = accessControlManager.connect(impersonatedUniswapOracle); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setPoolConfig(address,address)")).to.equal(true); + for (const account of PERMISSION_ACCOUNTS) { + expect(await acm.isAllowedToCall(account, "setPoolConfig(address,address)")).to.equal(true); + } }); // ======================================== - // Keeper permissions on PancakeSwapOracle + // GUARDIAN and timelocks permissions on PancakeSwapOracle // ======================================== - it("Keeper should have setPoolConfig permission on PancakeSwapOracle", async () => { + it("GUARDIAN and governance timelocks should have setPoolConfig permission on PancakeSwapOracle", async () => { const acm = accessControlManager.connect(impersonatedPancakeSwapOracle); - expect(await acm.isAllowedToCall(KEEPER_ADDRESS, "setPoolConfig(address,address)")).to.equal(true); + for (const account of PERMISSION_ACCOUNTS) { + expect(await acm.isAllowedToCall(account, "setPoolConfig(address,address)")).to.equal(true); + } }); // ============================================ diff --git a/vips/vip-900/bscmainnet.ts b/vips/vip-900/bscmainnet.ts index 22b60f982..faf11cda0 100644 --- a/vips/vip-900/bscmainnet.ts +++ b/vips/vip-900/bscmainnet.ts @@ -11,8 +11,11 @@ export const SENTINEL_ORACLE = "0x58eae0Cf4215590E19860b66b146C5d539cb6f14"; export const UNISWAP_ORACLE = "0x8FD05458faf220B2324c4BFbb29DBC4B3CF6f23f"; export const PANCAKESWAP_ORACLE = "0x44B72078240A3509979faF450085Fa818401D32E"; -// Keeper address that can call functions in the contracts -export const KEEPER_ADDRESS = "0x24c30C9C84b8a3C71A521ad30007ED47372331b3"; // TODO: Replace with actual keeper address +// GUARDIAN address +export const GUARDIAN = "0x1C2CAc6ec528c20800B2fe734820D87b581eAA6B"; + +// Keeper address +export const KEEPER_ADDRESS = "0x57fa23f591203f61cef84a7bc892df69ca95c86e"; // Access Control Manager export const ACM = bscmainnet.ACCESS_CONTROL_MANAGER; @@ -32,10 +35,10 @@ export const vip900 = () => { This VIP configures the DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle contracts on BSC Mainnet by: 1. Accepting ownership of all four contracts -2. Granting permissions for the keeper address and governance timelocks to call functions on DeviationSentinel -3. Granting permissions for the keeper address to call functions on SentinelOracle, UniswapOracle, and PancakeSwapOracle +2. Granting permissions for GUARDIAN and governance timelocks to call functions on DeviationSentinel +3. Granting permissions for GUARDIAN and governance timelocks to call functions on SentinelOracle, UniswapOracle, and PancakeSwapOracle 4. Granting permissions for DeviationSentinel to call required functions on all comptrollers (both isolated pools and core pool) -5. Whitelisting governance timelocks as trusted keepers on DeviationSentinel +5. Whitelisting keeper, GUARDIAN and governance timelocks as trusted keepers on DeviationSentinel #### Description @@ -47,20 +50,20 @@ This VIP configures the DeviationSentinel, SentinelOracle, UniswapOracle, and Pa **Permissions being granted:** -For the keeper address and governance timelocks on DeviationSentinel: +For GUARDIAN and governance timelocks on DeviationSentinel: - setTrustedKeeper(address,bool) - setTokenConfig(address,(uint8,bool)) - setTokenMonitoringEnabled(address,bool) - resetMarketState(address) -For the keeper address on SentinelOracle: +For GUARDIAN and governance timelocks on SentinelOracle: - setTokenOracleConfig(address,address) - setDirectPrice(address,uint256) -For the keeper address on UniswapOracle: +For GUARDIAN and governance timelocks on UniswapOracle: - setPoolConfig(address,address) -For the keeper address on PancakeSwapOracle: +For GUARDIAN and governance timelocks on PancakeSwapOracle: - setPoolConfig(address,address) For DeviationSentinel on any Comptroller: @@ -74,8 +77,7 @@ For DeviationSentinel on any Comptroller: - [DeviationSentinel Contract](https://bscscan.com/address/${DEVIATION_SENTINEL}) - [SentinelOracle Contract](https://bscscan.com/address/${SENTINEL_ORACLE}) - [UniswapOracle Contract](https://bscscan.com/address/${UNISWAP_ORACLE}) -- [PancakeSwapOracle Contract](https://bscscan.com/address/${PANCAKESWAP_ORACLE}) -- [Keeper Address](https://bscscan.com/address/${KEEPER_ADDRESS})`, +- [PancakeSwapOracle Contract](https://bscscan.com/address/${PANCAKESWAP_ORACLE})`, forDescription: "Execute this proposal", againstDescription: "Do not execute this proposal", abstainDescription: "Indifferent to execution", @@ -98,15 +100,15 @@ For DeviationSentinel on any Comptroller: // Grant permissions for DeviationSentinel // ======================================== - // Grant keeper permission to configure token deviation thresholds on DeviationSentinel - { + // Grant GUARDIAN and governance timelocks permission to configure token deviation thresholds on DeviationSentinel + ...[GUARDIAN, ...GOVERNANCE_TIMELOCKS].map((account: string) => ({ target: ACM, signature: "giveCallPermission(address,string,address)", - params: [DEVIATION_SENTINEL, "setTokenConfig(address,(uint8,bool))", KEEPER_ADDRESS], - }, + params: [DEVIATION_SENTINEL, "setTokenConfig(address,(uint8,bool))", account], + })), - // Grant keeper and governance timelocks permissions to manage keepers, monitoring, and market state on DeviationSentinel - ...[KEEPER_ADDRESS, ...GOVERNANCE_TIMELOCKS].flatMap((account: string) => [ + // Grant GUARDIAN and governance timelocks permissions to manage keepers, monitoring, and market state on DeviationSentinel + ...[GUARDIAN, ...GOVERNANCE_TIMELOCKS].flatMap((account: string) => [ { target: ACM, signature: "giveCallPermission(address,string,address)", @@ -124,8 +126,8 @@ For DeviationSentinel on any Comptroller: }, ]), - // Whitelist keeper and governance timelocks as trusted keepers so VIPs can call handleDeviation after parameter changes - ...[KEEPER_ADDRESS, ...GOVERNANCE_TIMELOCKS].flatMap((timelock: string) => ({ + // Whitelist Keeper, GUARDIAN and governance timelocks as trusted keepers so VIPs can call handleDeviation after parameter changes + ...[KEEPER_ADDRESS, GUARDIAN, ...GOVERNANCE_TIMELOCKS].flatMap((timelock: string) => ({ target: DEVIATION_SENTINEL, signature: "setTrustedKeeper(address,bool)", params: [timelock, true], @@ -135,37 +137,37 @@ For DeviationSentinel on any Comptroller: // Grant permissions for SentinelOracle // ======================================== - // Grant keeper permission to configure token-to-oracle mappings on SentinelOracle - { + // Grant GUARDIAN and governance timelocks permission to configure token-to-oracle mappings on SentinelOracle + ...[GUARDIAN, ...GOVERNANCE_TIMELOCKS].map((account: string) => ({ target: ACM, signature: "giveCallPermission(address,string,address)", - params: [SENTINEL_ORACLE, "setTokenOracleConfig(address,address)", KEEPER_ADDRESS], - }, + params: [SENTINEL_ORACLE, "setTokenOracleConfig(address,address)", account], + })), - // Grant keeper permission to set direct prices on SentinelOracle - { + // Grant GUARDIAN and governance timelocks permission to set direct prices on SentinelOracle + ...[GUARDIAN, ...GOVERNANCE_TIMELOCKS].map((account: string) => ({ target: ACM, signature: "giveCallPermission(address,string,address)", - params: [SENTINEL_ORACLE, "setDirectPrice(address,uint256)", KEEPER_ADDRESS], - }, + params: [SENTINEL_ORACLE, "setDirectPrice(address,uint256)", account], + })), // ======================================== // Grant permissions for DEX Oracles // ======================================== - // Grant keeper permission to configure TWAP pool settings on UniswapOracle - { + // Grant GUARDIAN and governance timelocks permission to configure TWAP pool settings on UniswapOracle + ...[GUARDIAN, ...GOVERNANCE_TIMELOCKS].map((account: string) => ({ target: ACM, signature: "giveCallPermission(address,string,address)", - params: [UNISWAP_ORACLE, "setPoolConfig(address,address)", KEEPER_ADDRESS], - }, + params: [UNISWAP_ORACLE, "setPoolConfig(address,address)", account], + })), - // Grant keeper permission to configure TWAP pool settings on PancakeSwapOracle - { + // Grant GUARDIAN and governance timelocks permission to configure TWAP pool settings on PancakeSwapOracle + ...[GUARDIAN, ...GOVERNANCE_TIMELOCKS].map((account: string) => ({ target: ACM, signature: "giveCallPermission(address,string,address)", - params: [PANCAKESWAP_ORACLE, "setPoolConfig(address,address)", KEEPER_ADDRESS], - }, + params: [PANCAKESWAP_ORACLE, "setPoolConfig(address,address)", account], + })), // ======================================== // Grant DeviationSentinel permissions on Comptrollers From 3841d6ba267ac4250c106a87fdd4a293e53aade7 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Wed, 4 Feb 2026 14:33:18 +0530 Subject: [PATCH 3/9] feat: add wrapWithSentinelGuard helper for safe governance commands Utility function to wrap VIP commands affecting markets monitored by DeviationSentinel. Prevents state conflicts when governance modifies collateral factors while Sentinel holds stale values. --- src/DeviationSentinel.ts | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/DeviationSentinel.ts diff --git a/src/DeviationSentinel.ts b/src/DeviationSentinel.ts new file mode 100644 index 000000000..4520353f4 --- /dev/null +++ b/src/DeviationSentinel.ts @@ -0,0 +1,73 @@ +interface ProposalCommand { + target: string; + signature: string; + params: (string | number | boolean | string[] | number[])[]; +} + +/** + * Wraps governance commands for markets monitored by DeviationSentinel with + * the required safety procedure to avoid state conflicts. + * + * When DeviationSentinel detects a price deviation, it stores the original collateral + * factor (CF) and liquidation threshold (LT), sets CF to 0, and pauses borrow or mint. + * If governance modifies CF/LT via a VIP while the Sentinel holds stale values, the + * following failure modes can occur: + * + * - Without resetMarketState: When the deviation resolves, the Sentinel overwrites + * the governance-set CF with the old stored value — silently reverting the VIP's + * risk parameter change. + * + * - With resetMarketState but incomplete cleanup: The Sentinel's internal state is + * cleared so it won't auto-restore or auto-unpause. If governance doesn't manually + * unpause supply/borrow, the market remains paused with no automated recovery. + * + * - E-mode changes: Adding/removing pools or markets from e-mode groups while the + * Sentinel holds stored CFs can cause mismatched pool ID iterations on restore. + * + * This helper generates the correct command sequence to avoid all three failure modes: + * + * 1. resetMarketState(market) — clear stored CF/LT and pause flags + * 2. Unpause borrow and mint in case Sentinel had paused them + * 3. Execute governance changes (CF updates, pause/unpause, e-mode changes) + * 4. handleDeviation(market) — re-evaluate deviation with new parameters and apply + * correct state (pause/CF changes if deviation still exists, or no-op if resolved) + * + * @param deviationSentinel - Address of the DeviationSentinel contract + * @param marketsToTokens - Array of { market, underlyingToken, comptroller } for each affected market + * @param commands - The governance commands to execute between reset and handleDeviation + */ +export const wrapWithSentinelGuard = ( + deviationSentinel: string, + marketsToTokens: { market: string; underlyingToken: string; comptroller: string }[], + commands: ProposalCommand[], +): ProposalCommand[] => { + const preCommands: ProposalCommand[] = marketsToTokens.flatMap(({ market, comptroller }) => [ + // Step 1: Reset market state to clear stored CF/LT and pause flags + { + target: deviationSentinel, + signature: "resetMarketState(address)", + params: [market], + }, + // Step 2: Unpause borrow and mint in case Sentinel had paused them + { + target: comptroller, + signature: "setActionsPaused(address[],uint8[],bool)", + params: [[market], [2], false], // Action.BORROW = 2 + }, + { + target: comptroller, + signature: "setActionsPaused(address[],uint8[],bool)", + params: [[market], [0], false], // Action.MINT = 0 + }, + ]); + + // Step 4: Call handleDeviation so the Sentinel re-evaluates and applies correct state + const postCommands: ProposalCommand[] = marketsToTokens.map(({ market }) => ({ + target: deviationSentinel, + signature: "handleDeviation(address)", + params: [market], + })); + + // Step 3: Governance changes are sandwiched between pre and post commands + return [...preCommands, ...commands, ...postCommands]; +}; From 9435baa0954cf274f9c9c268593f30461d8b7949 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Wed, 4 Feb 2026 16:20:07 +0530 Subject: [PATCH 4/9] feat: add CAKE token configuration to VIP-900 Configure CAKE with PancakeSwap pool for price feeds and set 20% deviation threshold on DeviationSentinel for price monitoring. --- simulations/vip-900/bscmainnet.ts | 17 +++++++++++++++++ vips/vip-900/bscmainnet.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/simulations/vip-900/bscmainnet.ts b/simulations/vip-900/bscmainnet.ts index 6fe8c114a..803a57a93 100644 --- a/simulations/vip-900/bscmainnet.ts +++ b/simulations/vip-900/bscmainnet.ts @@ -8,6 +8,8 @@ import { forking, testVip } from "src/vip-framework"; import vip900, { ACM, + CAKE, + CAKE_PCS_POOL, DEVIATION_SENTINEL, GOVERNANCE_TIMELOCKS, GUARDIAN, @@ -255,5 +257,20 @@ forking(78835203, async () => { ), ).to.equal(true); }); + + // ============================================ + // CAKE token configuration + // ============================================ + + it("CAKE pool should be configured on PancakeSwapOracle", async () => { + const pool = await pancakeSwapOracle.tokenPools(CAKE); + expect(pool).to.equal(CAKE_PCS_POOL); + }); + + it("CAKE deviation threshold should be configured on DeviationSentinel", async () => { + const tokenConfig = await deviationSentinel.tokenConfigs(CAKE); + expect(tokenConfig.deviation).to.equal(20); + expect(tokenConfig.enabled).to.equal(true); + }); }); }); diff --git a/vips/vip-900/bscmainnet.ts b/vips/vip-900/bscmainnet.ts index faf11cda0..e6cb28de0 100644 --- a/vips/vip-900/bscmainnet.ts +++ b/vips/vip-900/bscmainnet.ts @@ -17,6 +17,12 @@ export const GUARDIAN = "0x1C2CAc6ec528c20800B2fe734820D87b581eAA6B"; // Keeper address export const KEEPER_ADDRESS = "0x57fa23f591203f61cef84a7bc892df69ca95c86e"; +// Token addresses +export const CAKE = "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82"; + +// PancakeSwap pool for CAKE +export const CAKE_PCS_POOL = "0x7f51c8AaA6B0599aBd16674e2b17FEc7a9f674A1"; + // Access Control Manager export const ACM = bscmainnet.ACCESS_CONTROL_MANAGER; @@ -39,6 +45,7 @@ This VIP configures the DeviationSentinel, SentinelOracle, UniswapOracle, and Pa 3. Granting permissions for GUARDIAN and governance timelocks to call functions on SentinelOracle, UniswapOracle, and PancakeSwapOracle 4. Granting permissions for DeviationSentinel to call required functions on all comptrollers (both isolated pools and core pool) 5. Whitelisting keeper, GUARDIAN and governance timelocks as trusted keepers on DeviationSentinel +6. Configuring CAKE token with PancakeSwap pool and 20% deviation threshold #### Description @@ -71,6 +78,10 @@ For DeviationSentinel on any Comptroller: - setCollateralFactor(address,uint256,uint256) - for isolated pools - setCollateralFactor(uint96,address,uint256,uint256) - for core pool with emode groups +**CAKE token configuration:** +- PancakeSwap pool: 0x7f51c8AaA6B0599aBd16674e2b17FEc7a9f674A1 +- Deviation threshold: 20% + #### References - [VIP Pull Request](https://github.com/VenusProtocol/vips/pull/658) @@ -202,6 +213,24 @@ For DeviationSentinel on any Comptroller: DEVIATION_SENTINEL, ], }, + + // ======================================== + // Configure CAKE token + // ======================================== + + // Set CAKE pool config on PancakeSwapOracle + { + target: PANCAKESWAP_ORACLE, + signature: "setPoolConfig(address,address)", + params: [CAKE, CAKE_PCS_POOL], + }, + + // Set CAKE deviation threshold (20%) on DeviationSentinel + { + target: DEVIATION_SENTINEL, + signature: "setTokenConfig(address,(uint8,bool))", + params: [CAKE, [20, true]], + }, ], meta, ProposalType.REGULAR, From 65ef2e7017a06e175d333cbcadc23bfd192781d9 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Wed, 4 Feb 2026 19:41:11 +0530 Subject: [PATCH 5/9] feat: configure CAKE token oracle mapping in SentinelOracle Route CAKE price requests to PancakeSwapOracle via SentinelOracle, completing the oracle chain for CAKE price deviation monitoring. --- simulations/vip-900/bscmainnet.ts | 5 +++++ vips/vip-900/bscmainnet.ts | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/simulations/vip-900/bscmainnet.ts b/simulations/vip-900/bscmainnet.ts index 803a57a93..5f848a0e4 100644 --- a/simulations/vip-900/bscmainnet.ts +++ b/simulations/vip-900/bscmainnet.ts @@ -272,5 +272,10 @@ forking(78835203, async () => { expect(tokenConfig.deviation).to.equal(20); expect(tokenConfig.enabled).to.equal(true); }); + + it("Sentinel oracle should have CAKE configured with PancakeSwapOracle", async () => { + const oracleAddress = await sentinelOracle.tokenConfigs(CAKE); + expect(oracleAddress).to.equal(PANCAKESWAP_ORACLE); + }); }); }); diff --git a/vips/vip-900/bscmainnet.ts b/vips/vip-900/bscmainnet.ts index e6cb28de0..1bae4b967 100644 --- a/vips/vip-900/bscmainnet.ts +++ b/vips/vip-900/bscmainnet.ts @@ -231,6 +231,13 @@ For DeviationSentinel on any Comptroller: signature: "setTokenConfig(address,(uint8,bool))", params: [CAKE, [20, true]], }, + + // set config in sentinel oracle + { + target: SENTINEL_ORACLE, + signature: "setTokenOracleConfig(address,address)", + params: [CAKE, PANCAKESWAP_ORACLE], + }, ], meta, ProposalType.REGULAR, From 7ee04811593b5fccb05ee16fd23fa3d5d4798e47 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Thu, 5 Feb 2026 16:26:48 +0530 Subject: [PATCH 6/9] chore: fix minor meta and replace incorrect flatMap with map --- vips/vip-900/bscmainnet.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vips/vip-900/bscmainnet.ts b/vips/vip-900/bscmainnet.ts index 1bae4b967..2b2841637 100644 --- a/vips/vip-900/bscmainnet.ts +++ b/vips/vip-900/bscmainnet.ts @@ -45,7 +45,7 @@ This VIP configures the DeviationSentinel, SentinelOracle, UniswapOracle, and Pa 3. Granting permissions for GUARDIAN and governance timelocks to call functions on SentinelOracle, UniswapOracle, and PancakeSwapOracle 4. Granting permissions for DeviationSentinel to call required functions on all comptrollers (both isolated pools and core pool) 5. Whitelisting keeper, GUARDIAN and governance timelocks as trusted keepers on DeviationSentinel -6. Configuring CAKE token with PancakeSwap pool and 20% deviation threshold +6. Configuring CAKE token with PancakeSwap pool, 20% deviation threshold with monitoring enabled. #### Description @@ -84,7 +84,7 @@ For DeviationSentinel on any Comptroller: #### References -- [VIP Pull Request](https://github.com/VenusProtocol/vips/pull/658) +- [VIP Pull Request](https://github.com/VenusProtocol/vips/pull/666/) - [DeviationSentinel Contract](https://bscscan.com/address/${DEVIATION_SENTINEL}) - [SentinelOracle Contract](https://bscscan.com/address/${SENTINEL_ORACLE}) - [UniswapOracle Contract](https://bscscan.com/address/${UNISWAP_ORACLE}) @@ -138,7 +138,7 @@ For DeviationSentinel on any Comptroller: ]), // Whitelist Keeper, GUARDIAN and governance timelocks as trusted keepers so VIPs can call handleDeviation after parameter changes - ...[KEEPER_ADDRESS, GUARDIAN, ...GOVERNANCE_TIMELOCKS].flatMap((timelock: string) => ({ + ...[KEEPER_ADDRESS, GUARDIAN, ...GOVERNANCE_TIMELOCKS].map((timelock: string) => ({ target: DEVIATION_SENTINEL, signature: "setTrustedKeeper(address,bool)", params: [timelock, true], From 9681e0de46d3fe6e0906d47b9912850c2249e043 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Fri, 6 Feb 2026 15:36:21 +0530 Subject: [PATCH 7/9] fix: scope DeviationSentinel permissions to core pool comptroller only --- simulations/vip-900/bscmainnet.ts | 46 ++++++++++++------------------- vips/vip-900/bscmainnet.ts | 20 +++----------- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/simulations/vip-900/bscmainnet.ts b/simulations/vip-900/bscmainnet.ts index 5f848a0e4..fcabcad6e 100644 --- a/simulations/vip-900/bscmainnet.ts +++ b/simulations/vip-900/bscmainnet.ts @@ -10,6 +10,7 @@ import vip900, { ACM, CAKE, CAKE_PCS_POOL, + CORE_POOL_COMPTROLLER, DEVIATION_SENTINEL, GOVERNANCE_TIMELOCKS, GUARDIAN, @@ -42,6 +43,7 @@ forking(78835203, async () => { let impersonatedSentinelOracle: SignerWithAddress; let impersonatedUniswapOracle: SignerWithAddress; let impersonatedPancakeSwapOracle: SignerWithAddress; + let impersonatedCorePoolComptroller: SignerWithAddress; before(async () => { accessControlManager = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, ACM); @@ -54,6 +56,7 @@ forking(78835203, async () => { impersonatedSentinelOracle = await initMainnetUser(SENTINEL_ORACLE, ethers.utils.parseEther("1")); impersonatedUniswapOracle = await initMainnetUser(UNISWAP_ORACLE, ethers.utils.parseEther("1")); impersonatedPancakeSwapOracle = await initMainnetUser(PANCAKESWAP_ORACLE, ethers.utils.parseEther("1")); + impersonatedCorePoolComptroller = await initMainnetUser(CORE_POOL_COMPTROLLER, ethers.utils.parseEther("1")); }); describe("Pre-VIP behavior", () => { @@ -117,18 +120,14 @@ forking(78835203, async () => { // DeviationSentinel should not have comptroller permissions // ======================================== - it("DeviationSentinel should not have permissions on any comptroller", async () => { + it("DeviationSentinel should not have permissions on core pool comptroller", async () => { + const acm = accessControlManager.connect(impersonatedCorePoolComptroller); + expect(await acm.isAllowedToCall(DEVIATION_SENTINEL, "setActionsPaused(address[],uint8[],bool)")).to.equal(false); + expect(await acm.isAllowedToCall(DEVIATION_SENTINEL, "_setActionsPaused(address[],uint8[],bool)")).to.equal( + false, + ); expect( - await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "setActionsPaused(address[],uint8[],bool)"), - ).to.equal(false); - expect( - await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "setCollateralFactor(address,uint256,uint256)"), - ).to.equal(false); - expect( - await accessControlManager.isAllowedToCall( - DEVIATION_SENTINEL, - "setCollateralFactor(uint96,address,uint256,uint256)", - ), + await acm.isAllowedToCall(DEVIATION_SENTINEL, "setCollateralFactor(uint96,address,uint256,uint256)"), ).to.equal(false); }); }); @@ -234,27 +233,16 @@ forking(78835203, async () => { // DeviationSentinel permissions on Comptrollers // ============================================ - it("DeviationSentinel should have setActionsPaused permission on any comptroller", async () => { - expect( - await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "setActionsPaused(address[],uint8[],bool)"), - ).to.equal(true); - expect( - await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "_setActionsPaused(address[],uint8[],bool)"), - ).to.equal(true); - }); - - it("DeviationSentinel should have setCollateralFactor (isolated) permission on any comptroller", async () => { - expect( - await accessControlManager.isAllowedToCall(DEVIATION_SENTINEL, "setCollateralFactor(address,uint256,uint256)"), - ).to.equal(true); + it("DeviationSentinel should have setActionsPaused permission on core pool comptroller", async () => { + const acm = accessControlManager.connect(impersonatedCorePoolComptroller); + expect(await acm.isAllowedToCall(DEVIATION_SENTINEL, "setActionsPaused(address[],uint8[],bool)")).to.equal(true); + expect(await acm.isAllowedToCall(DEVIATION_SENTINEL, "_setActionsPaused(address[],uint8[],bool)")).to.equal(true); }); - it("DeviationSentinel should have setCollateralFactor (core pool) permission on any comptroller", async () => { + it("DeviationSentinel should have setCollateralFactor (core pool) permission on core pool comptroller", async () => { + const acm = accessControlManager.connect(impersonatedCorePoolComptroller); expect( - await accessControlManager.isAllowedToCall( - DEVIATION_SENTINEL, - "setCollateralFactor(uint96,address,uint256,uint256)", - ), + await acm.isAllowedToCall(DEVIATION_SENTINEL, "setCollateralFactor(uint96,address,uint256,uint256)"), ).to.equal(true); }); diff --git a/vips/vip-900/bscmainnet.ts b/vips/vip-900/bscmainnet.ts index 2b2841637..0aee452ab 100644 --- a/vips/vip-900/bscmainnet.ts +++ b/vips/vip-900/bscmainnet.ts @@ -1,4 +1,3 @@ -import { ethers } from "hardhat"; import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { ProposalType } from "src/types"; import { makeProposal } from "src/utils"; @@ -10,6 +9,7 @@ export const DEVIATION_SENTINEL = "0x6599C15cc8407046CD91E5c0F8B7f765fF914870"; export const SENTINEL_ORACLE = "0x58eae0Cf4215590E19860b66b146C5d539cb6f14"; export const UNISWAP_ORACLE = "0x8FD05458faf220B2324c4BFbb29DBC4B3CF6f23f"; export const PANCAKESWAP_ORACLE = "0x44B72078240A3509979faF450085Fa818401D32E"; +export const CORE_POOL_COMPTROLLER = "0xfD36E2c2a6789Db23113685031d7F16329158384"; // GUARDIAN address export const GUARDIAN = "0x1C2CAc6ec528c20800B2fe734820D87b581eAA6B"; @@ -188,30 +188,18 @@ For DeviationSentinel on any Comptroller: { target: ACM, signature: "giveCallPermission(address,string,address)", - params: [ethers.constants.AddressZero, "setActionsPaused(address[],uint8[],bool)", DEVIATION_SENTINEL], + params: [CORE_POOL_COMPTROLLER, "setActionsPaused(address[],uint8[],bool)", DEVIATION_SENTINEL], }, { target: ACM, signature: "giveCallPermission(address,string,address)", - params: [ethers.constants.AddressZero, "_setActionsPaused(address[],uint8[],bool)", DEVIATION_SENTINEL], + params: [CORE_POOL_COMPTROLLER, "_setActionsPaused(address[],uint8[],bool)", DEVIATION_SENTINEL], }, - - // Grant DeviationSentinel permission to set collateral factor on isolated pool comptrollers - { - target: ACM, - signature: "giveCallPermission(address,string,address)", - params: [ethers.constants.AddressZero, "setCollateralFactor(address,uint256,uint256)", DEVIATION_SENTINEL], - }, - // Grant DeviationSentinel permission to set collateral factor on core pool comptroller (with emode poolId) { target: ACM, signature: "giveCallPermission(address,string,address)", - params: [ - ethers.constants.AddressZero, - "setCollateralFactor(uint96,address,uint256,uint256)", - DEVIATION_SENTINEL, - ], + params: [CORE_POOL_COMPTROLLER, "setCollateralFactor(uint96,address,uint256,uint256)", DEVIATION_SENTINEL], }, // ======================================== From da7a3beadcd47cc3735c4ff6c120b2e4fada482f Mon Sep 17 00:00:00 2001 From: fred-venus Date: Mon, 9 Feb 2026 11:22:34 +0800 Subject: [PATCH 8/9] feat: update the vip content and title --- .../abi/AccessControlManager.json | 0 .../abi/DeviationSentinel.json | 0 .../{vip-900 => vip-590}/abi/DexOracle.json | 0 .../{vip-900 => vip-590}/abi/ERC20.json | 0 .../abi/ResilientOracle.json | 0 .../abi/SentinelOracle.json | 0 .../{vip-900 => vip-590}/abi/comptroller.json | 0 .../{vip-900 => vip-590}/bscmainnet.ts | 6 +- .../bsctestnet-addendum-2.ts | 0 .../bsctestnet-addendum.ts | 0 .../{vip-900 => vip-590}/bsctestnet.ts | 0 vips/{vip-900 => vip-590}/bscmainnet.ts | 59 +++++++------------ .../bsctestnet-addendum-2.ts | 0 .../bsctestnet-addendum.ts | 0 vips/{vip-900 => vip-590}/bsctestnet.ts | 0 15 files changed, 24 insertions(+), 41 deletions(-) rename simulations/{vip-900 => vip-590}/abi/AccessControlManager.json (100%) rename simulations/{vip-900 => vip-590}/abi/DeviationSentinel.json (100%) rename simulations/{vip-900 => vip-590}/abi/DexOracle.json (100%) rename simulations/{vip-900 => vip-590}/abi/ERC20.json (100%) rename simulations/{vip-900 => vip-590}/abi/ResilientOracle.json (100%) rename simulations/{vip-900 => vip-590}/abi/SentinelOracle.json (100%) rename simulations/{vip-900 => vip-590}/abi/comptroller.json (100%) rename simulations/{vip-900 => vip-590}/bscmainnet.ts (99%) rename simulations/{vip-900 => vip-590}/bsctestnet-addendum-2.ts (100%) rename simulations/{vip-900 => vip-590}/bsctestnet-addendum.ts (100%) rename simulations/{vip-900 => vip-590}/bsctestnet.ts (100%) rename vips/{vip-900 => vip-590}/bscmainnet.ts (75%) rename vips/{vip-900 => vip-590}/bsctestnet-addendum-2.ts (100%) rename vips/{vip-900 => vip-590}/bsctestnet-addendum.ts (100%) rename vips/{vip-900 => vip-590}/bsctestnet.ts (100%) diff --git a/simulations/vip-900/abi/AccessControlManager.json b/simulations/vip-590/abi/AccessControlManager.json similarity index 100% rename from simulations/vip-900/abi/AccessControlManager.json rename to simulations/vip-590/abi/AccessControlManager.json diff --git a/simulations/vip-900/abi/DeviationSentinel.json b/simulations/vip-590/abi/DeviationSentinel.json similarity index 100% rename from simulations/vip-900/abi/DeviationSentinel.json rename to simulations/vip-590/abi/DeviationSentinel.json diff --git a/simulations/vip-900/abi/DexOracle.json b/simulations/vip-590/abi/DexOracle.json similarity index 100% rename from simulations/vip-900/abi/DexOracle.json rename to simulations/vip-590/abi/DexOracle.json diff --git a/simulations/vip-900/abi/ERC20.json b/simulations/vip-590/abi/ERC20.json similarity index 100% rename from simulations/vip-900/abi/ERC20.json rename to simulations/vip-590/abi/ERC20.json diff --git a/simulations/vip-900/abi/ResilientOracle.json b/simulations/vip-590/abi/ResilientOracle.json similarity index 100% rename from simulations/vip-900/abi/ResilientOracle.json rename to simulations/vip-590/abi/ResilientOracle.json diff --git a/simulations/vip-900/abi/SentinelOracle.json b/simulations/vip-590/abi/SentinelOracle.json similarity index 100% rename from simulations/vip-900/abi/SentinelOracle.json rename to simulations/vip-590/abi/SentinelOracle.json diff --git a/simulations/vip-900/abi/comptroller.json b/simulations/vip-590/abi/comptroller.json similarity index 100% rename from simulations/vip-900/abi/comptroller.json rename to simulations/vip-590/abi/comptroller.json diff --git a/simulations/vip-900/bscmainnet.ts b/simulations/vip-590/bscmainnet.ts similarity index 99% rename from simulations/vip-900/bscmainnet.ts rename to simulations/vip-590/bscmainnet.ts index fcabcad6e..7b4224d87 100644 --- a/simulations/vip-900/bscmainnet.ts +++ b/simulations/vip-590/bscmainnet.ts @@ -6,7 +6,7 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents, initMainnetUser } from "src/utils"; import { forking, testVip } from "src/vip-framework"; -import vip900, { +import vip590, { ACM, CAKE, CAKE_PCS_POOL, @@ -18,7 +18,7 @@ import vip900, { PANCAKESWAP_ORACLE, SENTINEL_ORACLE, UNISWAP_ORACLE, -} from "../../vips/vip-900/bscmainnet"; +} from "../../vips/vip-590/bscmainnet"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; import DEVIATION_SENTINEL_ABI from "./abi/DeviationSentinel.json"; import DEX_ORACLE_ABI from "./abi/DexOracle.json"; @@ -132,7 +132,7 @@ forking(78835203, async () => { }); }); - testVip("VIP-900", await vip900(), { + testVip("VIP-590", await vip590(), { callbackAfterExecution: async txResponse => { // 4 contracts accept ownership await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["OwnershipTransferred"], [4]); diff --git a/simulations/vip-900/bsctestnet-addendum-2.ts b/simulations/vip-590/bsctestnet-addendum-2.ts similarity index 100% rename from simulations/vip-900/bsctestnet-addendum-2.ts rename to simulations/vip-590/bsctestnet-addendum-2.ts diff --git a/simulations/vip-900/bsctestnet-addendum.ts b/simulations/vip-590/bsctestnet-addendum.ts similarity index 100% rename from simulations/vip-900/bsctestnet-addendum.ts rename to simulations/vip-590/bsctestnet-addendum.ts diff --git a/simulations/vip-900/bsctestnet.ts b/simulations/vip-590/bsctestnet.ts similarity index 100% rename from simulations/vip-900/bsctestnet.ts rename to simulations/vip-590/bsctestnet.ts diff --git a/vips/vip-900/bscmainnet.ts b/vips/vip-590/bscmainnet.ts similarity index 75% rename from vips/vip-900/bscmainnet.ts rename to vips/vip-590/bscmainnet.ts index 0aee452ab..37c8af64b 100644 --- a/vips/vip-900/bscmainnet.ts +++ b/vips/vip-590/bscmainnet.ts @@ -32,55 +32,38 @@ export const GOVERNANCE_TIMELOCKS = [ bscmainnet.CRITICAL_TIMELOCK, ]; -export const vip900 = () => { +export const vip590 = () => { const meta = { version: "v2", - title: "VIP-900 Configure DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle on BSC Mainnet", - description: `#### Summary + title: "VIP-590 [BNB Chain] Enable Emergency Brake in Venus Core", + description: `## Summary -This VIP configures the DeviationSentinel, SentinelOracle, UniswapOracle, and PancakeSwapOracle contracts on BSC Mainnet by: +This VIP will enable **Emergency Brake** function in Venus core through configuring **DeviationSentinel**, **SentinelOracle**, **UniswapOracle**, and **PancakeSwapOracle** on BNB Chain mainnet. The goal is to enable automated deviation monitoring, trusted keeper operations, and oracle configuration while ensuring governance retains full control. -1. Accepting ownership of all four contracts -2. Granting permissions for GUARDIAN and governance timelocks to call functions on DeviationSentinel -3. Granting permissions for GUARDIAN and governance timelocks to call functions on SentinelOracle, UniswapOracle, and PancakeSwapOracle -4. Granting permissions for DeviationSentinel to call required functions on all comptrollers (both isolated pools and core pool) -5. Whitelisting keeper, GUARDIAN and governance timelocks as trusted keepers on DeviationSentinel -6. Configuring CAKE token with PancakeSwap pool, 20% deviation threshold with monitoring enabled. +If approved, this VIP will: -#### Description +- Governance accept ownership of all four contracts +- Grant keeper and governance timelocks the required permissions on DeviationSentinel +- Grant keeper permissions on SentinelOracle and DEX oracles +- Allow DeviationSentinel to pause actions and adjust collateral factors across comptrollers +- Whitelist governance timelocks as trusted keepers +- Enable Emergency Brake for $CAKE with PancakeSwap pool, 20% deviation threshold -**DeviationSentinel** monitors price deviations between the ResilientOracle and SentinelOracle. When significant deviations are detected, it can pause specific market actions (borrow, mint) and adjust collateral factors to protect the protocol. +## What This VIP Enables -**SentinelOracle** is an aggregator oracle that routes price requests to appropriate DEX oracles and supports direct price overrides. +**DeviationSentinel** -**UniswapOracle** and **PancakeSwapOracle** are DEX-based oracles that provide TWAP prices from Uniswap V3 and PancakeSwap V3 pools respectively. +- Monitors price deviations between ResilientOracle and SentinelOracle +- Can pause mint/borrow actions and adjust CFs when deviations exceed thresholds -**Permissions being granted:** +**SentinelOracle** -For GUARDIAN and governance timelocks on DeviationSentinel: -- setTrustedKeeper(address,bool) -- setTokenConfig(address,(uint8,bool)) -- setTokenMonitoringEnabled(address,bool) -- resetMarketState(address) +- Routes price queries to DEX oracles +- Supports direct price overrides (keeper-set) -For GUARDIAN and governance timelocks on SentinelOracle: -- setTokenOracleConfig(address,address) -- setDirectPrice(address,uint256) +**UniswapOracle / PancakeSwapOracle** -For GUARDIAN and governance timelocks on UniswapOracle: -- setPoolConfig(address,address) - -For GUARDIAN and governance timelocks on PancakeSwapOracle: -- setPoolConfig(address,address) - -For DeviationSentinel on any Comptroller: -- setActionsPaused(address[],uint8[],bool) - to pause/unpause borrow and mint actions -- setCollateralFactor(address,uint256,uint256) - for isolated pools -- setCollateralFactor(uint96,address,uint256,uint256) - for core pool with emode groups - -**CAKE token configuration:** -- PancakeSwap pool: 0x7f51c8AaA6B0599aBd16674e2b17FEc7a9f674A1 -- Deviation threshold: 20% +- Provide TWAP prices from Uniswap V3 / PancakeSwap V3 pools #### References @@ -232,4 +215,4 @@ For DeviationSentinel on any Comptroller: ); }; -export default vip900; +export default vip590; diff --git a/vips/vip-900/bsctestnet-addendum-2.ts b/vips/vip-590/bsctestnet-addendum-2.ts similarity index 100% rename from vips/vip-900/bsctestnet-addendum-2.ts rename to vips/vip-590/bsctestnet-addendum-2.ts diff --git a/vips/vip-900/bsctestnet-addendum.ts b/vips/vip-590/bsctestnet-addendum.ts similarity index 100% rename from vips/vip-900/bsctestnet-addendum.ts rename to vips/vip-590/bsctestnet-addendum.ts diff --git a/vips/vip-900/bsctestnet.ts b/vips/vip-590/bsctestnet.ts similarity index 100% rename from vips/vip-900/bsctestnet.ts rename to vips/vip-590/bsctestnet.ts From fd3fe1c408517450cbd1c43a2dbadc246af24c14 Mon Sep 17 00:00:00 2001 From: fred-venus Date: Mon, 9 Feb 2026 11:38:53 +0800 Subject: [PATCH 9/9] style: prettier --- simulations/vip-590/bsctestnet-addendum-2.ts | 6 +++--- simulations/vip-590/bsctestnet-addendum.ts | 6 +++--- simulations/vip-590/bsctestnet.ts | 6 +++--- vips/vip-590/bsctestnet-addendum-2.ts | 6 +++--- vips/vip-590/bsctestnet-addendum.ts | 10 +++++----- vips/vip-590/bsctestnet.ts | 6 +++--- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/simulations/vip-590/bsctestnet-addendum-2.ts b/simulations/vip-590/bsctestnet-addendum-2.ts index a07a6177e..d4c52aff6 100644 --- a/simulations/vip-590/bsctestnet-addendum-2.ts +++ b/simulations/vip-590/bsctestnet-addendum-2.ts @@ -11,8 +11,8 @@ import { NEW_CF, VETH_CORE, VWBNB_CORE, - vip900TestnetAddendum2, -} from "../../vips/vip-900/bsctestnet-addendum-2"; + vip590TestnetAddendum2, +} from "../../vips/vip-590/bsctestnet-addendum-2"; import ERC20_ABI from "./abi/ERC20.json"; import RESILIENT_ORACLE_ABI from "./abi/ResilientOracle.json"; import COMPTROLLER_ABI from "./abi/comptroller.json"; @@ -88,7 +88,7 @@ forking(84038082, async () => { }); }); - testVip("VIP-900 Addendum 2: Unpause Mint and Update CF", await vip900TestnetAddendum2(), { + testVip("VIP-590 Addendum 2: Unpause Mint and Update CF", await vip590TestnetAddendum2(), { callbackAfterExecution: async txResponse => { await expectEvents(txResponse, [COMPTROLLER_ABI], ["ActionPausedMarket", "NewCollateralFactor"], [8, 2]); }, diff --git a/simulations/vip-590/bsctestnet-addendum.ts b/simulations/vip-590/bsctestnet-addendum.ts index f24554c5b..46e7099cb 100644 --- a/simulations/vip-590/bsctestnet-addendum.ts +++ b/simulations/vip-590/bsctestnet-addendum.ts @@ -4,10 +4,10 @@ import { ethers } from "hardhat"; import { expectEvents } from "src/utils"; import { forking, testVip } from "src/vip-framework"; -import { ACM, DEVIATION_SENTINEL, vip900TestnetAddendum } from "../../vips/vip-900/bsctestnet-addendum"; +import { ACM, DEVIATION_SENTINEL, vip590TestnetAddendum } from "../../vips/vip-590/bsctestnet-addendum"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; -forking(82830213, async () => { +forking(80138518, async () => { let accessControlManager: Contract; before(async () => { @@ -26,7 +26,7 @@ forking(82830213, async () => { }); }); - testVip("VIP-900 Addendum: Grant _setActionsPaused permission", await vip900TestnetAddendum(), { + testVip("VIP-590 Addendum: Grant _setActionsPaused permission", await vip590TestnetAddendum(), { callbackAfterExecution: async txResponse => { await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [1]); }, diff --git a/simulations/vip-590/bsctestnet.ts b/simulations/vip-590/bsctestnet.ts index 5fcc7490a..a30ad80df 100644 --- a/simulations/vip-590/bsctestnet.ts +++ b/simulations/vip-590/bsctestnet.ts @@ -5,12 +5,12 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents } from "src/utils"; import { forking, testVip } from "src/vip-framework"; -import { ACM, DEVIATION_SENTINEL, KEEPER_ADDRESS, SENTINEL_ORACLE, vip900Testnet } from "../../vips/vip-900/bsctestnet"; +import { ACM, DEVIATION_SENTINEL, KEEPER_ADDRESS, SENTINEL_ORACLE, vip590Testnet } from "../../vips/vip-590/bsctestnet"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; import DEVIATION_SENTINEL_ABI from "./abi/DeviationSentinel.json"; import SENTINEL_ORACLE_ABI from "./abi/SentinelOracle.json"; -forking(82830213, async () => { +forking(80138518, async () => { let accessControlManager: Contract; let deviationSentinel: Contract; let sentinelOracle: Contract; @@ -91,7 +91,7 @@ forking(82830213, async () => { }); }); - testVip("VIP-900 Configure DeviationSentinel and SentinelOracle", await vip900Testnet(), { + testVip("VIP-590 Configure DeviationSentinel and SentinelOracle", await vip590Testnet(), { callbackAfterExecution: async txResponse => { await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["OwnershipTransferred"], [2]); await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["PermissionGranted"], [9]); diff --git a/vips/vip-590/bsctestnet-addendum-2.ts b/vips/vip-590/bsctestnet-addendum-2.ts index 0fe740b03..629d75127 100644 --- a/vips/vip-590/bsctestnet-addendum-2.ts +++ b/vips/vip-590/bsctestnet-addendum-2.ts @@ -14,10 +14,10 @@ const Action = { export const NEW_CF = "800000000000000000"; export const LT = "800000000000000000"; -export const vip900TestnetAddendum2 = () => { +export const vip590TestnetAddendum2 = () => { const meta = { version: "v2", - title: "VIP-900 Addendum 2: Unpause Mint and Update CF for vETH_Core and vWBNB_Core on BSC Testnet", + title: "VIP-590 Addendum 2: Unpause Mint and Update CF for vETH_Core and vWBNB_Core on BSC Testnet", description: ``, forDescription: "Execute this proposal", againstDescription: "Do not execute this proposal", @@ -55,4 +55,4 @@ export const vip900TestnetAddendum2 = () => { ); }; -export default vip900TestnetAddendum2; +export default vip590TestnetAddendum2; diff --git a/vips/vip-590/bsctestnet-addendum.ts b/vips/vip-590/bsctestnet-addendum.ts index 29cbf4bd1..a87398199 100644 --- a/vips/vip-590/bsctestnet-addendum.ts +++ b/vips/vip-590/bsctestnet-addendum.ts @@ -8,17 +8,17 @@ export const DEVIATION_SENTINEL = "0x9245d72712548707809D66848e63B8E2B169F3c1"; // Access Control Manager export const ACM = "0x45f8a08F534f34A97187626E05d4b6648Eeaa9AA"; -export const vip900TestnetAddendum = () => { +export const vip590TestnetAddendum = () => { const meta = { version: "v2", - title: "VIP-900 Addendum: Grant _setActionsPaused permission to DeviationSentinel on BSC Testnet", + title: "VIP-590 Addendum: Grant _setActionsPaused permission to DeviationSentinel on BSC Testnet", description: `#### Summary -This addendum to VIP-900 grants the missing \`_setActionsPaused(address[],uint8[],bool)\` permission to the DeviationSentinel contract on BSC Testnet. +This addendum to VIP-590 grants the missing \`_setActionsPaused(address[],uint8[],bool)\` permission to the DeviationSentinel contract on BSC Testnet. #### Description -The original VIP-900 granted the \`setActionsPaused(address[],uint8[],bool)\` permission but missed the underscore-prefixed version \`_setActionsPaused(address[],uint8[],bool)\` which is the actual internal function signature used by comptrollers. +The original VIP-590 granted the \`setActionsPaused(address[],uint8[],bool)\` permission but missed the underscore-prefixed version \`_setActionsPaused(address[],uint8[],bool)\` which is the actual internal function signature used by comptrollers. This addendum grants: - \`_setActionsPaused(address[],uint8[],bool)\` permission to DeviationSentinel on any comptroller (address zero pattern) @@ -47,4 +47,4 @@ This allows DeviationSentinel to properly pause/unpause market actions when pric ); }; -export default vip900TestnetAddendum; +export default vip590TestnetAddendum; diff --git a/vips/vip-590/bsctestnet.ts b/vips/vip-590/bsctestnet.ts index f9bb6f86e..2a626d515 100644 --- a/vips/vip-590/bsctestnet.ts +++ b/vips/vip-590/bsctestnet.ts @@ -12,10 +12,10 @@ export const ACM = "0x45f8a08F534f34A97187626E05d4b6648Eeaa9AA"; // Keeper address that can call functions in the contracts export const KEEPER_ADDRESS = "0x2Ce1d0ffD7E869D9DF33e28552b12DdDed326706"; -export const vip900Testnet = () => { +export const vip590Testnet = () => { const meta = { version: "v2", - title: "VIP-900 Configure DeviationSentinel and SentinelOracle on BSC Testnet", + title: "VIP-590 Configure DeviationSentinel and SentinelOracle on BSC Testnet", description: `#### Summary This VIP configures the DeviationSentinel and SentinelOracle contracts on BSC Testnet by: @@ -154,4 +154,4 @@ For DeviationSentinel on any Comptroller: ); }; -export default vip900Testnet; +export default vip590Testnet;