diff --git a/simulations/vip-616/abi/AccessControlManager.json b/simulations/vip-616/abi/AccessControlManager.json new file mode 100644 index 000000000..4a118fcc4 --- /dev/null +++ b/simulations/vip-616/abi/AccessControlManager.json @@ -0,0 +1,360 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "functionSig", + "type": "string" + } + ], + "name": "PermissionGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "functionSig", + "type": "string" + } + ], + "name": "PermissionRevoked", + "type": "event" + }, + { + "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": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + } + ], + "name": "hasPermission", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "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-616/abi/AerodromeSlipstreamOracle.json b/simulations/vip-616/abi/AerodromeSlipstreamOracle.json new file mode 100644 index 000000000..8c682078e --- /dev/null +++ b/simulations/vip-616/abi/AerodromeSlipstreamOracle.json @@ -0,0 +1,419 @@ +[ + { + "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": [], + "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" + }, + { + "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-616/abi/CurveOracle.json b/simulations/vip-616/abi/CurveOracle.json new file mode 100644 index 000000000..00e518859 --- /dev/null +++ b/simulations/vip-616/abi/CurveOracle.json @@ -0,0 +1,488 @@ +[ + { + "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": [], + "name": "AssetMismatch", + "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" + }, + { + "inputs": [], + "name": "ZeroPrice", + "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" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "coinIndex", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "refCoinIndex", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address", + "name": "referenceToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "assetDecimals", + "type": "uint8" + } + ], + "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": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "poolConfigs", + "outputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint8", + "name": "coinIndex", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "refCoinIndex", + "type": "uint8" + }, + { + "internalType": "address", + "name": "referenceToken", + "type": "address" + }, + { + "internalType": "uint8", + "name": "assetDecimals", + "type": "uint8" + } + ], + "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" + }, + { + "internalType": "uint8", + "name": "coinIndex", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "refCoinIndex", + "type": "uint8" + }, + { + "internalType": "address", + "name": "referenceToken", + "type": "address" + }, + { + "internalType": "uint8", + "name": "assetDecimals", + "type": "uint8" + } + ], + "name": "setPoolConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "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-616/abi/DeviationSentinel.json b/simulations/vip-616/abi/DeviationSentinel.json new file mode 100644 index 000000000..c12ea017a --- /dev/null +++ b/simulations/vip-616/abi/DeviationSentinel.json @@ -0,0 +1,589 @@ +[ + { + "inputs": [ + { + "internalType": "contract IEBrake", + "name": "eBrake_", + "type": "address" + }, + { + "internalType": "contract ResilientOracleInterface", + "name": "resilientOracle_", + "type": "address" + }, + { + "internalType": "contract OracleInterface", + "name": "sentinelOracle_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "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": 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": "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": "EBRAKE", + "outputs": [ + { + "internalType": "contract IEBrake", + "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-616/abi/EBrake.json b/simulations/vip-616/abi/EBrake.json new file mode 100644 index 000000000..c7aedf09d --- /dev/null +++ b/simulations/vip-616/abi/EBrake.json @@ -0,0 +1,683 @@ +[ + { + "inputs": [ + { + "internalType": "contract ICorePoolComptroller", + "name": "corePoolComptroller_", + "type": "address" + }, + { + "internalType": "bool", + "name": "isIsolatedPool_", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "ArrayLengthMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "currentCap", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requestedCap", + "type": "uint256" + } + ], + "name": "CapExceedsCurrent", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyArray", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum IComptroller.Action", + "name": "action", + "type": "uint8" + } + ], + "name": "ForbiddenAction", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + }, + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "MarketNotListed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "errorCode", + "type": "uint256" + } + ], + "name": "SetCollateralFactorFailed", + "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": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum IComptroller.Action", + "name": "action", + "type": "uint8" + } + ], + "name": "ActionPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "markets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "enum IComptroller.Action[]", + "name": "actions", + "type": "uint8[]" + } + ], + "name": "ActionsPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "markets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "newBorrowCaps", + "type": "uint256[]" + } + ], + "name": "BorrowCapsDecreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + } + ], + "name": "CollateralFactorZeroed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "FlashLoanPaused", + "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": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "markets", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "newSupplyCaps", + "type": "uint256[]" + } + ], + "name": "SupplyCapsDecreased", + "type": "event" + }, + { + "inputs": [], + "name": "COMPTROLLER", + "outputs": [ + { + "internalType": "contract ICorePoolComptroller", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "IS_ISOLATED_POOL", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "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": "market", + "type": "address" + }, + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + } + ], + "name": "getMarketCFSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "cf", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lt", + "type": "uint256" + } + ], + "stateMutability": "view", + "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": "uint256", + "name": "borrowCap", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "supplyCap", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "borrowCapSnapshotted", + "type": "bool" + }, + { + "internalType": "bool", + "name": "supplyCapSnapshotted", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "markets", + "type": "address[]" + }, + { + "internalType": "enum IComptroller.Action[]", + "name": "actions", + "type": "uint8[]" + } + ], + "name": "pauseActions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "pauseBorrow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pauseFlashLoan", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "pauseRedeem", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "pauseSupply", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "pauseTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "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": "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": "market", + "type": "address" + } + ], + "name": "setCFZero", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint96", + "name": "poolId", + "type": "uint96" + } + ], + "name": "setCFZero", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "markets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newBorrowCaps", + "type": "uint256[]" + } + ], + "name": "setMarketBorrowCaps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "markets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newSupplyCaps", + "type": "uint256[]" + } + ], + "name": "setMarketSupplyCaps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/simulations/vip-616/abi/ILComptroller.json b/simulations/vip-616/abi/ILComptroller.json new file mode 100644 index 000000000..d1801efd8 --- /dev/null +++ b/simulations/vip-616/abi/ILComptroller.json @@ -0,0 +1,2121 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "poolRegistry_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "enum Action", + "name": "action", + "type": "uint8" + } + ], + "name": "ActionPaused", + "type": "error" + }, + { + "inputs": [], + "name": "BorrowActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "BorrowCapExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "BorrowCapIsNotZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expectedLessThanOrEqualTo", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "CollateralExceedsThreshold", + "type": "error" + }, + { + "inputs": [], + "name": "CollateralFactorIsNotZero", + "type": "error" + }, + { + "inputs": [], + "name": "ComptrollerMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "DelegationStatusUnchanged", + "type": "error" + }, + { + "inputs": [], + "name": "EnterMarketActionNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "ExitMarketActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "collateralToSeize", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availableCollateral", + "type": "uint256" + } + ], + "name": "InsufficientCollateral", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientLiquidity", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientShortfall", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidCollateralFactor", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidLiquidationThreshold", + "type": "error" + }, + { + "inputs": [], + "name": "LiquidateActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "MarketAlreadyListed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "MarketNotCollateral", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "MarketNotListed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "loopsLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requiredLoops", + "type": "uint256" + } + ], + "name": "MaxLoopsLimitExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expectedGreaterThan", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "MinimalCollateralViolated", + "type": "error" + }, + { + "inputs": [], + "name": "MintActionNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "NonzeroBorrowBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "PriceError", + "type": "error" + }, + { + "inputs": [], + "name": "RedeemActionNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "RepayActionNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "SeizeActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "SnapshotError", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "SupplyCapExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "SupplyCapIsNotZero", + "type": "error" + }, + { + "inputs": [], + "name": "TooMuchRepay", + "type": "error" + }, + { + "inputs": [], + "name": "TransferActionNotPaused", + "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": [ + { + "internalType": "address", + "name": "expectedSender", + "type": "address" + }, + { + "internalType": "address", + "name": "actualSender", + "type": "address" + } + ], + "name": "UnexpectedSender", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum Action", + "name": "action", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bool", + "name": "pauseState", + "type": "bool" + } + ], + "name": "ActionPausedMarket", + "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": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "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": false, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "MarketSupported", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "MarketUnlisted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldMaxLoopsLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newmaxLoopsLimit", + "type": "uint256" + } + ], + "name": "MaxLoopsLimitUpdated", + "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": "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": false, + "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": "uint256", + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "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": "uint256", + "name": "oldMinLiquidatableCollateral", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMinLiquidatableCollateral", + "type": "uint256" + } + ], + "name": "NewMinLiquidatableCollateral", + "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": "address", + "name": "rewardsDistributor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "rewardToken", + "type": "address" + } + ], + "name": "NewRewardsDistributor", + "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": 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" + }, + { + "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" + }, + { + "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": "contract RewardsDistributor", + "name": "_rewardsDistributor", + "type": "address" + } + ], + "name": "addRewardsDistributor", + "outputs": [], + "stateMutability": "nonpayable", + "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": "", + "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": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "vTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "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": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "shortfall", + "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": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "shortfall", + "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": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "shortfall", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRewardDistributors", + "outputs": [ + { + "internalType": "contract RewardsDistributor[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "getRewardsByMarket", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "rewardToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "supplySpeed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowSpeed", + "type": "uint256" + } + ], + "internalType": "struct ComptrollerStorage.RewardSpeeds[]", + "name": "rewardSpeeds", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "healAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "loopLimit", + "type": "uint256" + }, + { + "internalType": "address", + "name": "accessControlManager", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "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": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "isMarketListed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract VToken", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "contract VToken", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "internalType": "struct ComptrollerStorage.LiquidationOrder[]", + "name": "orders", + "type": "tuple[]" + } + ], + "name": "liquidateAccount", + "outputs": [], + "stateMutability": "nonpayable", + "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": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokensToSeize", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "internalType": "bool", + "name": "isListed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "collateralFactorMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationThresholdMantissa", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLoopsLimit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minLiquidatableCollateral", + "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": "actualMintAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "oracle", + "outputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "", + "type": "address" + } + ], + "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": "poolRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "preBorrowHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "skipLiquidityCheck", + "type": "bool" + } + ], + "name": "preLiquidateHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "preMintHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "preRedeemHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + } + ], + "name": "preRepayHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "seizerContract", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + } + ], + "name": "preSeizeHook", + "outputs": [], + "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": "preTransferHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "prime", + "outputs": [ + { + "internalType": "contract IPrime", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "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": "renounceOwnership", + "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": "actualRepayAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "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": "accessControlManager_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "marketsList", + "type": "address[]" + }, + { + "internalType": "enum Action[]", + "name": "actionsList", + "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": [], + "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": [], + "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": "uint256", + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "setLiquidationIncentive", + "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": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "setMaxLoopsLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMinLiquidatableCollateral", + "type": "uint256" + } + ], + "name": "setMinLiquidatableCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "newOracle", + "type": "address" + } + ], + "name": "setPriceOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IPrime", + "name": "_prime", + "type": "address" + } + ], + "name": "setPrimeToken", + "outputs": [], + "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": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "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": [ + { + "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": "account", + "type": "address" + } + ], + "name": "updatePrices", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/simulations/vip-616/abi/ResilientOracle.json b/simulations/vip-616/abi/ResilientOracle.json new file mode 100644 index 000000000..35f52caa0 --- /dev/null +++ b/simulations/vip-616/abi/ResilientOracle.json @@ -0,0 +1,640 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "nativeMarketAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "vaiAddress", + "type": "address" + }, + { + "internalType": "contract BoundValidatorInterface", + "name": "_boundValidator", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "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": "INVALID_PRICE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NATIVE_TOKEN_ADDR", + "outputs": [ + { + "internalType": "address", + "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": [], + "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": "nativeMarket", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "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": "vai", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-616/abi/SentinelOracle.json b/simulations/vip-616/abi/SentinelOracle.json new file mode 100644 index 000000000..7c9930f95 --- /dev/null +++ b/simulations/vip-616/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-616/abi/UniswapOracle.json b/simulations/vip-616/abi/UniswapOracle.json new file mode 100644 index 000000000..66770c861 --- /dev/null +++ b/simulations/vip-616/abi/UniswapOracle.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-616/abi/VToken.json b/simulations/vip-616/abi/VToken.json new file mode 100644 index 000000000..9a13ff711 --- /dev/null +++ b/simulations/vip-616/abi/VToken.json @@ -0,0 +1,1691 @@ +[ + { + "inputs": [], + "name": "FlashLoanAlreadyActive", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFee", + "type": "uint256" + } + ], + "name": "FlashLoanFeeTooHigh", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFee", + "type": "uint256" + } + ], + "name": "FlashLoanProtocolShareTooHigh", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientCash", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requiredTotalFee", + "type": "uint256" + } + ], + "name": "InsufficientRepayment", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidComptroller", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "cashPrior", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "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": false, + "internalType": "uint256", + "name": "oldFlashLoanFeeMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newFlashLoanFeeMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldFlashLoanProtocolShare", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newFlashLoanProtocolShare", + "type": "uint256" + } + ], + "name": "FlashLoanFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "previousStatus", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "newStatus", + "type": "bool" + } + ], + "name": "FlashLoanStatusChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mintTokens", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mintTokens", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + } + ], + "name": "MintBehalf", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlAddress", + "type": "address" + } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract ComptrollerInterface", + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract ComptrollerInterface", + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract InterestRateModelV8", + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract InterestRateModelV8", + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldProtocolShareReserve", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newProtocolShareReserve", + "type": "address" + } + ], + "name": "NewProtocolShareReserve", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldReduceReservesBlockDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newReduceReservesBlockDelta", + "type": "uint256" + } + ], + "name": "NewReduceReservesBlockDelta", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "RedeemFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "benefactor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "addAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "protocolShareReserve", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "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": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "protocolFee", + "type": "uint256" + } + ], + "name": "TransferInUnderlyingFlashLoan", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TransferOutUnderlyingFlashLoan", + "type": "event" + }, + { + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "reduceAmount_", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ComptrollerInterface", + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract InterestRateModelV8", + "name": "newInterestRateModel_", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newReserveFactorMantissa_", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "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": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "calculateFlashLoanFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "internalType": "contract ComptrollerInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "flashLoanAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "flashLoanDebtPosition", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "flashLoanFeeMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "flashLoanProtocolShareMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ComptrollerInterface", + "name": "comptroller_", + "type": "address" + }, + { + "internalType": "contract InterestRateModelV8", + "name": "interestRateModel_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "internalType": "contract InterestRateModelV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isFlashLoanEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isVToken", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "protocolShareReserve", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "reduceReservesBlockDelta", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "reduceReservesBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAccessControlManagerAddress", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + } + ], + "name": "setFlashLoanEnabled", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "flashLoanFeeMantissa_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "flashLoanProtocolShare_", + "type": "uint256" + } + ], + "name": "setFlashLoanFeeMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "protcolShareReserve_", + "type": "address" + } + ], + "name": "setProtocolShareReserve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newReduceReservesBlockDelta_", + "type": "uint256" + } + ], + "name": "setReduceReservesBlockDelta", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repaymentAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "protocolFee", + "type": "uint256" + } + ], + "name": "transferInUnderlyingFlashLoan", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferOutUnderlyingFlashLoan", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "underlying", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-616/arbitrumone.ts b/simulations/vip-616/arbitrumone.ts new file mode 100644 index 000000000..bd502f15d --- /dev/null +++ b/simulations/vip-616/arbitrumone.ts @@ -0,0 +1,10 @@ +import { forking } from "src/vip-framework"; + +import { ARBITRUMONE_CONFIG } from "../../vips/vip-616/addresses/arbitrumone"; +import { runVip616Suite } from "./shared"; + +const FORK_BLOCK = 459572065; + +forking(FORK_BLOCK, async () => { + await runVip616Suite(ARBITRUMONE_CONFIG); +}); diff --git a/simulations/vip-616/basemainnet.ts b/simulations/vip-616/basemainnet.ts new file mode 100644 index 000000000..dd8e28ec9 --- /dev/null +++ b/simulations/vip-616/basemainnet.ts @@ -0,0 +1,10 @@ +import { forking } from "src/vip-framework"; + +import { BASEMAINNET_CONFIG } from "../../vips/vip-616/addresses/basemainnet"; +import { runVip616Suite } from "./shared"; + +const FORK_BLOCK = 45589260; + +forking(FORK_BLOCK, async () => { + await runVip616Suite(BASEMAINNET_CONFIG); +}); diff --git a/simulations/vip-616/ethereum.ts b/simulations/vip-616/ethereum.ts new file mode 100644 index 000000000..735e82b27 --- /dev/null +++ b/simulations/vip-616/ethereum.ts @@ -0,0 +1,10 @@ +import { forking } from "src/vip-framework"; + +import { ETHEREUM_CONFIG } from "../../vips/vip-616/addresses/ethereum"; +import { runVip616Suite } from "./shared"; + +const FORK_BLOCK = 25027435; + +forking(FORK_BLOCK, async () => { + await runVip616Suite(ETHEREUM_CONFIG); +}); diff --git a/simulations/vip-616/sepolia.ts b/simulations/vip-616/sepolia.ts new file mode 100644 index 000000000..e58f3bebb --- /dev/null +++ b/simulations/vip-616/sepolia.ts @@ -0,0 +1,269 @@ +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { ZERO_ADDRESS } from "src/networkAddresses"; +import { expectEvents, initMainnetUser } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import { SEPOLIA_CONFIG, SEPOLIA_GUARDIAN_OWNER } from "../../vips/vip-616/addresses/sepolia"; +import { + DIAMOND_ONLY_EBRAKE_PERMS, + EBRAKE_COMPTROLLER_PERMS_IL, + SENTINEL_EBRAKE_PERMS, +} from "../../vips/vip-616/bscmainnet"; +import vip666Sepolia, { + DEPLOYER_COMPTROLLER_PERMS, + DEPLOYER_EBRAKE_PERMS, + DEPLOYER_SENTINEL_ORACLE_PERMS, +} from "../../vips/vip-616/bsctestnet"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import DEVIATION_SENTINEL_ABI from "./abi/DeviationSentinel.json"; +import EBRAKE_ABI from "./abi/EBrake.json"; +import SENTINEL_ORACLE_ABI from "./abi/SentinelOracle.json"; + +const FORK_BLOCK = 10761588; + +const cfg = SEPOLIA_CONFIG; + +// Trusted keepers in the new minimal VIP: +// - SEPOLIA_GUARDIAN_OWNER: deployer EOA, drives the manual E2E test cycle +// - cfg.keeper (= cfg.guardian on Sepolia): on-chain keeper backup +// These are two distinct addresses (GUARDIAN_OWNER ≠ GUARDIAN). +const TRUSTED_KEEPERS = [SEPOLIA_GUARDIAN_OWNER, cfg.keeper]; + +// RoleGranted events emitted by the unified 22-command VIP: +// normalTimelock setTrustedKeeper perm on DS: 1 +// normalTimelock setTokenConfig perm on DS: 1 +// EBrake → Comptroller (4 sigs): 4 +// Sentinel → EBrake (3 sigs): 3 +// Deployer extra (1 + 3 + 2): 6 +// --- +// 15 +const EXPECTED_ROLE_GRANTED = 15; + +forking(FORK_BLOCK, async () => { + let acm: Contract; + let deviationSentinel: Contract; + let eBrake: Contract; + let sentinelOracle: Contract; + + let impersonatedDeviationSentinel: SignerWithAddress; + let impersonatedSentinelOracle: SignerWithAddress; + let impersonatedComptroller: SignerWithAddress; + + before(async () => { + acm = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, cfg.acm); + deviationSentinel = await ethers.getContractAt(DEVIATION_SENTINEL_ABI, cfg.deviationSentinel); + eBrake = await ethers.getContractAt(EBRAKE_ABI, cfg.eBrake); + sentinelOracle = await ethers.getContractAt(SENTINEL_ORACLE_ABI, cfg.sentinelOracle); + + impersonatedDeviationSentinel = await initMainnetUser(cfg.deviationSentinel, ethers.utils.parseEther("1")); + impersonatedSentinelOracle = await initMainnetUser(cfg.sentinelOracle, ethers.utils.parseEther("1")); + impersonatedComptroller = await initMainnetUser(cfg.comptroller, ethers.utils.parseEther("1")); + }); + + describe("VIP-666 [Sepolia] — Pre-VIP behaviour", () => { + it("DeviationSentinel pendingOwner is Normal Timelock", async () => { + expect(await deviationSentinel.pendingOwner()).to.equal(cfg.normalTimelock); + }); + + it("SentinelOracle pendingOwner is Normal Timelock", async () => { + expect(await sentinelOracle.pendingOwner()).to.equal(cfg.normalTimelock); + }); + + it("EBrake pendingOwner is Normal Timelock", async () => { + expect(await eBrake.pendingOwner()).to.equal(cfg.normalTimelock); + }); + + it("EBrake immutables are correctly set", async () => { + expect(await eBrake.COMPTROLLER()).to.equal(cfg.comptroller); + expect(await eBrake.IS_ISOLATED_POOL()).to.equal(true); + }); + + it("DeviationSentinel immutables wire to local EBrake + SentinelOracle", async () => { + expect(await deviationSentinel.EBRAKE()).to.equal(cfg.eBrake); + expect(await deviationSentinel.SENTINEL_ORACLE()).to.equal(cfg.sentinelOracle); + }); + + // Use hasPermission (not isAllowedToCall) to avoid false positives from wildcard + // ACM grants already present on Sepolia testnet. + it("EBrake has no permissions on the Comptroller yet", async () => { + for (const sig of EBRAKE_COMPTROLLER_PERMS_IL) { + expect(await acm.hasPermission(cfg.eBrake, cfg.comptroller, sig)).to.equal(false, `unexpected: ${sig}`); + } + }); + + it("DeviationSentinel has no action permissions on EBrake yet", async () => { + for (const sig of SENTINEL_EBRAKE_PERMS) { + expect(await acm.hasPermission(cfg.deviationSentinel, cfg.eBrake, sig)).to.equal(false, `unexpected: ${sig}`); + } + }); + + it("No accounts are whitelisted as trusted keepers yet", async () => { + for (const account of TRUSTED_KEEPERS) { + expect(await deviationSentinel.trustedKeepers(account)).to.equal(false); + } + }); + + it("Deployer EOA has no extra permissions yet", async () => { + for (const sig of DEPLOYER_SENTINEL_ORACLE_PERMS) { + expect(await acm.hasPermission(SEPOLIA_GUARDIAN_OWNER, cfg.sentinelOracle, sig)).to.equal(false); + } + for (const sig of DEPLOYER_EBRAKE_PERMS) { + expect(await acm.hasPermission(SEPOLIA_GUARDIAN_OWNER, cfg.eBrake, sig)).to.equal(false); + } + for (const sig of DEPLOYER_COMPTROLLER_PERMS) { + expect(await acm.hasPermission(SEPOLIA_GUARDIAN_OWNER, cfg.comptroller, sig)).to.equal(false); + } + }); + + it("WETH monitoring is not configured yet", async () => { + const tc = await deviationSentinel.tokenConfigs(cfg.monitoredMarkets[0].token); + expect(tc.deviation).to.equal(0); + expect(tc.enabled).to.equal(false); + }); + + it("WBTC monitoring is not configured yet", async () => { + const tc = await deviationSentinel.tokenConfigs(cfg.monitoredMarkets[1].token); + expect(tc.deviation).to.equal(0); + expect(tc.enabled).to.equal(false); + }); + }); + + testForkedNetworkVipCommands("VIP-666 [Sepolia] Minimal E2E Bootstrap", await vip666Sepolia(), { + callbackAfterExecution: async txResponse => { + // acceptOwnership(): DeviationSentinel + SentinelOracle + EBrake. + // All three share the same OwnershipTransferred topic so any ABI catches all 3. + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["OwnershipTransferred"], [3]); + + // setTrustedKeeper: 2 accounts (GUARDIAN_OWNER + keeper/guardian) + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TrustedKeeperUpdated"], [TRUSTED_KEEPERS.length]); + + // setTokenConfig: WETH + WBTC + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TokenConfigUpdated"], [cfg.monitoredMarkets.length]); + + // RoleGranted: see EXPECTED_ROLE_GRANTED comment above + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["RoleGranted"], [EXPECTED_ROLE_GRANTED]); + }, + }); + + describe("VIP-666 [Sepolia] — Post-VIP behaviour", () => { + describe("Ownership", () => { + it("DeviationSentinel owner is Normal Timelock", async () => { + expect(await deviationSentinel.owner()).to.equal(cfg.normalTimelock); + expect(await deviationSentinel.pendingOwner()).to.equal(ZERO_ADDRESS); + }); + + it("SentinelOracle owner is Normal Timelock", async () => { + expect(await sentinelOracle.owner()).to.equal(cfg.normalTimelock); + expect(await sentinelOracle.pendingOwner()).to.equal(ZERO_ADDRESS); + }); + + it("EBrake owner is Normal Timelock", async () => { + expect(await eBrake.owner()).to.equal(cfg.normalTimelock); + expect(await eBrake.pendingOwner()).to.equal(ZERO_ADDRESS); + }); + }); + + describe("Permissions — EBrake → Comptroller", () => { + it("EBrake has all four IL-supported permissions on the Comptroller", async () => { + const a = acm.connect(impersonatedComptroller); + for (const sig of EBRAKE_COMPTROLLER_PERMS_IL) { + expect(await a.isAllowedToCall(cfg.eBrake, sig)).to.equal(true, `missing: ${sig}`); + } + }); + }); + + describe("Permissions — Sentinel → EBrake", () => { + it("DeviationSentinel has the three handleDeviation permissions on EBrake", async () => { + for (const sig of SENTINEL_EBRAKE_PERMS) { + expect(await acm.hasPermission(cfg.deviationSentinel, cfg.eBrake, sig)).to.equal(true, `missing: ${sig}`); + } + }); + }); + + describe("Permissions — Diamond-only NOT granted", () => { + it("Diamond-only EBrake permissions are not granted", async () => { + for (const sig of DIAMOND_ONLY_EBRAKE_PERMS) { + expect(await acm.hasPermission(cfg.deviationSentinel, cfg.eBrake, sig)).to.equal( + false, + `unexpected Diamond-only: ${sig}`, + ); + } + }); + }); + + describe("Trusted keepers", () => { + it("Deployer EOA and on-chain keeper are whitelisted", async () => { + for (const account of TRUSTED_KEEPERS) { + expect(await deviationSentinel.trustedKeepers(account)).to.equal(true, `not whitelisted: ${account}`); + } + }); + }); + + describe("Deployer EOA extra permissions", () => { + it("Deployer EOA has setDirectPrice on SentinelOracle", async () => { + const a = acm.connect(impersonatedSentinelOracle); + for (const sig of DEPLOYER_SENTINEL_ORACLE_PERMS) { + expect(await a.isAllowedToCall(SEPOLIA_GUARDIAN_OWNER, sig)).to.equal(true, `missing: ${sig}`); + } + }); + + it("Deployer EOA has reset perms on EBrake", async () => { + for (const sig of DEPLOYER_EBRAKE_PERMS) { + expect(await acm.hasPermission(SEPOLIA_GUARDIAN_OWNER, cfg.eBrake, sig)).to.equal(true, `missing: ${sig}`); + } + }); + + it("Deployer EOA has setCollateralFactor + setActionsPaused on Comptroller", async () => { + for (const sig of DEPLOYER_COMPTROLLER_PERMS) { + expect(await acm.hasPermission(SEPOLIA_GUARDIAN_OWNER, cfg.comptroller, sig)).to.equal( + true, + `missing: ${sig}`, + ); + } + }); + }); + + describe("Permissions — Normal Timelock can call DS functions used in this VIP", () => { + it("Normal Timelock has setTrustedKeeper permission on DeviationSentinel", async () => { + const a = acm.connect(impersonatedDeviationSentinel); + expect(await a.isAllowedToCall(cfg.normalTimelock, "setTrustedKeeper(address,bool)")).to.equal(true); + }); + + it("Normal Timelock has setTokenConfig permission on DeviationSentinel", async () => { + const a = acm.connect(impersonatedDeviationSentinel); + expect(await a.isAllowedToCall(cfg.normalTimelock, "setTokenConfig(address,(uint8,bool))")).to.equal(true); + }); + }); + + describe("Market monitoring config", () => { + it("WETH monitoring is enabled with 10% threshold", async () => { + const market = cfg.monitoredMarkets[0]; + expect(market.symbol).to.equal("WETH"); + const tc = await deviationSentinel.tokenConfigs(market.token); + expect(tc.deviation).to.equal(market.deviationPercent); + expect(tc.enabled).to.equal(true); + }); + + it("WBTC monitoring is enabled with 10% threshold", async () => { + const market = cfg.monitoredMarkets[1]; + expect(market.symbol).to.equal("WBTC"); + const tc = await deviationSentinel.tokenConfigs(market.token); + expect(tc.deviation).to.equal(market.deviationPercent); + expect(tc.enabled).to.equal(true); + }); + + it("SentinelOracle has no DEX oracle wired for WETH (direct price flow)", async () => { + const tc = await sentinelOracle.tokenConfigs(cfg.monitoredMarkets[0].token); + expect(tc.oracle ?? tc).to.equal(ZERO_ADDRESS); + }); + + it("SentinelOracle has no DEX oracle wired for WBTC (direct price flow)", async () => { + const tc = await sentinelOracle.tokenConfigs(cfg.monitoredMarkets[1].token); + expect(tc.oracle ?? tc).to.equal(ZERO_ADDRESS); + }); + }); + }); +}); diff --git a/simulations/vip-616/shared.ts b/simulations/vip-616/shared.ts new file mode 100644 index 000000000..c73c1555a --- /dev/null +++ b/simulations/vip-616/shared.ts @@ -0,0 +1,647 @@ +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { ZERO_ADDRESS } from "src/networkAddresses"; +import { expectEvents, getForkedNetworkAddress, initMainnetUser, setMaxStalePeriodInChainlinkOracle } from "src/utils"; +import { testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip616 from "../../vips/vip-616/bscmainnet"; +import { + AERODROME_ORACLE_ADMIN_PERMS, + CURVE_ORACLE_ADMIN_PERMS, + ChainConfig, + DIAMOND_ONLY_EBRAKE_PERMS, + EBRAKE_COMPTROLLER_PERMS_IL, + GOVERNANCE_EBRAKE_PERMS_IL, + MonitoredMarket, + RESET_PERMS, + SENTINEL_ADMIN_PERMS, + SENTINEL_EBRAKE_PERMS, + SENTINEL_ORACLE_ADMIN_PERMS, + UNISWAP_ORACLE_ADMIN_PERMS, + governanceAccounts, +} from "../../vips/vip-616/bscmainnet"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import AERODROME_ORACLE_ABI from "./abi/AerodromeSlipstreamOracle.json"; +import CURVE_ORACLE_ABI from "./abi/CurveOracle.json"; +import DEVIATION_SENTINEL_ABI from "./abi/DeviationSentinel.json"; +import EBRAKE_ABI from "./abi/EBrake.json"; +import IL_COMPTROLLER_ABI from "./abi/ILComptroller.json"; +import RESILIENT_ORACLE_ABI from "./abi/ResilientOracle.json"; +import SENTINEL_ORACLE_ABI from "./abi/SentinelOracle.json"; +import UNISWAP_ORACLE_ABI from "./abi/UniswapOracle.json"; +import VTOKEN_ABI from "./abi/VToken.json"; + +// The VIP grants the configurator DEFAULT_ADMIN_ROLE on the local ACM so that +// execute() can call giveCallPermission / revokeCallPermission (both wrap OZ +// grantRole / revokeRole which require DEFAULT_ADMIN_ROLE). The configurator +// renounces this role at the end of execute() via _selfRevokeACMPermissions(). +const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +// Tokens whose `DeviationSentinel.checkPriceDeviation` end-to-end check is +// fragile at fork time only — wrapped/correlated oracles whose inner feeds +// expose staleness windows we can't override from the simulation side. +// - LBTC: OneJumpOracle (RedStone LBTC/BTC ratio + Chainlink BTC/USD). +// - eBTC: same OneJumpOracle pattern (eBTC/BTC ratio + BTC/USD). +const SKIP_CHECK_PRICE_DEVIATION = new Set(["LBTC", "eBTC"]); + +// RoleGranted event count emitted by VIP-616 per chain: +// 1 DEFAULT_ADMIN_ROLE grant (VIP-level grantRole(0x00, configurator)) +// + 51 base permission grants (12 sentinel admin + 8 sentinelOracle admin +// + 4 uniswapOracle admin + 4 ebrake→comptroller +// + 12 reset + 3 sentinel→ebrake + 8 multisig) +// + 4 if cfg.curveOracle present (CurveOracle admin × 4 govAccounts) +// + 4 if cfg.aerodromeOracle present (AerodromeSlipstreamOracle admin × 4 govAccounts) +// + 32 governance EBrake-action grants (8 sigs × 4 govAccounts) +// + 4 transient self-grants in execute() (_selfGrantBaseTransientPermissions: +// DeviationSentinel×2, SentinelOracle×1, UniswapOracle×1) +// + 1 if cfg.curveOracle / aerodromeOracle present (_selfGrantChainSpecificTransientPermissions) +const expectedRoleGranted = (cfg: ChainConfig): number => { + let n = 1 + 51 + 32 + 4; // DEFAULT_ADMIN_ROLE + base grants + governance EBrake + base transient + if (cfg.curveOracle) n += 4 + 1; // CurveOracle admin grants + transient self-grant + if (cfg.aerodromeOracle) n += 4 + 1; // AerodromeOracle admin grants + transient self-grant + return n; +}; + +// RoleRevoked event count emitted by VIP-616 per chain: +// 4 base transient self-revokes in execute() (_selfRevokeBaseTransientPermissions) +// + 1 if cfg.curveOracle / aerodromeOracle present (_selfRevokeChainSpecificTransientPermissions) +// + 1 configurator renounces DEFAULT_ADMIN_ROLE (_selfRevokeACMPermissions) +const expectedRoleRevoked = (cfg: ChainConfig): number => { + let n = 4 + 1; // base transient revokes + DEFAULT_ADMIN_ROLE renounce + if (cfg.curveOracle || cfg.aerodromeOracle) n += 1; + return n; +}; + +// OwnershipTransferred count = 4 base contracts (DeviationSentinel, SentinelOracle, +// UniswapOracle, EBrake) + 1 each for CurveOracle / AerodromeSlipstreamOracle. +const expectedAcceptOwnership = (cfg: ChainConfig): number => { + let n = 4; + if (cfg.curveOracle) n += 1; + if (cfg.aerodromeOracle) n += 1; + return n; +}; + +const countMarketsByOracle = (markets: MonitoredMarket[], type: MonitoredMarket["oracleType"]) => + markets.filter(m => (m.oracleType ?? "uniswap") === (type ?? "uniswap")).length; + +const dexOracleFor = (cfg: ChainConfig, market: MonitoredMarket): string => { + switch (market.oracleType ?? "uniswap") { + case "uniswap": + return cfg.uniswapOracle; + case "curve": + return cfg.curveOracle as string; + case "aerodrome": + return cfg.aerodromeOracle as string; + } +}; + +const tryGetAddress = (key: string): string | undefined => { + try { + return getForkedNetworkAddress(key); + } catch { + return undefined; + } +}; + +// testForkedNetworkVipCommands advances chain time past timelock delays. Past +// that window Chainlink/RedStone heartbeats expire and ResilientOracle reverts +// with "invalid resilient oracle price". Bump at the adapter level so main + +// pivot + fallback slots and OneJumpOracle wrappers are all covered. +const bumpAdapterStaleness = async (cfg: ChainConfig) => { + const adapters = [tryGetAddress("CHAINLINK_ORACLE"), tryGetAddress("REDSTONE_ORACLE")].filter( + (a): a is string => !!a, + ); + for (const market of cfg.monitoredMarkets) { + for (const adapter of adapters) { + await setMaxStalePeriodInChainlinkOracle(adapter, market.token, ZERO_ADDRESS, cfg.normalTimelock); + } + } +}; + +const buildVTokenIndex = async (comptrollerAddress: string): Promise> => { + const comptroller = await ethers.getContractAt(IL_COMPTROLLER_ABI, comptrollerAddress); + const vTokens: string[] = await comptroller.getAllMarkets(); + const vTokenByUnderlying = new Map(); + for (const vToken of vTokens) { + try { + const v = await ethers.getContractAt(VTOKEN_ABI, vToken); + const underlying: string = await v.underlying(); + vTokenByUnderlying.set(underlying.toLowerCase(), vToken); + } catch { + // native-token vTokens don't expose underlying() — skip + } + } + return vTokenByUnderlying; +}; + +const collectMissingPlaceholders = (cfg: ChainConfig): string[] => { + const missing: string[] = []; + if (cfg.deviationSentinel === ZERO_ADDRESS) missing.push("deviationSentinel"); + if (cfg.eBrake === ZERO_ADDRESS) missing.push("eBrake"); + if (cfg.sentinelOracle === ZERO_ADDRESS) missing.push("sentinelOracle"); + if (cfg.uniswapOracle === ZERO_ADDRESS) missing.push("uniswapOracle"); + if (cfg.multisigPauser === ZERO_ADDRESS) missing.push("multisigPauser"); + if (cfg.keeper === ZERO_ADDRESS) missing.push("keeper"); + if (cfg.configurator === ZERO_ADDRESS) missing.push("configurator"); + return missing; +}; + +export const runVip616Suite = async (cfg: ChainConfig) => { + const missing = collectMissingPlaceholders(cfg); + if (missing.length > 0) { + describe.skip(`VIP-616 [${cfg.name}] — placeholder addresses missing: ${missing.join(", ")}`, () => { + it(`Fill ${missing.join(", ")} to run this suite`, () => { + // intentionally empty — skip stub + }); + }); + return; + } + + // vip616() iterates all three chains and throws if any configurator is ZERO_ADDRESS. + // Catch so one undeployed chain doesn't silently break another chain's sim file. + let proposal: Awaited>; + try { + proposal = await vip616(); + } catch (e: unknown) { + const msg = e instanceof Error ? e.message : String(e); + describe.skip(`VIP-616 [${cfg.name}] — cannot build VIP (all configurators must be set): ${msg}`, () => { + it("Deploy all three configurators and update addresses/.ts", () => { + // intentionally empty — skip stub + }); + }); + return; + } + + let acm: Contract; + let deviationSentinel: Contract; + let eBrake: Contract; + let sentinelOracle: Contract; + let uniswapOracle: Contract; + let curveOracle: Contract | undefined; + let aerodromeOracle: Contract | undefined; + let resilientOracle: Contract; + // underlying address (lowercased) → vToken address — built by walking IL Comptroller markets. + let vTokenByUnderlying: Map; + + // ACM.isAllowedToCall(account, sig) checks msg.sender as the host contract. + // Impersonate each host so the role lookup resolves correctly. + let impersonatedDeviationSentinel: SignerWithAddress; + let impersonatedSentinelOracle: SignerWithAddress; + let impersonatedUniswapOracle: SignerWithAddress; + let impersonatedCurveOracle: SignerWithAddress | undefined; + let impersonatedAerodromeOracle: SignerWithAddress | undefined; + let impersonatedComptroller: SignerWithAddress; + + const govAccounts = governanceAccounts(cfg); + const trustedKeeperAccounts = [cfg.keeper, ...govAccounts]; + + before(async () => { + acm = await ethers.getContractAt(ACCESS_CONTROL_MANAGER_ABI, cfg.acm); + deviationSentinel = await ethers.getContractAt(DEVIATION_SENTINEL_ABI, cfg.deviationSentinel); + eBrake = await ethers.getContractAt(EBRAKE_ABI, cfg.eBrake); + sentinelOracle = await ethers.getContractAt(SENTINEL_ORACLE_ABI, cfg.sentinelOracle); + uniswapOracle = await ethers.getContractAt(UNISWAP_ORACLE_ABI, cfg.uniswapOracle); + resilientOracle = await ethers.getContractAt(RESILIENT_ORACLE_ABI, getForkedNetworkAddress("RESILIENT_ORACLE")); + + impersonatedDeviationSentinel = await initMainnetUser(cfg.deviationSentinel, ethers.utils.parseEther("1")); + impersonatedSentinelOracle = await initMainnetUser(cfg.sentinelOracle, ethers.utils.parseEther("1")); + impersonatedUniswapOracle = await initMainnetUser(cfg.uniswapOracle, ethers.utils.parseEther("1")); + impersonatedComptroller = await initMainnetUser(cfg.comptroller, ethers.utils.parseEther("1")); + + if (cfg.curveOracle) { + curveOracle = await ethers.getContractAt(CURVE_ORACLE_ABI, cfg.curveOracle); + impersonatedCurveOracle = await initMainnetUser(cfg.curveOracle, ethers.utils.parseEther("1")); + } + if (cfg.aerodromeOracle) { + aerodromeOracle = await ethers.getContractAt(AERODROME_ORACLE_ABI, cfg.aerodromeOracle); + impersonatedAerodromeOracle = await initMainnetUser(cfg.aerodromeOracle, ethers.utils.parseEther("1")); + } + + await bumpAdapterStaleness(cfg); + vTokenByUnderlying = await buildVTokenIndex(cfg.comptroller); + }); + + // -------------------- Monitored-market config validity -------------------- + describe(`VIP-616 [${cfg.name}] — Monitored markets config validity`, () => { + // A zero-address token or pool, or an out-of-range deviation, would be silently + // skipped or accepted-as-malformed by the wiring loop. Fail loud at simulation time. + it("Every monitored market has non-zero token, non-zero pool, and 0 < deviation ≤ 100", () => { + for (const market of cfg.monitoredMarkets) { + expect(market.token, `${market.symbol}: token is ZERO_ADDRESS`).to.not.equal(ZERO_ADDRESS); + expect(market.pool, `${market.symbol}: pool is ZERO_ADDRESS`).to.not.equal(ZERO_ADDRESS); + expect(market.token.length, `${market.symbol}: token not 20 bytes`).to.equal(42); + expect(market.pool.length, `${market.symbol}: pool not 20 bytes`).to.equal(42); + expect(market.deviationPercent, `${market.symbol}: deviation must be > 0`).to.be.greaterThan(0); + expect(market.deviationPercent, `${market.symbol}: deviation must be ≤ 100`).to.be.lessThanOrEqual(100); + } + }); + + // ResilientOracle is the reference price source for handleDeviation. If it has + // no feed for a monitored token, oraclePrice = 0 makes hasDeviation always true + // and every keeper call would pause the market. + it("ResilientOracle returns a non-zero price for every monitored token", async () => { + for (const market of cfg.monitoredMarkets) { + const price = await resilientOracle.getPrice(market.token); + expect(price, `${market.symbol}: ResilientOracle.getPrice returned 0`).to.be.gt(0); + } + }); + }); + + // -------------------- Pre-VIP behaviour -------------------- + describe(`VIP-616 [${cfg.name}] — Pre-VIP behaviour`, () => { + it("DeviationSentinel pendingOwner is Normal Timelock", async () => { + expect(await deviationSentinel.pendingOwner()).to.equal(cfg.normalTimelock); + }); + + it("SentinelOracle pendingOwner is Normal Timelock", async () => { + expect(await sentinelOracle.pendingOwner()).to.equal(cfg.normalTimelock); + }); + + it("UniswapOracle pendingOwner is Normal Timelock", async () => { + expect(await uniswapOracle.pendingOwner()).to.equal(cfg.normalTimelock); + }); + + it("EBrake pendingOwner is Normal Timelock", async () => { + expect(await eBrake.pendingOwner()).to.equal(cfg.normalTimelock); + }); + + if (cfg.curveOracle) { + it("CurveOracle pendingOwner is Normal Timelock", async () => { + expect(await curveOracle!.pendingOwner()).to.equal(cfg.normalTimelock); + }); + } + + if (cfg.aerodromeOracle) { + it("AerodromeSlipstreamOracle pendingOwner is Normal Timelock", async () => { + expect(await aerodromeOracle!.pendingOwner()).to.equal(cfg.normalTimelock); + }); + } + + it("EBrake immutables are correctly set for IL", async () => { + expect(await eBrake.COMPTROLLER()).to.equal(cfg.comptroller); + expect(await eBrake.IS_ISOLATED_POOL()).to.equal(true); + }); + + it("DeviationSentinel immutables wire to local EBrake + SentinelOracle", async () => { + expect(await deviationSentinel.EBRAKE()).to.equal(cfg.eBrake); + expect(await deviationSentinel.SENTINEL_ORACLE()).to.equal(cfg.sentinelOracle); + }); + + it("Configurator does not yet hold DEFAULT_ADMIN_ROLE on ACM", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, cfg.configurator)).to.equal(false); + }); + + it("Guardian + Timelocks have no admin permissions on DeviationSentinel yet", async () => { + const a = acm.connect(impersonatedDeviationSentinel); + for (const account of govAccounts) { + for (const sig of SENTINEL_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(false, `unexpected ${sig} for ${account}`); + } + } + }); + + it("Guardian + Timelocks have no admin permissions on SentinelOracle yet", async () => { + const a = acm.connect(impersonatedSentinelOracle); + for (const account of govAccounts) { + for (const sig of SENTINEL_ORACLE_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(false, `unexpected ${sig} for ${account}`); + } + } + }); + + it("Guardian + Timelocks have no admin permissions on UniswapOracle yet", async () => { + const a = acm.connect(impersonatedUniswapOracle); + for (const account of govAccounts) { + for (const sig of UNISWAP_ORACLE_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(false, `unexpected ${sig} for ${account}`); + } + } + }); + + if (cfg.curveOracle) { + it("Guardian + Timelocks have no admin permissions on CurveOracle yet", async () => { + const a = acm.connect(impersonatedCurveOracle!); + for (const account of govAccounts) { + for (const sig of CURVE_ORACLE_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(false, `unexpected ${sig} for ${account}`); + } + } + }); + } + + if (cfg.aerodromeOracle) { + it("Guardian + Timelocks have no admin permissions on AerodromeSlipstreamOracle yet", async () => { + const a = acm.connect(impersonatedAerodromeOracle!); + for (const account of govAccounts) { + for (const sig of AERODROME_ORACLE_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(false, `unexpected ${sig} for ${account}`); + } + } + }); + } + + // Use hasPermission (specific role lookup), not isAllowedToCall — the IL Comptroller is + // a live contract that may already hold wildcard grants on these sigs (Risk Steward, + // Guardian, etc.), and isAllowedToCall would return true off the wildcard, masking the + // genuine pre-VIP state of EBrake's specific perm. + it("EBrake has no specific permissions on the IL Comptroller yet", async () => { + for (const sig of EBRAKE_COMPTROLLER_PERMS_IL) { + expect(await acm.hasPermission(cfg.eBrake, cfg.comptroller, sig)).to.equal(false, `unexpected ${sig}`); + } + }); + + it("Guardian + Timelocks have no reset permissions on EBrake yet", async () => { + for (const account of govAccounts) { + for (const sig of RESET_PERMS) { + expect(await acm.hasPermission(account, cfg.eBrake, sig)).to.equal(false, `unexpected ${sig} for ${account}`); + } + } + }); + + it("DeviationSentinel has no action permissions on EBrake yet", async () => { + for (const sig of SENTINEL_EBRAKE_PERMS) { + expect(await acm.hasPermission(cfg.deviationSentinel, cfg.eBrake, sig)).to.equal(false, `unexpected ${sig}`); + } + }); + + it("Multisig Pauser has no EBrake action permissions yet", async () => { + for (const sig of GOVERNANCE_EBRAKE_PERMS_IL) { + expect(await acm.hasPermission(cfg.multisigPauser, cfg.eBrake, sig)).to.equal(false, `unexpected ${sig}`); + } + }); + + it("Guardian + Timelocks have no EBrake-specific action permissions yet", async () => { + for (const account of govAccounts) { + for (const sig of GOVERNANCE_EBRAKE_PERMS_IL) { + expect(await acm.hasPermission(account, cfg.eBrake, sig)).to.equal(false, `unexpected ${sig} for ${account}`); + } + } + }); + + it("No accounts are whitelisted as trusted keepers yet", async () => { + for (const account of trustedKeeperAccounts) { + expect(await deviationSentinel.trustedKeepers(account)).to.equal(false); + } + }); + + for (const market of cfg.monitoredMarkets) { + it(`${market.symbol} is not wired yet`, async () => { + // Each oracle uses a different storage shape for its pool config: + // - UniswapOracle / AerodromeSlipstreamOracle: tokenPools(token) -> address + // - CurveOracle: poolConfigs(token) -> { pool, coinIndex, referenceToken, ... } + const oracleType = market.oracleType ?? "uniswap"; + if (oracleType === "curve") { + const cfgEntry = await curveOracle!.poolConfigs(market.token); + expect(cfgEntry.pool).to.equal(ZERO_ADDRESS); + } else if (oracleType === "aerodrome") { + expect(await aerodromeOracle!.tokenPools(market.token)).to.equal(ZERO_ADDRESS); + } else { + expect(await uniswapOracle.tokenPools(market.token)).to.equal(ZERO_ADDRESS); + } + const tcSentinel = await sentinelOracle.tokenConfigs(market.token); + expect(tcSentinel.oracle ?? tcSentinel).to.equal(ZERO_ADDRESS); + const tcDev = await deviationSentinel.tokenConfigs(market.token); + expect(tcDev.deviation).to.equal(0); + expect(tcDev.enabled).to.equal(false); + }); + } + }); + + // -------------------- Apply VIP -------------------- + testForkedNetworkVipCommands(`VIP-616 [${cfg.name}] Bootstrap, Permissions, Wiring`, proposal, { + callbackAfterExecution: async txResponse => { + // 4 acceptOwnership() calls, +1 each for CurveOracle / AerodromeSlipstreamOracle. + await expectEvents( + txResponse, + [DEVIATION_SENTINEL_ABI], + ["OwnershipTransferred"], + [expectedAcceptOwnership(cfg)], + ); + + // 5 trusted keepers per chain: cfg.keeper + 4 governance accounts. + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TrustedKeeperUpdated"], [5]); + + // Total RoleGranted per chain — see expectedRoleGranted comment for the breakdown. + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["RoleGranted"], [expectedRoleGranted(cfg)]); + + // Configurator revokes its transient periphery perms and renounces DEFAULT_ADMIN_ROLE + // at the end of execute() — see expectedRoleRevoked comment for the breakdown. + await expectEvents(txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["RoleRevoked"], [expectedRoleRevoked(cfg)]); + + // Pool wiring counts. UniswapOracle and AerodromeSlipstreamOracle emit the same + // 2-arg `PoolConfigUpdated(address,address)` event (identical topic hash), so + // the UniswapOracle ABI filter decodes both. CurveOracle's 4-arg variant has its + // own topic and is asserted separately. + const uniswapMarkets = countMarketsByOracle(cfg.monitoredMarkets, "uniswap"); + const curveMarkets = countMarketsByOracle(cfg.monitoredMarkets, "curve"); + const aerodromeMarkets = countMarketsByOracle(cfg.monitoredMarkets, "aerodrome"); + await expectEvents(txResponse, [UNISWAP_ORACLE_ABI], ["PoolConfigUpdated"], [uniswapMarkets + aerodromeMarkets]); + if (cfg.curveOracle && curveMarkets > 0) { + await expectEvents(txResponse, [CURVE_ORACLE_ABI], ["PoolConfigUpdated"], [curveMarkets]); + } + await expectEvents( + txResponse, + [SENTINEL_ORACLE_ABI], + ["TokenOracleConfigUpdated"], + [cfg.monitoredMarkets.length], + ); + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TokenConfigUpdated"], [cfg.monitoredMarkets.length]); + }, + }); + + // -------------------- Post-VIP behaviour -------------------- + describe(`VIP-616 [${cfg.name}] — Post-VIP behaviour`, () => { + it("All bootstrap contracts have Normal Timelock as owner", async () => { + expect(await deviationSentinel.owner()).to.equal(cfg.normalTimelock); + expect(await sentinelOracle.owner()).to.equal(cfg.normalTimelock); + expect(await uniswapOracle.owner()).to.equal(cfg.normalTimelock); + expect(await eBrake.owner()).to.equal(cfg.normalTimelock); + if (cfg.curveOracle) expect(await curveOracle!.owner()).to.equal(cfg.normalTimelock); + if (cfg.aerodromeOracle) expect(await aerodromeOracle!.owner()).to.equal(cfg.normalTimelock); + }); + + it("All bootstrap contracts have AddressZero as pendingOwner (acceptOwnership cleared it)", async () => { + expect(await deviationSentinel.pendingOwner()).to.equal(ZERO_ADDRESS); + expect(await sentinelOracle.pendingOwner()).to.equal(ZERO_ADDRESS); + expect(await uniswapOracle.pendingOwner()).to.equal(ZERO_ADDRESS); + expect(await eBrake.pendingOwner()).to.equal(ZERO_ADDRESS); + if (cfg.curveOracle) expect(await curveOracle!.pendingOwner()).to.equal(ZERO_ADDRESS); + if (cfg.aerodromeOracle) expect(await aerodromeOracle!.pendingOwner()).to.equal(ZERO_ADDRESS); + }); + + // The configurator renounces DEFAULT_ADMIN_ROLE at the end of execute() via + // _selfRevokeACMPermissions(). Leaving it in place would be a standing + // ACM-mutation foothold. + it("Configurator no longer holds DEFAULT_ADMIN_ROLE on ACM (renounced in execute())", async () => { + expect(await acm.hasRole(DEFAULT_ADMIN_ROLE, cfg.configurator)).to.equal( + false, + "configurator still holds DEFAULT_ADMIN_ROLE", + ); + }); + + it("Guardian + Timelocks have all admin permissions on DeviationSentinel", async () => { + const a = acm.connect(impersonatedDeviationSentinel); + for (const account of govAccounts) { + for (const sig of SENTINEL_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(true, `missing ${sig} for ${account}`); + } + } + }); + + it("Guardian + Timelocks have all admin permissions on SentinelOracle", async () => { + const a = acm.connect(impersonatedSentinelOracle); + for (const account of govAccounts) { + for (const sig of SENTINEL_ORACLE_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(true, `missing ${sig} for ${account}`); + } + } + }); + + it("Guardian + Timelocks have setPoolConfig permission on UniswapOracle", async () => { + const a = acm.connect(impersonatedUniswapOracle); + for (const account of govAccounts) { + for (const sig of UNISWAP_ORACLE_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(true, `missing ${sig} for ${account}`); + } + } + }); + + if (cfg.curveOracle) { + it("Guardian + Timelocks have setPoolConfig permission on CurveOracle", async () => { + const a = acm.connect(impersonatedCurveOracle!); + for (const account of govAccounts) { + for (const sig of CURVE_ORACLE_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(true, `missing ${sig} for ${account}`); + } + } + }); + } + + if (cfg.aerodromeOracle) { + it("Guardian + Timelocks have setPoolConfig permission on AerodromeSlipstreamOracle", async () => { + const a = acm.connect(impersonatedAerodromeOracle!); + for (const account of govAccounts) { + for (const sig of AERODROME_ORACLE_ADMIN_PERMS) { + expect(await a.isAllowedToCall(account, sig)).to.equal(true, `missing ${sig} for ${account}`); + } + } + }); + } + + it("EBrake has all four IL-supported permissions on the local IL Comptroller", async () => { + const a = acm.connect(impersonatedComptroller); + for (const sig of EBRAKE_COMPTROLLER_PERMS_IL) { + expect(await a.isAllowedToCall(cfg.eBrake, sig)).to.equal(true, `missing ${sig}`); + } + }); + + it("Guardian + Timelocks have all reset permissions on EBrake", async () => { + for (const account of govAccounts) { + for (const sig of RESET_PERMS) { + expect(await acm.hasPermission(account, cfg.eBrake, sig)).to.equal(true, `missing ${sig} for ${account}`); + } + } + }); + + it("DeviationSentinel has the three handleDeviation permissions on EBrake", async () => { + for (const sig of SENTINEL_EBRAKE_PERMS) { + expect(await acm.hasPermission(cfg.deviationSentinel, cfg.eBrake, sig)).to.equal(true, `missing ${sig}`); + } + }); + + it("Multisig Pauser has all 8 IL-supported EBrake action permissions", async () => { + for (const sig of GOVERNANCE_EBRAKE_PERMS_IL) { + expect(await acm.hasPermission(cfg.multisigPauser, cfg.eBrake, sig)).to.equal(true, `missing ${sig}`); + } + }); + + it("Guardian + Timelocks have all 8 IL-supported EBrake action permissions", async () => { + for (const account of govAccounts) { + for (const sig of GOVERNANCE_EBRAKE_PERMS_IL) { + expect(await acm.hasPermission(account, cfg.eBrake, sig)).to.equal(true, `missing ${sig} for ${account}`); + } + } + }); + + it("Diamond-only EBrake permissions are intentionally NOT granted", async () => { + for (const account of govAccounts) { + for (const sig of DIAMOND_ONLY_EBRAKE_PERMS) { + expect(await acm.hasPermission(account, cfg.eBrake, sig)).to.equal( + false, + `Diamond-only ${sig} unexpectedly granted to ${account}`, + ); + } + } + }); + + it("Keeper + Guardian + Timelocks are whitelisted as trusted keepers on DeviationSentinel", async () => { + for (const account of trustedKeeperAccounts) { + expect(await deviationSentinel.trustedKeepers(account)).to.equal(true); + } + }); + + for (const market of cfg.monitoredMarkets) { + const expectedDexOracle = dexOracleFor(cfg, market); + + it(`${market.symbol} pool is configured on the routed DEX oracle`, async () => { + const oracleType = market.oracleType ?? "uniswap"; + if (oracleType === "curve") { + const cfgEntry = await curveOracle!.poolConfigs(market.token); + expect(ethers.utils.getAddress(cfgEntry.pool)).to.equal(ethers.utils.getAddress(market.pool)); + expect(cfgEntry.coinIndex).to.equal(market.coinIndex); + expect(cfgEntry.refCoinIndex).to.equal(market.refCoinIndex); + expect(ethers.utils.getAddress(cfgEntry.referenceToken)).to.equal( + ethers.utils.getAddress(market.referenceToken as string), + ); + expect(cfgEntry.assetDecimals).to.equal(market.assetDecimals); + } else if (oracleType === "aerodrome") { + const actual = await aerodromeOracle!.tokenPools(market.token); + expect(ethers.utils.getAddress(actual)).to.equal(ethers.utils.getAddress(market.pool)); + } else { + const actual = await uniswapOracle.tokenPools(market.token); + expect(ethers.utils.getAddress(actual)).to.equal(ethers.utils.getAddress(market.pool)); + } + }); + + it(`${market.symbol} oracle is configured on SentinelOracle`, async () => { + const tc = await sentinelOracle.tokenConfigs(market.token); + const actual = tc.oracle ?? tc; + expect(ethers.utils.getAddress(actual)).to.equal(ethers.utils.getAddress(expectedDexOracle)); + }); + + it(`${market.symbol} deviation threshold is configured on DeviationSentinel`, async () => { + const tc = await deviationSentinel.tokenConfigs(market.token); + expect(tc.deviation).to.equal(market.deviationPercent); + expect(tc.enabled).to.equal(true); + }); + + // End-to-end price-pipeline check: SentinelOracle → routed DEX oracle → pool. + // If the pool isn't a real Uniswap V3 / V3-compatible contract, slot0 reverts + // and handleDeviation would always revert (silent monitoring outage). + it(`${market.symbol} SentinelOracle.getPrice returns a non-zero price`, async () => { + const price = await sentinelOracle.getPrice(market.token); + expect(price, `${market.symbol}: SentinelOracle.getPrice returned 0`).to.be.gt(0); + }); + + // Full handleDeviation pre-flight: same path the keeper exercises, minus the + // EBrake side-effect. Skipped for fork-fragile tokens (see SKIP_CHECK_PRICE_DEVIATION). + if (!SKIP_CHECK_PRICE_DEVIATION.has(market.symbol)) { + it(`${market.symbol} DeviationSentinel.checkPriceDeviation returns hasDeviation=false at fork time`, async () => { + const vToken = vTokenByUnderlying.get(market.token.toLowerCase()); + expect(vToken, `${market.symbol}: no vToken in Core Pool with underlying=${market.token}`).to.not.be + .undefined; + const [hasDeviation, oraclePrice, sentinelPrice, deviationPercent] = + await deviationSentinel.checkPriceDeviation(vToken); + expect(oraclePrice, `${market.symbol}: oraclePrice = 0`).to.be.gt(0); + expect(sentinelPrice, `${market.symbol}: sentinelPrice = 0`).to.be.gt(0); + expect(deviationPercent, `${market.symbol}: live deviation ≥ trigger threshold`).to.be.lt( + market.deviationPercent, + ); + expect(hasDeviation, `${market.symbol}: handleDeviation would trigger right now`).to.equal(false); + }); + } + } + }); +}; diff --git a/src/networkAddresses.ts b/src/networkAddresses.ts index 21cb44e94..c985fd67f 100644 --- a/src/networkAddresses.ts +++ b/src/networkAddresses.ts @@ -102,6 +102,7 @@ export const NETWORK_ADDRESSES = { FAST_TRACK_TIMELOCK: "0x7F043F43Adb392072a3Ba0cC9c96e894C6f7e182", CRITICAL_TIMELOCK: "0xA24A7A65b8968a749841988Bd7d05F6a94329fDe", GUARDIAN: "0x94fa6078b6b8a26F0B6EDFFBE6501B22A10470fB", + ACCESS_CONTROL_MANAGER: "0xbf705C00578d43B6147ab4eaE04DBBEd1ccCdc96", CHAINLINK_ORACLE: oracleSepoliaContracts.addresses.ChainlinkOracle, RESILIENT_ORACLE: oracleSepoliaContracts.addresses.ResilientOracle, REDSTONE_ORACLE: oracleSepoliaContracts.addresses.RedStoneOracle, @@ -114,6 +115,7 @@ export const NETWORK_ADDRESSES = { ENDPOINT: "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", LZ_LIBRARY: "0x3acaaf60502791d199a5a5f0b173d78229ebfe32", OMNICHAIN_GOVERNANCE_EXECUTOR: "0xD9B18a43Ee9964061c1A1925Aa907462F0249109", + CORE_COMPTROLLER: "0x7Aa39ab4BcA897F403425C9C6FDbd0f882Be0D70", }, opbnbtestnet: { NORMAL_TIMELOCK: "0x1c4e015Bd435Efcf4f58D82B0d0fBa8fC4F81120", @@ -167,6 +169,7 @@ export const NETWORK_ADDRESSES = { OMNICHAIN_GOVERNANCE_EXECUTOR: "0xcf3e6972a8e9c53D33b642a2592938944956f138", }, arbitrumone: { + ACCESS_CONTROL_MANAGER: "0xD9dD18EB0cf10CbA837677f28A8F9Bda4bc2b157", NORMAL_TIMELOCK: "0x4b94589Cc23F618687790036726f744D602c4017", FAST_TRACK_TIMELOCK: "0x2286a9B2a5246218f2fC1F380383f45BDfCE3E04", CRITICAL_TIMELOCK: "0x181E4f8F21D087bF02Ea2F64D5e550849FBca674", @@ -202,6 +205,7 @@ export const NETWORK_ADDRESSES = { OMNICHAIN_GOVERNANCE_EXECUTOR: "0x83F79CfbaEee738173c0dfd866796743F4E25C9e", }, zksyncmainnet: { + ACCESS_CONTROL_MANAGER: "0x526159A92A82afE5327d37Ef446b68FD9a5cA914", NORMAL_TIMELOCK: "0x093565Bc20AA326F4209eBaF3a26089272627613", FAST_TRACK_TIMELOCK: "0x32f71c95BC8F9d996f89c642f1a84d06B2484AE9", CRITICAL_TIMELOCK: "0xbfbc79D4198963e4a66270F3EfB1fdA0F382E49c", @@ -271,6 +275,7 @@ export const NETWORK_ADDRESSES = { ENDPOINT: "0x55370E0fBB5f5b8dAeD978BA1c075a499eB107B8", }, basemainnet: { + ACCESS_CONTROL_MANAGER: "0x9E6CeEfDC6183e4D0DF8092A9B90cDF659687daB", NORMAL_TIMELOCK: "0x21c12f2946a1a66cBFf7eb997022a37167eCf517", FAST_TRACK_TIMELOCK: "0x209F73Ee2Fa9A72aF3Fa6aF1933A3B58ed3De5D7", CRITICAL_TIMELOCK: "0x47F65466392ff2aE825d7a170889F7b5b9D8e60D", diff --git a/src/utils.ts b/src/utils.ts index eee4e3da3..090b3b72c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -30,6 +30,15 @@ import COMPTROLLER_ABI from "./vip-framework/abi/comptroller.json"; const BSCTESTNET_OMNICHAIN_SENDER = "0xCfD34AEB46b1CB4779c945854d405E91D27A1899"; const BSCMAINNET_OMNICHAIN_SENDER = "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6"; +// LayerZero payload size cap. Verified on-chain across every destination +// OmnichainGovernanceExecutor Venus supports (ethereum, arbitrumone, opmainnet, basemainnet, +// zksyncmainnet, opbnbmainnet, unichainmainnet, plus the matching testnets): +// DEFAULT_PAYLOAD_SIZE_LIMIT = 10000 and payloadSizeLimitLookup(bsc src) = 0 (no override) +// on every executor. The LZ Relayer enforces the same 10000-byte cap on the sender side, +// so this single constant is the binding limit for every cross-chain VIP. If any executor +// later sets a per-source override, switch to a runtime lookup. +const LZ_PAYLOAD_SIZE_LIMIT = 10_000; + export const getOmnichainProposalSenderAddress = () => { if (FORKED_NETWORK === "bscmainnet" || REMOTE_MAINNET_NETWORKS.includes(FORKED_NETWORK as REMOTE_NETWORKS)) { return BSCMAINNET_OMNICHAIN_SENDER; @@ -240,6 +249,19 @@ export const makeProposal = async ( ); const remoteAdapterParam = getAdapterParam(chainCommands.map(cmd => cmd.target).length); + // LZ Relayer sizes the payloadWithId envelope (the same shape estimateFees receives), + // not just the raw makePayload output. Reproduce that wrapping here so the byte count + // matches what the on-chain Relayer would check, then fail before propose is attempted. + const payloadWithIdSize = + ethers.utils.defaultAbiCoder.encode(["bytes", "uint256"], [remoteParam, 0]).length / 2 - 1; + if (payloadWithIdSize > LZ_PAYLOAD_SIZE_LIMIT) { + throw new Error( + `LayerZero payload size ${payloadWithIdSize} bytes exceeds limit of ${LZ_PAYLOAD_SIZE_LIMIT} ` + + `for dstChainId=${key} (${chainCommands.length} commands). ` + + `Split the proposal into multiple VIPs so each cross-chain message fits within the LZ Relayer cap.`, + ); + } + proposal.targets.push(getOmnichainProposalSenderAddress()); const value = await getEstimateFeesForBridge(key, remoteParam, remoteAdapterParam); proposal.values.push(value.toString()); diff --git a/vips/vip-616/addresses/arbitrumone.ts b/vips/vip-616/addresses/arbitrumone.ts new file mode 100644 index 000000000..a24e022b5 --- /dev/null +++ b/vips/vip-616/addresses/arbitrumone.ts @@ -0,0 +1,78 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; + +import type { ChainConfig } from "../bscmainnet"; + +const { arbitrumone } = NETWORK_ADDRESSES; + +// Already-deployed governance + protocol addresses on Arbitrum One +export const ARBITRUMONE_ACM = arbitrumone.ACCESS_CONTROL_MANAGER; +export const ARBITRUMONE_GUARDIAN = arbitrumone.GUARDIAN; +export const ARBITRUMONE_NORMAL_TIMELOCK = arbitrumone.NORMAL_TIMELOCK; +export const ARBITRUMONE_FAST_TRACK_TIMELOCK = arbitrumone.FAST_TRACK_TIMELOCK; +export const ARBITRUMONE_CRITICAL_TIMELOCK = arbitrumone.CRITICAL_TIMELOCK; +export const ARBITRUMONE_CORE_COMPTROLLER = arbitrumone.CORE_COMPTROLLER; + +// Deployed via venus-periphery PR #65 (feat/VPD-1134) +export const ARBITRUMONE_DEVIATION_SENTINEL = "0xb4CC54B33d34fD809E8fBD83A066158591ED7Fba"; +export const ARBITRUMONE_EBRAKE = "0xFc4CE7Ca9BB5119705Cfb84d6e4476e8a4032b26"; +export const ARBITRUMONE_SENTINEL_ORACLE = "0x3563CAbc541a0432C66A64942ffB4070a9726226"; +export const ARBITRUMONE_UNISWAP_ORACLE = "0xB6CFbfe6834EF519f002DBc1a8B81Ea437Ca647D"; +export const ARBITRUMONE_MULTISIG_PAUSER = "0xCCa5a587eBDBe80f23c8610F2e53B03158e62948"; // Venus team multisig +export const ARBITRUMONE_KEEPER = "0x57fa23f591203f61cef84a7bc892df69ca95c86e"; +export const ARBITRUMONE_CONFIGURATOR = "0x2AFAed4A909491E0181E55429F7F621528BEd5Ef"; +export const ARBITRUMONE_DST_CHAIN_ID = LzChainId.arbitrumone; + +// Eligible Core Pool markets — Uniswap V3 (Arbitrum) sources, unified 10% threshold. +// USDC and USD₮0 share the same Uniswap V3 pool (USDC/USD₮0 pair). +export const ARBITRUMONE_MONITORED_MARKETS = [ + { + symbol: "WETH", + token: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + pool: "0xc6962004f452be9203591991d15f6b388e09e8d0", // WETH/USDC Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "WBTC", + token: "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + pool: "0x0e4831319a50228b9e450861297ab92dee15b44f", // WBTC/USDC Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "USDC", + token: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + pool: "0xbe3ad6a5669dc0b8b12febc03608860c31e2eef6", // USDC/USDT Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "USD₮0", + token: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", + pool: "0xbe3ad6a5669dc0b8b12febc03608860c31e2eef6", // USD₮0/USDC Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "ARB", + token: "0x912CE59144191C1204E64559FE8253a0e49E6548", + pool: "0xaebdca1bc8d89177ebe2308d62af5e74885dccc3", // ARB/USDC Uniswap V3 + deviationPercent: 10, + }, +]; + +export const ARBITRUMONE_CONFIG = { + name: "Arbitrum One", + dstChainId: ARBITRUMONE_DST_CHAIN_ID, + acm: ARBITRUMONE_ACM, + guardian: ARBITRUMONE_GUARDIAN, + normalTimelock: ARBITRUMONE_NORMAL_TIMELOCK, + fastTrackTimelock: ARBITRUMONE_FAST_TRACK_TIMELOCK, + criticalTimelock: ARBITRUMONE_CRITICAL_TIMELOCK, + comptroller: ARBITRUMONE_CORE_COMPTROLLER, + deviationSentinel: ARBITRUMONE_DEVIATION_SENTINEL, + eBrake: ARBITRUMONE_EBRAKE, + sentinelOracle: ARBITRUMONE_SENTINEL_ORACLE, + uniswapOracle: ARBITRUMONE_UNISWAP_ORACLE, + multisigPauser: ARBITRUMONE_MULTISIG_PAUSER, + keeper: ARBITRUMONE_KEEPER, + monitoredMarkets: ARBITRUMONE_MONITORED_MARKETS, + configurator: ARBITRUMONE_CONFIGURATOR, +} satisfies ChainConfig; diff --git a/vips/vip-616/addresses/basemainnet.ts b/vips/vip-616/addresses/basemainnet.ts new file mode 100644 index 000000000..64678f5d3 --- /dev/null +++ b/vips/vip-616/addresses/basemainnet.ts @@ -0,0 +1,80 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; + +import type { ChainConfig } from "../bscmainnet"; + +const { basemainnet } = NETWORK_ADDRESSES; + +// Already-deployed governance + protocol addresses on Base mainnet +export const BASEMAINNET_ACM = basemainnet.ACCESS_CONTROL_MANAGER; +export const BASEMAINNET_GUARDIAN = basemainnet.GUARDIAN; +export const BASEMAINNET_NORMAL_TIMELOCK = basemainnet.NORMAL_TIMELOCK; +export const BASEMAINNET_FAST_TRACK_TIMELOCK = basemainnet.FAST_TRACK_TIMELOCK; +export const BASEMAINNET_CRITICAL_TIMELOCK = basemainnet.CRITICAL_TIMELOCK; +export const BASEMAINNET_CORE_COMPTROLLER = basemainnet.CORE_COMPTROLLER; + +// Deployed via venus-periphery PR #65 (feat/VPD-1134) +export const BASEMAINNET_DEVIATION_SENTINEL = "0x12D09d5b13A673269cdB624D17A42f45a5233076"; +export const BASEMAINNET_EBRAKE = "0x062C68Af7B9Fb059DCB7FA4B6b92E633350fb7c2"; +export const BASEMAINNET_SENTINEL_ORACLE = "0xCdD6D79Fd313C21967CED04C1b8bE70BDc27574D"; +export const BASEMAINNET_UNISWAP_ORACLE = "0xc3b5169a7d5f6341403c74187Db3C4Fe6d447762"; +// Deployed via venus-periphery PR #66 — prices Aerodrome Slipstream (CL) pools whose +// slot0() 6-tuple is incompatible with the UniswapOracle V3 ABI. +export const BASEMAINNET_AERODROME_ORACLE = "0x5DE0B322A74088fD64CDD01042BE2fBc47FE82EC"; +export const BASEMAINNET_MULTISIG_PAUSER = "0xCCa5a587eBDBe80f23c8610F2e53B03158e62948"; // Venus team multisig +export const BASEMAINNET_KEEPER = "0x57fa23f591203f61cef84a7bc892df69ca95c86e"; +export const BASEMAINNET_CONFIGURATOR = "0x3fb0aD3828E6A62E3B527CF51F4F3d011B4a9EA1"; + +export const BASEMAINNET_DST_CHAIN_ID = LzChainId.basemainnet; + +// Eligible Core Pool markets — unified 10% threshold. WETH and USDC route through the +// most liquid Uniswap V3 Base pool; cbBTC and wstETH route through the AerodromeSlipstreamOracle +// because their only liquid pools live on Aerodrome's concentrated-liquidity DEX. +export const BASEMAINNET_MONITORED_MARKETS = [ + { + symbol: "WETH", + token: "0x4200000000000000000000000000000000000006", + pool: "0x6c561b446416e1a00e8e93e221854d6ea4171372", // WETH/USDC Uniswap V3 Base + deviationPercent: 10, + }, + { + symbol: "USDC", + token: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + pool: "0x6c561b446416e1a00e8e93e221854d6ea4171372", // USDC/WETH Uniswap V3 Base + deviationPercent: 10, + }, + { + symbol: "cbBTC", + token: "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf", + pool: "0x4e962bb3889bf030368f56810a9c96b83cb3e778", // cbBTC/USDC Aerodrome Slipstream + deviationPercent: 10, + oracleType: "aerodrome" as const, + }, + { + symbol: "wstETH", + token: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", + pool: "0x861a2922be165a5bd41b1e482b49216b465e1b5f", // wstETH/WETH Aerodrome Slipstream + deviationPercent: 10, + oracleType: "aerodrome" as const, + }, +]; + +export const BASEMAINNET_CONFIG = { + name: "Base", + dstChainId: BASEMAINNET_DST_CHAIN_ID, + acm: BASEMAINNET_ACM, + guardian: BASEMAINNET_GUARDIAN, + normalTimelock: BASEMAINNET_NORMAL_TIMELOCK, + fastTrackTimelock: BASEMAINNET_FAST_TRACK_TIMELOCK, + criticalTimelock: BASEMAINNET_CRITICAL_TIMELOCK, + comptroller: BASEMAINNET_CORE_COMPTROLLER, + deviationSentinel: BASEMAINNET_DEVIATION_SENTINEL, + eBrake: BASEMAINNET_EBRAKE, + sentinelOracle: BASEMAINNET_SENTINEL_ORACLE, + uniswapOracle: BASEMAINNET_UNISWAP_ORACLE, + aerodromeOracle: BASEMAINNET_AERODROME_ORACLE, + multisigPauser: BASEMAINNET_MULTISIG_PAUSER, + keeper: BASEMAINNET_KEEPER, + monitoredMarkets: BASEMAINNET_MONITORED_MARKETS, + configurator: BASEMAINNET_CONFIGURATOR, +} satisfies ChainConfig; diff --git a/vips/vip-616/addresses/ethereum.ts b/vips/vip-616/addresses/ethereum.ts new file mode 100644 index 000000000..224b481bd --- /dev/null +++ b/vips/vip-616/addresses/ethereum.ts @@ -0,0 +1,124 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; + +import type { ChainConfig } from "../bscmainnet"; + +const { ethereum } = NETWORK_ADDRESSES; + +// Already-deployed governance + protocol addresses on Ethereum mainnet +export const ETHEREUM_ACM = ethereum.ACCESS_CONTROL_MANAGER; +export const ETHEREUM_GUARDIAN = ethereum.GUARDIAN; +export const ETHEREUM_NORMAL_TIMELOCK = ethereum.NORMAL_TIMELOCK; +export const ETHEREUM_FAST_TRACK_TIMELOCK = ethereum.FAST_TRACK_TIMELOCK; +export const ETHEREUM_CRITICAL_TIMELOCK = ethereum.CRITICAL_TIMELOCK; +export const ETHEREUM_CORE_COMPTROLLER = ethereum.CORE_COMPTROLLER; + +// Deployed via venus-periphery PR #65 (feat/VPD-1134) +export const ETHEREUM_DEVIATION_SENTINEL = "0x7D0EFA41eBF1aF242A37174E1E047bD6ea1b1B9c"; +export const ETHEREUM_EBRAKE = "0xCD09042c5DFFed762998Df9a058ec5944e39949B"; +export const ETHEREUM_SENTINEL_ORACLE = "0x444C53E194B40c272fAd683210e2cB1c16Ab132e"; +export const ETHEREUM_UNISWAP_ORACLE = "0x873993F8f5f5Ddbae0952e939ab3005Af363Af00"; +// Deployed via venus-periphery PR #66 — prices Curve StableSwap-NG assets that +// UniswapOracle can't read (eBTC/WBTC pool, etc.). +export const ETHEREUM_CURVE_ORACLE = "0x9F508F3146cb03276282f9237c6eE64f76E3261D"; +export const ETHEREUM_MULTISIG_PAUSER = "0xCCa5a587eBDBe80f23c8610F2e53B03158e62948"; // Venus team multisig +export const ETHEREUM_KEEPER = "0x57fa23f591203f61cef84a7bc892df69ca95c86e"; +export const ETHEREUM_CONFIGURATOR = "0x8E84b25144de0eA1d9D6E126b85769B60f4D604b"; + +// Reference token for eBTC's CurveOracle entry — see CurveOracle.sol for the pricing math. +const WBTC = "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"; + +export const ETHEREUM_DST_CHAIN_ID = LzChainId.ethereum; + +// Eligible Core Pool markets — Uniswap V3 sources except eBTC (CurveOracle). +// Unified 10% threshold. crvUSD and EIGEN are intentionally excluded per market spec. +export const ETHEREUM_MONITORED_MARKETS = [ + { + symbol: "WETH", + token: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + pool: "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // WETH/USDC Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "WBTC", + token: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + pool: "0x99ac8ca7087fa4a2a1fb6357269965a2014abc35", // WBTC/USDC Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "USDC", + token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + pool: "0x3416cf6c708da44db2624d63ea0aaef7113527c6", // USDC/USDT Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "USDT", + token: "0xdAC17F958D2ee523a2206206994597C13D831ec7", + pool: "0x3416cf6c708da44db2624d63ea0aaef7113527c6", // USDC/USDT Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "LBTC", + token: "0x8236a87084f8B84306f72007F36F2618A5634494", + pool: "0x87428a53e14d24ab19c6ca4939b4df93b8996ca9", // LBTC/WBTC Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "USDe", + token: "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3", + pool: "0xe6d7ebb9f1a9519dc06d557e03c522d53520e76a", // USDe/USDC Uniswap V3 + deviationPercent: 10, + }, + // eBTC routes through CurveOracle (eBTC/WBTC StableSwap-NG pool). + // coinIndex=0 (eBTC is coins[0]), refCoinIndex=1 (WBTC is coins[1]). + // assetDecimals=8 matches eBTC's ERC-20 decimals; get_dy probes 10^8 units. + { + symbol: "eBTC", + token: "0x657e8C867D8B37dCC18fA4Caead9C45EB088C642", + pool: "0x7704d01908afd31bf647d969c295bb45230cd2d6", + deviationPercent: 10, + oracleType: "curve" as const, + coinIndex: 0, + refCoinIndex: 1, + referenceToken: WBTC, + assetDecimals: 8, + }, + { + symbol: "DAI", + token: "0x6B175474E89094C44Da98b954EedeAC495271d0F", + pool: "0x5777d92f208679db4b9778590fa3cab3ac9e2168", // DAI/USDC Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "tBTC", + token: "0x18084fbA666a33d37592fA2633fD49a74DD93a88", + pool: "0x97944213d2caeea773da1c9b11b0525f25b749cc", // tBTC/WETH Uniswap V3 + deviationPercent: 10, + }, + { + symbol: "USDS", + token: "0xdC035D45d973E3EC169d2276DDab16f1e407384F", + pool: "0xe9f1e2ef814f5686c30ce6fb7103d0f780836c67", // USDS/DAI Uniswap V3 + deviationPercent: 10, + }, +]; + +export const ETHEREUM_CONFIG = { + name: "Ethereum", + dstChainId: ETHEREUM_DST_CHAIN_ID, + acm: ETHEREUM_ACM, + guardian: ETHEREUM_GUARDIAN, + normalTimelock: ETHEREUM_NORMAL_TIMELOCK, + fastTrackTimelock: ETHEREUM_FAST_TRACK_TIMELOCK, + criticalTimelock: ETHEREUM_CRITICAL_TIMELOCK, + comptroller: ETHEREUM_CORE_COMPTROLLER, + deviationSentinel: ETHEREUM_DEVIATION_SENTINEL, + eBrake: ETHEREUM_EBRAKE, + sentinelOracle: ETHEREUM_SENTINEL_ORACLE, + uniswapOracle: ETHEREUM_UNISWAP_ORACLE, + curveOracle: ETHEREUM_CURVE_ORACLE, + multisigPauser: ETHEREUM_MULTISIG_PAUSER, + keeper: ETHEREUM_KEEPER, + monitoredMarkets: ETHEREUM_MONITORED_MARKETS, + configurator: ETHEREUM_CONFIGURATOR, +} satisfies ChainConfig; diff --git a/vips/vip-616/addresses/sepolia.ts b/vips/vip-616/addresses/sepolia.ts new file mode 100644 index 000000000..9fc817124 --- /dev/null +++ b/vips/vip-616/addresses/sepolia.ts @@ -0,0 +1,67 @@ +import { NETWORK_ADDRESSES, ZERO_ADDRESS } from "src/networkAddresses"; +import { LzChainId } from "src/types"; + +const { sepolia } = NETWORK_ADDRESSES; + +// Already-deployed governance + protocol addresses on Sepolia +export const SEPOLIA_GUARDIAN_OWNER = "0xFEA1c651A47FE29dB9b1bf3cC1f224d8D9CFF68C"; // deployer EOA +export const SEPOLIA_ACM = sepolia.ACCESS_CONTROL_MANAGER; +export const SEPOLIA_GUARDIAN = sepolia.GUARDIAN; +export const SEPOLIA_NORMAL_TIMELOCK = sepolia.NORMAL_TIMELOCK; +export const SEPOLIA_FAST_TRACK_TIMELOCK = sepolia.FAST_TRACK_TIMELOCK; +export const SEPOLIA_CRITICAL_TIMELOCK = sepolia.CRITICAL_TIMELOCK; +export const SEPOLIA_CORE_COMPTROLLER = sepolia.CORE_COMPTROLLER; + +// Deployed via venus-periphery feat/VPD-1134 +export const SEPOLIA_DEVIATION_SENTINEL = "0x3a22AA95998a6c5f57e86E24fEA1503452Bdfa39"; +export const SEPOLIA_EBRAKE = "0x44784FBa07b5199a7a21C8A8E4a50c45137227BC"; +export const SEPOLIA_SENTINEL_ORACLE = "0xb5A87b6738C1cB2f1a1Acae8c49DbE32f8034CA5"; +// UniswapOracle not deployed on testnet — deviation testing uses SentinelOracle.setDirectPrice() +// instead of live DEX feeds. Ownership acceptance is skipped for ZERO_ADDRESS targets in the +// Sepolia VIP builder. +export const SEPOLIA_UNISWAP_ORACLE = ZERO_ADDRESS; + +// On Sepolia testnet the guardian EOA acts as both keeper and multisig pauser so that +// all emergency actions can be triggered manually after the VIP executes once. +export const SEPOLIA_MULTISIG_PAUSER = sepolia.GUARDIAN; +export const SEPOLIA_KEEPER = "0x2Ce1d0ffD7E869D9DF33e28552b12DdDed326706"; // same keeper as BSC testnet + +export const SEPOLIA_DST_CHAIN_ID = LzChainId.sepolia; + +// Underlying token addresses for the two monitored markets. +// Pools are ZERO_ADDRESS — testnet deviation is simulated via SentinelOracle.setDirectPrice(). +// The VIP-667 builder skips setPoolConfig / setTokenOracleConfig for markets with a zero pool. +const WBTC = "0x92A2928f5634BEa89A195e7BeCF0f0FEEDAB885b"; // MockWBTC on Sepolia + +export const SEPOLIA_MONITORED_MARKETS = [ + { + symbol: "WETH", + token: sepolia.WETH, + pool: ZERO_ADDRESS, + deviationPercent: 10, + }, + { + symbol: "WBTC", + token: WBTC, + pool: ZERO_ADDRESS, + deviationPercent: 10, + }, +]; + +export const SEPOLIA_CONFIG = { + name: "Sepolia", + dstChainId: SEPOLIA_DST_CHAIN_ID, + acm: SEPOLIA_ACM, + guardian: SEPOLIA_GUARDIAN, + normalTimelock: SEPOLIA_NORMAL_TIMELOCK, + fastTrackTimelock: SEPOLIA_FAST_TRACK_TIMELOCK, + criticalTimelock: SEPOLIA_CRITICAL_TIMELOCK, + comptroller: SEPOLIA_CORE_COMPTROLLER, + deviationSentinel: SEPOLIA_DEVIATION_SENTINEL, + eBrake: SEPOLIA_EBRAKE, + sentinelOracle: SEPOLIA_SENTINEL_ORACLE, + uniswapOracle: SEPOLIA_UNISWAP_ORACLE, + multisigPauser: SEPOLIA_MULTISIG_PAUSER, + keeper: SEPOLIA_KEEPER, + monitoredMarkets: SEPOLIA_MONITORED_MARKETS, +} as const; diff --git a/vips/vip-616/bscmainnet.ts b/vips/vip-616/bscmainnet.ts new file mode 100644 index 000000000..dd0ec4094 --- /dev/null +++ b/vips/vip-616/bscmainnet.ts @@ -0,0 +1,216 @@ +import { ZERO_ADDRESS } from "src/networkAddresses"; +import { Command, LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +import { ARBITRUMONE_CONFIG } from "./addresses/arbitrumone"; +import { BASEMAINNET_CONFIG } from "./addresses/basemainnet"; +import { ETHEREUM_CONFIG } from "./addresses/ethereum"; + +// --------------------------------------------------------------------------- +// Shared types + ACM permission constants. Exported for simulation use; the +// VIP itself only delegates into per-chain DeviationSentinelConfigurator.execute(). +// --------------------------------------------------------------------------- + +export type OracleType = "uniswap" | "curve" | "aerodrome"; + +export interface MonitoredMarket { + symbol: string; + token: string; + pool: string; + deviationPercent: number; + // Defaults to "uniswap" for the existing UniswapOracle path. "curve" routes through + // CurveOracle and requires coinIndex + refCoinIndex + referenceToken + assetDecimals; + // "aerodrome" routes through AerodromeSlipstreamOracle and uses the Uniswap-shaped (token, pool) signature. + oracleType?: OracleType; + // Curve-only: coins() index of the priced asset in the StableSwap-NG pool. + coinIndex?: number; + // Curve-only: coins() index of the reference asset (whose USD price ResilientOracle supplies). + refCoinIndex?: number; + // Curve-only: address of the reference asset. + referenceToken?: string; + // Curve-only: decimals of the priced asset (used to scale get_dy() output). + assetDecimals?: number; +} + +export interface ChainConfig { + name: string; + dstChainId: LzChainId; + acm: string; + guardian: string; + normalTimelock: string; + fastTrackTimelock: string; + criticalTimelock: string; + comptroller: string; + deviationSentinel: string; + eBrake: string; + sentinelOracle: string; + uniswapOracle: string; + curveOracle?: string; + aerodromeOracle?: string; + multisigPauser: string; + keeper: string; + monitoredMarkets: MonitoredMarket[]; + // Per-chain DeviationSentinelConfigurator address. ZERO_ADDRESS until deployed. + configurator: string; +} + +export const governanceAccounts = (cfg: ChainConfig): string[] => [ + cfg.guardian, + cfg.normalTimelock, + cfg.fastTrackTimelock, + cfg.criticalTimelock, +]; + +// setTokenConfig uses the struct-tuple form (uint8,bool), matching DeviationSentinel.sol. +export const SENTINEL_ADMIN_PERMS = [ + "setTrustedKeeper(address,bool)", + "setTokenConfig(address,(uint8,bool))", + "setTokenMonitoringEnabled(address,bool)", +]; + +// SentinelOracle access-controlled functions +export const SENTINEL_ORACLE_ADMIN_PERMS = ["setTokenOracleConfig(address,address)", "setDirectPrice(address,uint256)"]; + +// UniswapOracle access-controlled functions +export const UNISWAP_ORACLE_ADMIN_PERMS = ["setPoolConfig(address,address)"]; + +// CurveOracle access-controlled functions — distinct setPoolConfig signature +// (StableSwap-NG needs coinIndex + refCoinIndex + referenceToken + assetDecimals in addition to token + pool). +export const CURVE_ORACLE_ADMIN_PERMS = ["setPoolConfig(address,address,uint8,uint8,address,uint8)"]; + +// AerodromeSlipstreamOracle access-controlled functions — same shape as UniswapOracle. +export const AERODROME_ORACLE_ADMIN_PERMS = ["setPoolConfig(address,address)"]; + +// IL Comptroller permissions for EBrake. +// setActionsPaused uses uint256[] (not uint8[]) in the IL Comptroller. +export const EBRAKE_COMPTROLLER_PERMS_IL = [ + "setActionsPaused(address[],uint256[],bool)", + "setCollateralFactor(address,uint256,uint256)", + "setMarketBorrowCaps(address[],uint256[])", + "setMarketSupplyCaps(address[],uint256[])", +]; + +// Granular snapshot-reset functions governance Timelocks and Guardian can call on EBrake. +export const RESET_PERMS = [ + "resetCFSnapshot(address)", + "resetBorrowCapSnapshot(address)", + "resetSupplyCapSnapshot(address)", +]; + +// EBrake functions DeviationSentinel.handleDeviation invokes (single-arg decreaseCF +// is the IL-supported form). +export const SENTINEL_EBRAKE_PERMS = ["pauseBorrow(address)", "pauseSupply(address)", "decreaseCF(address,uint256)"]; + +// IL-supported subset of EBrake action functions granted to governance + multisig. +// Excludes: pauseFlashLoan(), disablePoolBorrow(uint96,address), +// revokeFlashLoanAccess(address), decreaseCF(address,uint96,uint256) — all revert +// on isIsolatedPool=true (they target Diamond-only Comptroller methods). +export const GOVERNANCE_EBRAKE_PERMS_IL = [ + "pauseSupply(address)", + "pauseRedeem(address)", + "pauseBorrow(address)", + "pauseTransfer(address)", + "pauseActions(address[],uint8[])", + "setMarketBorrowCaps(address[],uint256[])", + "setMarketSupplyCaps(address[],uint256[])", + "decreaseCF(address,uint256)", +]; + +// Diamond-only EBrake fns deliberately NOT granted on IL chains (would revert). +export const DIAMOND_ONLY_EBRAKE_PERMS = [ + "pauseFlashLoan()", + "disablePoolBorrow(uint96,address)", + "revokeFlashLoanAccess(address)", + "decreaseCF(address,uint96,uint256)", +]; + +// Per-chain configs are the single source of truth — see addresses/.ts. +// Adding a new chain only requires creating an addresses/.ts and +// extending this array. +const NETWORKS: ChainConfig[] = [ETHEREUM_CONFIG, ARBITRUMONE_CONFIG, BASEMAINNET_CONFIG]; + +const buildChainCommands = (cfg: ChainConfig): Command[] => { + if (cfg.configurator === ZERO_ADDRESS) { + throw new Error(`${cfg.name}: configurator address unset; deploy and update addresses/.ts.`); + } + + const { acm, dstChainId, configurator } = cfg; + + const ownershipTargets: string[] = [cfg.deviationSentinel, cfg.sentinelOracle, cfg.uniswapOracle, cfg.eBrake]; + if (cfg.curveOracle) ownershipTargets.push(cfg.curveOracle); + if (cfg.aerodromeOracle) ownershipTargets.push(cfg.aerodromeOracle); + + return [ + // Accept pending-ownership + ...ownershipTargets.map(target => ({ + target, + signature: "acceptOwnership()", + params: [], + dstChainId, + })), + + // Grant DEFAULT_ADMIN_ROLE on the local ACM so execute() can call giveCallPermission / + // revokeCallPermission (both internally call grantRole / revokeRole, which require + // DEFAULT_ADMIN_ROLE per OZ AccessControl). The configurator renounces this role at the + // very end of execute() via _selfRevokeACMPermissions(). + { + target: acm, + signature: "grantRole(bytes32,address)", + params: ["0x0000000000000000000000000000000000000000000000000000000000000000", configurator], + dstChainId, + }, + + // Apply all grants + market wiring atomically. See DeviationSentinelConfigurator.execute(). + { + target: configurator, + signature: "execute()", + params: [], + dstChainId, + }, + ]; +}; + +export const vip616 = () => { + const meta = { + version: "v2", + title: "VIP-616 [Ethereum, Arbitrum One, Base] Configure DeviationSentinel + EBrakeV2", + description: `#### Description + +This VIP configures the **DeviationSentinel** + **EBrakeV2** Emergency Brake stack on **Ethereum**, **Arbitrum One**, and **Base**, mirroring the BSC setup from VIP-590 + VIP-610. Each chain's DeviationSentinel routes automated oracle-deviation enforcement through a local EBrakeV2, which applies per-action, per-market restrictions (pause borrow/supply, zero collateral factor) without manual intervention. + +The full bootstrap — ownership transfer, ACM grants for Guardian + 3 Timelocks, EBrake action permissions, multisig-pauser permissions, trusted-keeper whitelisting, and per-market deviation wiring across UniswapOracle / CurveOracle / AerodromeSlipstreamOracle — is encoded inside a per-chain **DeviationSentinelConfigurator** contract deployed to venus-periphery. + +The on-chain VIP needs only to (1) accept ownership of the periphery contracts, (2) grant the configurator \`DEFAULT_ADMIN_ROLE\` on the local ACM (required by OZ \`grantRole\` / \`revokeRole\`, which both \`giveCallPermission\` and \`revokeCallPermission\` wrap internally), and (3) call \`configurator.execute()\`. The configurator applies every grant and wiring atomically, then renounces \`DEFAULT_ADMIN_ROLE\` at the very end, so it retires permanently in a single transaction with no follow-up cleanup VIP required. + +This packaging keeps the cross-chain payload tiny — well under LayerZero V1's RelayerV2 payload-size ceiling — without splitting the bootstrap across multiple VIPs. + +In addition to UniswapOracle, two extra DEX oracles are bootstrapped on the chains that need them: + +- **CurveOracle (Ethereum only)** — prices eBTC against WBTC via \`get_dy\` on the eBTC/WBTC Curve StableSwap-NG pool, which the existing UniswapOracle can't read (StableSwap-NG isn't Uniswap V3 ABI-compatible). +- **AerodromeSlipstreamOracle (Base only)** — prices cbBTC and wstETH on the most liquid Aerodrome Slipstream pools (cbBTC/USDC and wstETH/WETH). Aerodrome Slipstream's \`slot0()\` returns a 6-tuple (no \`feeProtocol\`) so the Solidity decoder reverts when read against the Uniswap V3 7-tuple ABI used by UniswapOracle. + +Because EBrake on these chains uses \`isIsolatedPool=true\` (single-pool IL Comptroller, not the BSC Diamond), only the IL-supported subset of EBrake action functions is granted. Diamond-only functions (\`pauseFlashLoan\`, \`disablePoolBorrow\`, \`revokeFlashLoanAccess\`, \`decreaseCF(address,uint96,uint256)\`) are omitted as they revert on IL comptrollers. + +#### Summary + +If approved, this VIP will, for each of Ethereum, Arbitrum One, and Base: + +- Accept governance ownership of **DeviationSentinel**, **SentinelOracle**, **UniswapOracle**, and **EBrakeV2** (plus **CurveOracle** on Ethereum and **AerodromeSlipstreamOracle** on Base) +- Grant the per-chain **DeviationSentinelConfigurator** \`DEFAULT_ADMIN_ROLE\` on the local ACM so \`execute()\` can call \`giveCallPermission\` / \`revokeCallPermission\` (both wrap OZ \`grantRole\` / \`revokeRole\`, which require that role). The configurator renounces \`DEFAULT_ADMIN_ROLE\` at the end of \`execute()\` so it retires permanently. +- Invoke \`configurator.execute()\`, which atomically applies all admin grants, EBrake permissions, multisig-pauser permissions, trusted-keeper whitelisting, and per-market deviation wiring at the unified 10% threshold (10 markets on Ethereum, 5 on Arbitrum One, 4 on Base) — and renounces its own \`DEFAULT_ADMIN_ROLE\` at the end + +#### References + +- [VIP-590 (BSC)](https://app.venus.io/governance/proposal/590) +- [VIP-610 (BSC)](https://app.venus.io/governance/proposal/610) +- [Original Proposal: Emergency Brake — Price Deviation Safeguard Mechanism](https://community.venus.io/t/proposal-emergency-brake-price-deviation-safeguard-mechanism/5668) +- [GitHub PR](https://github.com/VenusProtocol/vips/pull/702)`, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + + return makeProposal(NETWORKS.flatMap(buildChainCommands), meta, ProposalType.REGULAR); +}; + +export default vip616; diff --git a/vips/vip-616/bsctestnet.ts b/vips/vip-616/bsctestnet.ts new file mode 100644 index 000000000..79e5e66f2 --- /dev/null +++ b/vips/vip-616/bsctestnet.ts @@ -0,0 +1,119 @@ +import { Command, LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +import { SEPOLIA_CONFIG, SEPOLIA_GUARDIAN_OWNER } from "./addresses/sepolia"; +import { EBRAKE_COMPTROLLER_PERMS_IL, SENTINEL_EBRAKE_PERMS } from "./bscmainnet"; + +// ACM `giveCallPermission` command builder. Inlined here because this VIP is +// the only consumer — the mainnet VIP delegates all grants into the +// configurator helper and doesn't need it. +const grant = (acm: string, target: string, signature: string, account: string, dstChainId: LzChainId): Command => ({ + target: acm, + signature: "giveCallPermission(address,string,address)", + params: [target, signature, account], + dstChainId, +}); + +// Exported for simulation imports. +export const DEPLOYER_SENTINEL_ORACLE_PERMS = ["setDirectPrice(address,uint256)"]; +export const DEPLOYER_EBRAKE_PERMS = [ + "resetCFSnapshot(address)", + "resetBorrowCapSnapshot(address)", + "resetSupplyCapSnapshot(address)", +]; +export const DEPLOYER_COMPTROLLER_PERMS = [ + "setCollateralFactor(address,uint256,uint256)", + "setActionsPaused(address[],uint256[],bool)", +]; + +// Minimal single-VIP Sepolia testnet bootstrap for DeviationSentinel + EBrakeV2 E2E testing. +// +// Command count: 3 (ownership) + 2 (normalTimelock DS perms) + 4 (EBrake→Comptroller) +// + 3 (Sentinel→EBrake) + 2 (trusted keepers) + 6 (deployer extra) + 2 (market config) = 22 +// +// 22 × ~411 bytes ≈ 9.2 KB — under the LZ V1 testnet relayer 10 KB payload ceiling. +// +// The broader governance permission set (all 4 gov accounts × every sig) from the mainnet +// split is intentionally omitted: the LZ testnet relayer rejects payloads > ~10 KB, and +// those admin grants are not needed to drive the E2E deviation → pause → reset flow. +export const vip666Sepolia = () => { + const cfg = SEPOLIA_CONFIG; + const { acm, dstChainId } = cfg; + + const meta = { + version: "v2", + title: "VIP-666 [Sepolia] DeviationSentinel + EBrakeV2 — Minimal E2E Bootstrap", + description: `#### Summary + +One-time Sepolia testnet VIP to wire the **DeviationSentinel** + **EBrakeV2** stack for E2E deviation testing. + +Since Sepolia has no live DEX feeds, price deviation is simulated via \`SentinelOracle.setDirectPrice()\`. Only the permissions strictly needed for the E2E test cycle are granted; the full governance admin set from the mainnet VIPs is omitted to stay within the LZ testnet relayer payload limit (~10 KB). + +**E2E test cycle after this VIP:** +1. Deployer calls \`SentinelOracle.setDirectPrice(token, artificialPrice)\` +2. Deployer calls \`DeviationSentinel.handleDeviation(vToken)\` as trusted keeper → EBrake pauses the market +3. Deployer calls \`EBrake.resetCFSnapshot / resetBorrowCapSnapshot / resetSupplyCapSnapshot\` +4. Deployer calls \`Comptroller.setCollateralFactor\` / \`setActionsPaused\` to restore state`, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + + return makeProposal( + [ + // 1. Accept ownership of the three deployed contracts. + // UniswapOracle is ZERO_ADDRESS on Sepolia — skip. + { target: cfg.deviationSentinel, signature: "acceptOwnership()", params: [], dstChainId }, + { target: cfg.sentinelOracle, signature: "acceptOwnership()", params: [], dstChainId }, + { target: cfg.eBrake, signature: "acceptOwnership()", params: [], dstChainId }, + + // 2. Grant Normal Timelock the two DeviationSentinel functions it calls later in this VIP. + // These grants must precede the setTrustedKeeper and setTokenConfig calls below. + grant(acm, cfg.deviationSentinel, "setTrustedKeeper(address,bool)", cfg.normalTimelock, dstChainId), + grant(acm, cfg.deviationSentinel, "setTokenConfig(address,(uint8,bool))", cfg.normalTimelock, dstChainId), + + // 3. Grant EBrake the IL-supported emergency-action permissions on the Comptroller. (4) + ...EBRAKE_COMPTROLLER_PERMS_IL.map(sig => grant(acm, cfg.comptroller, sig, cfg.eBrake, dstChainId)), + + // 4. Grant DeviationSentinel the three EBrake functions handleDeviation invokes. (3) + ...SENTINEL_EBRAKE_PERMS.map(sig => grant(acm, cfg.eBrake, sig, cfg.deviationSentinel, dstChainId)), + + // 5. Whitelist trusted keepers. (2) + // - SEPOLIA_GUARDIAN_OWNER (deployer EOA): drives the manual E2E test cycle + // - cfg.keeper (= on-chain Guardian): standard keeper backup + { + target: cfg.deviationSentinel, + signature: "setTrustedKeeper(address,bool)", + params: [SEPOLIA_GUARDIAN_OWNER, true], + dstChainId, + }, + { + target: cfg.deviationSentinel, + signature: "setTrustedKeeper(address,bool)", + params: [cfg.keeper, true], + dstChainId, + }, + + // 6. Grant deployer EOA the extra permissions needed to drive the full E2E test cycle. (6) + ...DEPLOYER_SENTINEL_ORACLE_PERMS.map(sig => + grant(acm, cfg.sentinelOracle, sig, SEPOLIA_GUARDIAN_OWNER, dstChainId), + ), + ...DEPLOYER_EBRAKE_PERMS.map(sig => grant(acm, cfg.eBrake, sig, SEPOLIA_GUARDIAN_OWNER, dstChainId)), + ...DEPLOYER_COMPTROLLER_PERMS.map(sig => grant(acm, cfg.comptroller, sig, SEPOLIA_GUARDIAN_OWNER, dstChainId)), + + // 7. Enable deviation monitoring (10% threshold) for WETH and WBTC. (2) + // setPoolConfig / setTokenOracleConfig are skipped — no live DEX pools on Sepolia; + // prices are injected manually via SentinelOracle.setDirectPrice(). + ...cfg.monitoredMarkets.map(market => ({ + target: cfg.deviationSentinel, + signature: "setTokenConfig(address,(uint8,bool))", + params: [market.token, [market.deviationPercent, true]], + dstChainId, + })), + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip666Sepolia;