diff --git a/simulations/vip-658/abi/AccessControlManager.json b/simulations/vip-658/abi/AccessControlManager.json new file mode 100644 index 000000000..4a118fcc4 --- /dev/null +++ b/simulations/vip-658/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-658/abi/AerodromeSlipstreamOracle.json b/simulations/vip-658/abi/AerodromeSlipstreamOracle.json new file mode 100644 index 000000000..8c682078e --- /dev/null +++ b/simulations/vip-658/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-658/abi/Comptroller.json b/simulations/vip-658/abi/Comptroller.json new file mode 100644 index 000000000..4a4960dbc --- /dev/null +++ b/simulations/vip-658/abi/Comptroller.json @@ -0,0 +1,15 @@ +[ + { + "inputs": [], + "name": "getAllMarkets", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-658/abi/CurveOracle.json b/simulations/vip-658/abi/CurveOracle.json new file mode 100644 index 000000000..00e518859 --- /dev/null +++ b/simulations/vip-658/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-658/abi/DeviationSentinel.json b/simulations/vip-658/abi/DeviationSentinel.json new file mode 100644 index 000000000..c12ea017a --- /dev/null +++ b/simulations/vip-658/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-658/abi/ILComptroller.json b/simulations/vip-658/abi/ILComptroller.json new file mode 100644 index 000000000..d1801efd8 --- /dev/null +++ b/simulations/vip-658/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-658/abi/ResilientOracle.json b/simulations/vip-658/abi/ResilientOracle.json new file mode 100644 index 000000000..35f52caa0 --- /dev/null +++ b/simulations/vip-658/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-658/abi/SentinelOracle.json b/simulations/vip-658/abi/SentinelOracle.json new file mode 100644 index 000000000..7c9930f95 --- /dev/null +++ b/simulations/vip-658/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-658/abi/UniswapOracle.json b/simulations/vip-658/abi/UniswapOracle.json new file mode 100644 index 000000000..66770c861 --- /dev/null +++ b/simulations/vip-658/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-658/abi/VToken.json b/simulations/vip-658/abi/VToken.json new file mode 100644 index 000000000..a4a285256 --- /dev/null +++ b/simulations/vip-658/abi/VToken.json @@ -0,0 +1,15 @@ +[ + { + "inputs": [], + "name": "underlying", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-658/arbitrumone.ts b/simulations/vip-658/arbitrumone.ts new file mode 100644 index 000000000..1d938d27d --- /dev/null +++ b/simulations/vip-658/arbitrumone.ts @@ -0,0 +1,42 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip658, { ARBITRUMONE_CTX } from "../../vips/vip-658/bscmainnet"; +import { + TestConfig, + buildPostExecutionEventChecks, + runCommandCountAssertion, + runConfigSanity, + runPostVipAssertions, + runPreVipAssertions, +} from "./shared"; + +// Recent Arbitrum One block (node-supported, used by recent VIP sims). USDC / USD₮0 +// wired at 1%, WBTC at 3%, ARB at 10% (VIP-616 wire, left as-is by VIP-624). +const FORK_BLOCK = 474085204; + +const a = NETWORK_ADDRESSES.arbitrumone; + +// Structural pre/post-VIP + event-count assertions only (no trip-behavior tests — see shared.ts). +const TEST_CONFIG: TestConfig = { + ctx: ARBITRUMONE_CTX, + resilientOracle: a.RESILIENT_ORACLE, + timelock: a.NORMAL_TIMELOCK, + comptrollers: [{ address: a.CORE_COMPTROLLER, type: "il" }], +}; + +forking(FORK_BLOCK, async () => { + runConfigSanity(TEST_CONFIG); + runCommandCountAssertion(ARBITRUMONE_CTX, 7); + runPreVipAssertions(TEST_CONFIG); + + testForkedNetworkVipCommands( + "VIP-658 [Arbitrum One] DeviationSentinel 2026-08 Parameter Adjustment", + await vip658(), + { + callbackAfterExecution: buildPostExecutionEventChecks(ARBITRUMONE_CTX), + }, + ); + + runPostVipAssertions(TEST_CONFIG); +}); diff --git a/simulations/vip-658/basemainnet.ts b/simulations/vip-658/basemainnet.ts new file mode 100644 index 000000000..c06199017 --- /dev/null +++ b/simulations/vip-658/basemainnet.ts @@ -0,0 +1,39 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip658, { BASEMAINNET_CTX } from "../../vips/vip-658/bscmainnet"; +import { + TestConfig, + buildPostExecutionEventChecks, + runCommandCountAssertion, + runConfigSanity, + runPostVipAssertions, + runPreVipAssertions, +} from "./shared"; + +// Recent Base block (post the Base Guardian's block-50298851 USDC retune, so the +// pre-VIP assertions validate live state). USDC / cbBTC / wstETH all wired at 3% +// on-chain here. No pool changes on Base. +const FORK_BLOCK = 50503680; + +const a = NETWORK_ADDRESSES.basemainnet; + +// Structural pre/post-VIP + event-count assertions only (no trip-behavior tests — see shared.ts). +const TEST_CONFIG: TestConfig = { + ctx: BASEMAINNET_CTX, + resilientOracle: a.RESILIENT_ORACLE, + timelock: a.NORMAL_TIMELOCK, + comptrollers: [{ address: a.CORE_COMPTROLLER, type: "il" }], +}; + +forking(FORK_BLOCK, async () => { + runConfigSanity(TEST_CONFIG); + runCommandCountAssertion(BASEMAINNET_CTX, 3); + runPreVipAssertions(TEST_CONFIG); + + testForkedNetworkVipCommands("VIP-658 [Base] DeviationSentinel 2026-08 Parameter Adjustment", await vip658(), { + callbackAfterExecution: buildPostExecutionEventChecks(BASEMAINNET_CTX), + }); + + runPostVipAssertions(TEST_CONFIG); +}); diff --git a/simulations/vip-658/bscmainnet.ts b/simulations/vip-658/bscmainnet.ts new file mode 100644 index 000000000..b89c2d93b --- /dev/null +++ b/simulations/vip-658/bscmainnet.ts @@ -0,0 +1,44 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { forking, testVip } from "src/vip-framework"; + +import vip658, { BSC_CTX } from "../../vips/vip-658/bscmainnet"; +import { + TestConfig, + buildPostExecutionEventChecks, + runCommandCountAssertion, + runConfigSanity, + runDisableBehaviorTests, + runPostVipAssertions, + runPreVipAssertions, +} from "./shared"; + +// Near BSC head (2026-08-26). All in-scope BSC markets are wired per the V2 doc's +// "current" column; DAI is already disabled (VIP-644) and TUSD is still enabled. +const FORK_BLOCK = 118190000; + +const a = NETWORK_ADDRESSES.bscmainnet; + +// Trusted keeper on the DeviationSentinel (verified on-chain, same as VIP-644) — +// used to prove that TUSD's market can no longer be acted on once disabled. +const GUARDIAN = "0x1C2CAc6ec528c20800B2fe734820D87b581eAA6B"; + +const TEST_CONFIG: TestConfig = { + ctx: BSC_CTX, + resilientOracle: a.RESILIENT_ORACLE, + timelock: a.NORMAL_TIMELOCK, + comptrollers: [{ address: a.UNITROLLER, type: "core" }], + keeper: GUARDIAN, // proves the disabled TUSD market reverts handleDeviation +}; + +forking(FORK_BLOCK, async () => { + runConfigSanity(TEST_CONFIG); + runCommandCountAssertion(BSC_CTX, 14); + runPreVipAssertions(TEST_CONFIG); + + testVip("VIP-658 [BSC] DeviationSentinel 2026-08 Parameter Adjustment", await vip658(), { + callbackAfterExecution: buildPostExecutionEventChecks(BSC_CTX), + }); + + runPostVipAssertions(TEST_CONFIG); + runDisableBehaviorTests(TEST_CONFIG); +}); diff --git a/simulations/vip-658/ethereum.ts b/simulations/vip-658/ethereum.ts new file mode 100644 index 000000000..e66ec954d --- /dev/null +++ b/simulations/vip-658/ethereum.ts @@ -0,0 +1,41 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip658, { ETHEREUM_CTX } from "../../vips/vip-658/bscmainnet"; +import { + TestConfig, + buildPostExecutionEventChecks, + runCommandCountAssertion, + runConfigSanity, + runPostVipAssertions, + runPreVipAssertions, +} from "./shared"; + +// All in-scope markets are wired per the V2 doc's "current" column (sUSDe / sUSDS were +// wired by VIP-624; WETH stays at 10%). Uses a block where the LayerZero receive library +// on the fork is valid (blocks nearer head hit "invalid default library" in receivePayload). +const FORK_BLOCK = 25590000; + +const a = NETWORK_ADDRESSES.ethereum; + +// Trip-behavior (checkPriceDeviation) tests are intentionally not run here — see the +// note in shared.ts. Only structural pre/post-VIP + event-count assertions run on the +// remote chains, so no oracle/vToken behavior-test fields are needed. +const TEST_CONFIG: TestConfig = { + ctx: ETHEREUM_CTX, + resilientOracle: a.RESILIENT_ORACLE, + timelock: a.NORMAL_TIMELOCK, + comptrollers: [{ address: a.CORE_COMPTROLLER, type: "il" }], +}; + +forking(FORK_BLOCK, async () => { + runConfigSanity(TEST_CONFIG); + runCommandCountAssertion(ETHEREUM_CTX, 26); + runPreVipAssertions(TEST_CONFIG); + + testForkedNetworkVipCommands("VIP-658 [Ethereum] DeviationSentinel 2026-08 Parameter Adjustment", await vip658(), { + callbackAfterExecution: buildPostExecutionEventChecks(ETHEREUM_CTX), + }); + + runPostVipAssertions(TEST_CONFIG); +}); diff --git a/simulations/vip-658/shared.ts b/simulations/vip-658/shared.ts new file mode 100644 index 000000000..c3f153d5b --- /dev/null +++ b/simulations/vip-658/shared.ts @@ -0,0 +1,506 @@ +import { TransactionResponse } from "@ethersproject/providers"; +import { expect } from "chai"; +import { BigNumber, Contract } from "ethers"; +import { ethers } from "hardhat"; +import { ZERO_ADDRESS } from "src/networkAddresses"; +import { expectEvents, initMainnetUser } from "src/utils"; + +import { buildAllCommands, dexOracleFor } from "../../vips/vip-658/bscmainnet"; +import type { ChainContext, MarketEntry } from "../../vips/vip-658/config"; +import ACM_ABI from "./abi/AccessControlManager.json"; +import AERODROME_ORACLE_ABI from "./abi/AerodromeSlipstreamOracle.json"; +import COMPTROLLER_ABI from "./abi/Comptroller.json"; +import CURVE_ORACLE_ABI from "./abi/CurveOracle.json"; +import DEVIATION_SENTINEL_ABI from "./abi/DeviationSentinel.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"; + +// ────────────────────────────────────────────────────────────────────────── +// Test-only chain config: addresses needed to run live behavior tests. +// Kept separate from ChainContext so VIP runtime types don't carry test-only +// fields. Each entry file (`bscmainnet.ts`, `ethereum.ts`, …) builds one of +// these and hands it to the suite helpers. +// ────────────────────────────────────────────────────────────────────────── + +export interface TestConfig { + ctx: ChainContext; + resilientOracle: string; + timelock: string; // governance timelock — already permissioned for all relevant setters + // Pools we walk to map underlying → vToken. BSC has the Diamond Unitroller (Core Pool); + // remote chains use one or more IL Comptrollers. + comptrollers: { address: string; type: "core" | "il" }[]; + // Keeper permitted to call handleDeviation (BSC only) — used to prove a disabled market reverts. + keeper?: string; +} + +// ────────────────────────────────────────────────────────────────────────── +// Internal helpers +// ────────────────────────────────────────────────────────────────────────── + +// DEX-oracle address for a market — reuses the proposal builder's resolver so the +// simulation checks against exactly the address the VIP targets. +const dexOracleAddress = dexOracleFor; + +const dexOracleAbi = (m: MarketEntry) => { + // BSC's PancakeSwapOracle shares the UniswapOracle ABI (same setPoolConfig / + // PoolConfigUpdated shape), so one Uniswap ABI covers every "uniswap" market. + const t = m.oracleType ?? "uniswap"; + if (t === "uniswap") return UNISWAP_ORACLE_ABI; + if (t === "curve") return CURVE_ORACLE_ABI; + return AERODROME_ORACLE_ABI; +}; + +// Pre-VIP `enabled` flag: a wired-but-disabled market (e.g. BSC DAI) sets it explicitly. +const currentEnabled = (m: MarketEntry): boolean => m.currentEnabled ?? m.currentPct > 0; + +interface Partitioned { + retunes: MarketEntry[]; // setTokenConfig only (threshold change) + poolSwaps: MarketEntry[]; // pool + oracle + setTokenConfig (rebind + retune) + poolOnly: MarketEntry[]; // pool + oracle (threshold left unchanged) + disables: MarketEntry[]; // setTokenMonitoringEnabled(token, false) + skips: MarketEntry[]; // no on-chain action +} + +const partition = (markets: MarketEntry[]): Partitioned => ({ + retunes: markets.filter(m => m.action === "retune"), + poolSwaps: markets.filter(m => m.action === "poolSwap"), + poolOnly: markets.filter(m => m.action === "poolOnly"), + disables: markets.filter(m => m.action === "disable"), + skips: markets.filter(m => m.action === "skip"), +}); + +// Markets that write a pool config (the pool always changes for these). +const poolWriteMarkets = (p: Partitioned): MarketEntry[] => [...p.poolSwaps, ...p.poolOnly]; +// Markets that write a SentinelOracle repoint (all pool-writers except the verified no-ops). +const oracleRepointMarkets = (p: Partitioned): MarketEntry[] => poolWriteMarkets(p).filter(m => !m.skipOracleRepoint); +// Markets that write a DeviationSentinel threshold (setTokenConfig). +const thresholdWriteMarkets = (p: Partitioned): MarketEntry[] => [...p.retunes, ...p.poolSwaps]; + +const V3_POOL_ABI = ["function token0() view returns (address)", "function token1() view returns (address)"]; +const ERC20_DECIMALS_ABI = ["function decimals() view returns (uint8)"]; +const BPS_SCALE = 10_000; +const MAX_BASELINE_DEVIATION_BPS = 100; // 1% — catches wrong sides/decimals without pinning exact spot prices + +interface ChainContracts { + deviationSentinel: Contract; + sentinelOracle: Contract; + resilientOracle: Contract; +} + +const buildContracts = async (cfg: TestConfig): Promise => ({ + deviationSentinel: await ethers.getContractAt(DEVIATION_SENTINEL_ABI, cfg.ctx.deviationSentinel), + sentinelOracle: await ethers.getContractAt(SENTINEL_ORACLE_ABI, cfg.ctx.sentinelOracle), + resilientOracle: await ethers.getContractAt(RESILIENT_ORACLE_ABI, cfg.resilientOracle), +}); + +// Walks every configured comptroller and returns a lowercase-underlying → vToken map. +const buildVTokenIndex = async (cfg: TestConfig): Promise> => { + const map = new Map(); + for (const c of cfg.comptrollers) { + const abi = c.type === "core" ? COMPTROLLER_ABI : IL_COMPTROLLER_ABI; + const comptroller = await ethers.getContractAt(abi, c.address); + const vTokens: string[] = await comptroller.getAllMarkets(); + for (const vToken of vTokens) { + try { + const v = await ethers.getContractAt(VTOKEN_ABI, vToken); + const underlying: string = await v.underlying(); + // first-write-wins: if a token appears in multiple pools, we keep the first vToken found + const key = underlying.toLowerCase(); + if (!map.has(key)) map.set(key, vToken); + } catch { + // native-token vTokens (vBNB, vETH) don't expose underlying() — skip + } + } + } + return map; +}; + +// Equality on the (deviation, enabled) tuple returned by tokenConfigs. +const expectTokenConfig = async ( + deviationSentinel: Contract, + token: string, + expectedPct: number, + expectedEnabled: boolean, + ctx: string, +) => { + const tc = await deviationSentinel.tokenConfigs(token); + expect(tc.deviation, `${ctx}: deviation`).to.equal(expectedPct); + expect(tc.enabled, `${ctx}: enabled`).to.equal(expectedEnabled); +}; + +// Assert SentinelOracle routes `token` to `expectedOracle` (tokenConfigs(token).oracle). +const expectSentinelRoutesTo = async (sentinelOracle: Contract, token: string, expectedOracle: string, ctx: string) => { + const tc = await sentinelOracle.tokenConfigs(token); + const actual = tc.oracle ?? tc; + expect(ethers.utils.getAddress(actual), `${ctx}: sentinel oracle entry`).to.equal( + ethers.utils.getAddress(expectedOracle), + ); +}; + +const absoluteDifference = (a: BigNumber, b: BigNumber): BigNumber => (a.gte(b) ? a.sub(b) : b.sub(a)); + +const configureTargetPricePath = async (cfg: TestConfig, c: ChainContracts, m: MarketEntry) => { + const timelock = await initMainnetUser(cfg.timelock, ethers.utils.parseEther("1")); + const dexOracle = await ethers.getContractAt(dexOracleAbi(m), dexOracleAddress(cfg.ctx, m)); + + if (m.oracleType === "curve") { + await dexOracle + .connect(timelock) + .setPoolConfig(m.token, m.pool, m.coinIndex, m.refCoinIndex, m.referenceToken, m.assetDecimals); + } else { + await dexOracle.connect(timelock).setPoolConfig(m.token, m.pool); + } + await c.sentinelOracle.connect(timelock).setTokenOracleConfig(m.token, dexOracleAddress(cfg.ctx, m)); + + return dexOracle; +}; + +// ────────────────────────────────────────────────────────────────────────── +// Config sanity — guards the hand-entered tables in addresses/.ts. +// ────────────────────────────────────────────────────────────────────────── + +export const runConfigSanity = (cfg: TestConfig) => { + const { ctx } = cfg; + const p = partition(ctx.markets); + + describe(`VIP-658 [${ctx.name}] — Config sanity`, () => { + it("every market has well-formed token, pool, and threshold fields", () => { + for (const m of ctx.markets) { + expect(m.token.length, `${m.symbol}: token not 20 bytes`).to.equal(42); + expect(m.pool.length, `${m.symbol}: pool not 20 bytes`).to.equal(42); + // skip / disable markets may carry placeholder pools; they emit no pool command. + if (m.action !== "skip" && m.action !== "disable") { + expect(m.token, `${m.symbol}: token is ZERO_ADDRESS`).to.not.equal(ZERO_ADDRESS); + expect(m.pool, `${m.symbol}: pool is ZERO_ADDRESS`).to.not.equal(ZERO_ADDRESS); + expect(m.targetPct, `${m.symbol}: targetPct must be > 0`).to.be.greaterThan(0); + expect(m.targetPct, `${m.symbol}: targetPct must be ≤ 100`).to.be.lessThanOrEqual(100); + } + } + }); + + it("threshold-write markets target 5% (unified tier)", () => { + // Every retune / poolSwap in this VIP moves to the unified 5% tier. + for (const m of thresholdWriteMarkets(p)) { + expect(m.targetPct, `${m.symbol}: targetPct`).to.equal(5); + } + }); + + it("poolOnly markets keep their threshold (targetPct == currentPct)", () => { + for (const m of p.poolOnly) { + expect(m.targetPct, `${m.symbol}: targetPct should equal currentPct`).to.equal(m.currentPct); + } + }); + + it("curve markets carry all StableSwap params", () => { + for (const m of ctx.markets) { + if (m.oracleType !== "curve" || m.action === "skip" || m.action === "disable") continue; + expect(m.coinIndex, `${m.symbol}: coinIndex`).to.not.be.undefined; + expect(m.refCoinIndex, `${m.symbol}: refCoinIndex`).to.not.be.undefined; + expect(m.referenceToken, `${m.symbol}: referenceToken`).to.not.be.undefined; + expect(m.assetDecimals, `${m.symbol}: assetDecimals`).to.not.be.undefined; + } + }); + }); +}; + +// ────────────────────────────────────────────────────────────────────────── +// Pre-VIP assertions — snapshot the on-chain baseline before the proposal runs. +// ────────────────────────────────────────────────────────────────────────── + +export const runPreVipAssertions = (cfg: TestConfig) => { + const p = partition(cfg.ctx.markets); + + describe(`VIP-658 [${cfg.ctx.name}] — Pre-VIP state`, () => { + let c: ChainContracts; + let vTokenByUnderlying: Map; + + before(async () => { + c = await buildContracts(cfg); + vTokenByUnderlying = await buildVTokenIndex(cfg); + }); + + for (const m of p.retunes) { + it(`${m.symbol}: configured at ${m.currentPct}%, enabled`, async () => { + await expectTokenConfig(c.deviationSentinel, m.token, m.currentPct, true, m.symbol); + }); + } + + for (const m of [...p.poolSwaps, ...p.poolOnly]) { + it(`${m.symbol}: currently wired at ${m.currentPct}% (oracle will repoint)`, async () => { + await expectTokenConfig(c.deviationSentinel, m.token, m.currentPct, true, m.symbol); + }); + + // Where we elide the SentinelOracle repoint as a no-op, prove the current binding + // already equals the target DEX oracle — otherwise the elision would leave it wrong. + if (m.skipOracleRepoint) { + it(`${m.symbol}: SentinelOracle already routes to the target DEX oracle (elided repoint)`, async () => { + await expectSentinelRoutesTo(c.sentinelOracle, m.token, dexOracleAddress(cfg.ctx, m), m.symbol); + }); + } + } + + for (const m of p.disables) { + it(`${m.symbol}: currently monitored at ${m.currentPct}% (will disable)`, async () => { + await expectTokenConfig(c.deviationSentinel, m.token, m.currentPct, currentEnabled(m), m.symbol); + expect(currentEnabled(m), `${m.symbol}: expected enabled pre-VIP`).to.equal(true); + }); + } + + // Configure each target pool and route inside a snapshot while oracle feeds are + // fresh, then roll the state back. The full VIP simulation below independently + // proves that the emitted governance commands produce the same stored config. + for (const m of poolWriteMarkets(p)) { + it(`${m.symbol}: target pool supports the full DeviationSentinel price path`, async () => { + const snapshot = await ethers.provider.send("evm_snapshot", []); + + try { + const dexOracle = await configureTargetPricePath(cfg, c, m); + const directPrice = await c.sentinelOracle.directPrices(m.token); + expect(directPrice, `${m.symbol}: direct price bypasses the configured DEX oracle`).to.equal(0); + + const dexPrice = await dexOracle.getPrice(m.token); + const sentinelPrice = await c.sentinelOracle.getPrice(m.token); + const resilientPrice = await c.resilientOracle.getPrice(m.token); + + expect(dexPrice, `${m.symbol}: DEX oracle price`).to.be.gt(0); + expect(sentinelPrice, `${m.symbol}: SentinelOracle price`).to.equal(dexPrice); + expect(resilientPrice, `${m.symbol}: ResilientOracle price`).to.be.gt(0); + + const deviationBps = absoluteDifference(sentinelPrice, resilientPrice).mul(BPS_SCALE).div(resilientPrice); + expect(deviationBps, `${m.symbol}: Sentinel/Resilient baseline deviation (bps)`).to.be.lt( + MAX_BASELINE_DEVIATION_BPS, + ); + + const vToken = vTokenByUnderlying.get(m.token.toLowerCase()); + expect(vToken, `${m.symbol}: no listed Venus market found for the pool-write asset`).to.not.be.undefined; + + const [hasDeviation, oraclePrice, checkedSentinelPrice, deviationPercent] = + await c.deviationSentinel.checkPriceDeviation(vToken); + expect(oraclePrice, `${m.symbol}: DeviationSentinel oraclePrice`).to.equal(resilientPrice); + expect(checkedSentinelPrice, `${m.symbol}: DeviationSentinel sentinelPrice`).to.equal(sentinelPrice); + expect(deviationPercent, `${m.symbol}: deviationPercent`).to.be.lt(m.currentPct); + expect(hasDeviation, `${m.symbol}: target pool would immediately trigger the sentinel`).to.equal(false); + } finally { + expect(await ethers.provider.send("evm_revert", [snapshot]), `${m.symbol}: snapshot revert`).to.equal(true); + } + }); + } + }); +}; + +// ────────────────────────────────────────────────────────────────────────── +// Post-VIP assertions — final state per market, plus skip-market untouched-diff. +// ────────────────────────────────────────────────────────────────────────── + +interface StateSnapshot { + symbol: string; + token: string; + deviation: number; + enabled: boolean; +} + +export const runPostVipAssertions = (cfg: TestConfig) => { + const p = partition(cfg.ctx.markets); + + describe(`VIP-658 [${cfg.ctx.name}] — Post-VIP state`, () => { + let c: ChainContracts; + let skipSnapshots: StateSnapshot[]; + + before(async () => { + c = await buildContracts(cfg); + skipSnapshots = await Promise.all( + p.skips.map(async m => { + const tc = await c.deviationSentinel.tokenConfigs(m.token); + return { symbol: m.symbol, token: m.token, deviation: tc.deviation, enabled: tc.enabled }; + }), + ); + }); + + for (const m of p.retunes) { + it(`${m.symbol}: threshold now ${m.targetPct}%, still enabled`, async () => { + await expectTokenConfig(c.deviationSentinel, m.token, m.targetPct, true, m.symbol); + }); + } + + for (const m of poolWriteMarkets(p)) { + const oracleType = m.oracleType ?? "uniswap"; + + it(`${m.symbol}: pool registered on routed DEX oracle (${oracleType})`, async () => { + const oracle = await ethers.getContractAt(dexOracleAbi(m), dexOracleAddress(cfg.ctx, m)); + if (oracleType === "curve") { + const pc = await oracle.poolConfigs(m.token); + expect(ethers.utils.getAddress(pc.pool), `${m.symbol}: pool`).to.equal(ethers.utils.getAddress(m.pool)); + expect(pc.coinIndex, `${m.symbol}: coinIndex`).to.equal(m.coinIndex); + expect(pc.refCoinIndex, `${m.symbol}: refCoinIndex`).to.equal(m.refCoinIndex); + expect(ethers.utils.getAddress(pc.referenceToken), `${m.symbol}: referenceToken`).to.equal( + ethers.utils.getAddress(m.referenceToken as string), + ); + expect(pc.assetDecimals, `${m.symbol}: assetDecimals`).to.equal(m.assetDecimals); + } else { + const actualPool = await oracle.tokenPools(m.token); + expect(ethers.utils.getAddress(actualPool), `${m.symbol}: pool`).to.equal(ethers.utils.getAddress(m.pool)); + } + }); + + it(`${m.symbol}: SentinelOracle routes to the new DEX oracle`, async () => { + await expectSentinelRoutesTo(c.sentinelOracle, m.token, dexOracleAddress(cfg.ctx, m), m.symbol); + }); + + if (oracleType === "curve") { + it(`${m.symbol}: Curve pool.coins() matches stored coin indexes`, async () => { + const pool = new ethers.Contract(m.pool, ["function coins(uint256) view returns (address)"], ethers.provider); + const token = new ethers.Contract(m.token, ERC20_DECIMALS_ABI, ethers.provider); + const priced = await pool.coins(m.coinIndex as number); + const ref = await pool.coins(m.refCoinIndex as number); + expect(ethers.utils.getAddress(priced), `${m.symbol}: pool.coins(coinIndex)`).to.equal( + ethers.utils.getAddress(m.token), + ); + expect(ethers.utils.getAddress(ref), `${m.symbol}: pool.coins(refCoinIndex)`).to.equal( + ethers.utils.getAddress(m.referenceToken as string), + ); + expect(await token.decimals(), `${m.symbol}: assetDecimals`).to.equal(m.assetDecimals); + }); + } else { + it(`${m.symbol}: target token is present in the V3-compatible pool`, async () => { + const pool = new ethers.Contract(m.pool, V3_POOL_ABI, ethers.provider); + const tokens = [await pool.token0(), await pool.token1()].map(token => token.toLowerCase()); + expect(tokens, `${m.symbol}: target token is neither token0 nor token1`).to.include(m.token.toLowerCase()); + }); + } + } + + // poolSwap: threshold set to targetPct, enabled. + for (const m of p.poolSwaps) { + it(`${m.symbol}: DeviationSentinel threshold ${m.targetPct}%, enabled`, async () => { + await expectTokenConfig(c.deviationSentinel, m.token, m.targetPct, true, m.symbol); + }); + } + + // poolOnly: threshold left unchanged (== currentPct), still enabled. + for (const m of p.poolOnly) { + it(`${m.symbol}: threshold unchanged at ${m.currentPct}%, still enabled (pool-only)`, async () => { + await expectTokenConfig(c.deviationSentinel, m.token, m.currentPct, true, m.symbol); + }); + } + + // disable: monitoring off, stored deviation preserved. + for (const m of p.disables) { + it(`${m.symbol}: monitoring disabled, deviation config preserved (${m.currentPct}%)`, async () => { + await expectTokenConfig(c.deviationSentinel, m.token, m.currentPct, false, m.symbol); + }); + } + + // Skip markets: assert each one's tokenConfigs survived the VIP unchanged. + for (const m of p.skips) { + it(`${m.symbol} (skip): tokenConfigs untouched by VIP`, async () => { + const snap = skipSnapshots.find(s => s.token === m.token)!; + expect(snap.deviation, `${m.symbol}: deviation drifted`).to.equal(m.currentPct); + expect(snap.enabled, `${m.symbol}: enabled drifted`).to.equal(currentEnabled(m)); + }); + } + }); +}; + +// ────────────────────────────────────────────────────────────────────────── +// Disable behavior — prove a disabled market can no longer be acted on. +// handleDeviation on a disabled market reverts with TokenMonitoringDisabled. +// (BSC only — remote chains have no local keeper signer in the forked-command harness.) +// ────────────────────────────────────────────────────────────────────────── + +export const runDisableBehaviorTests = (cfg: TestConfig) => { + const p = partition(cfg.ctx.markets); + if (p.disables.length === 0 || !cfg.keeper) return; + + describe(`VIP-658 [${cfg.ctx.name}] — Disable behavior`, () => { + let deviationSentinel: Contract; + let vTokenByUnderlying: Map; + + before(async () => { + deviationSentinel = await ethers.getContractAt(DEVIATION_SENTINEL_ABI, cfg.ctx.deviationSentinel); + vTokenByUnderlying = await buildVTokenIndex(cfg); + }); + + for (const m of p.disables) { + it(`${m.symbol}: handleDeviation reverts TokenMonitoringDisabled`, async () => { + const vToken = vTokenByUnderlying.get(m.token.toLowerCase()); + if (!vToken) throw new Error(`${m.symbol}: vToken not found — fix comptroller config`); + const keeper = await initMainnetUser(cfg.keeper as string, ethers.utils.parseEther("1")); + await expect(deviationSentinel.connect(keeper).handleDeviation(vToken)).to.be.revertedWithCustomError( + deviationSentinel, + "TokenMonitoringDisabled", + ); + }); + } + }); +}; + +// ────────────────────────────────────────────────────────────────────────── +// Threshold boundary mechanics with a deliberately perturbed direct price remain +// covered by VIP-616 / VIP-624. This suite exercises every changed pool through the +// natural adapter -> SentinelOracle -> DeviationSentinel path at the fork timestamp, +// before the governance simulation advances time beyond external feed heartbeats. +// ────────────────────────────────────────────────────────────────────────── + +// ────────────────────────────────────────────────────────────────────────── +// callbackAfterExecution — event-count and permission-neutrality checks. +// ────────────────────────────────────────────────────────────────────────── + +export const buildPostExecutionEventChecks = (ctx: ChainContext) => { + const p = partition(ctx.markets); + const poolWrites = poolWriteMarkets(p); + + const uniswapPoolWrites = poolWrites.filter(m => (m.oracleType ?? "uniswap") === "uniswap").length; + const curvePoolWrites = poolWrites.filter(m => m.oracleType === "curve").length; + const aerodromePoolWrites = poolWrites.filter(m => m.oracleType === "aerodrome").length; + const sentinelOracleWrites = oracleRepointMarkets(p).length; + const tokenConfigWrites = thresholdWriteMarkets(p).length; + const monitoringToggles = p.disables.length; + + return async (txResponse: TransactionResponse) => { + if (uniswapPoolWrites + aerodromePoolWrites > 0) { + // UniswapOracle and AerodromeSlipstreamOracle share the same setPoolConfig signature + // and emit the same PoolConfigUpdated event signature, so the count is summed. + // (BSC's PancakeSwapOracle shares the UniswapOracle ABI as well.) + await expectEvents( + txResponse, + [UNISWAP_ORACLE_ABI], + ["PoolConfigUpdated"], + [uniswapPoolWrites + aerodromePoolWrites], + ); + } + if (ctx.curveOracle && curvePoolWrites > 0) { + await expectEvents(txResponse, [CURVE_ORACLE_ABI], ["PoolConfigUpdated"], [curvePoolWrites]); + } + if (sentinelOracleWrites > 0) { + await expectEvents(txResponse, [SENTINEL_ORACLE_ABI], ["TokenOracleConfigUpdated"], [sentinelOracleWrites]); + } + if (tokenConfigWrites > 0) { + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TokenConfigUpdated"], [tokenConfigWrites]); + } + if (monitoringToggles > 0) { + await expectEvents(txResponse, [DEVIATION_SENTINEL_ABI], ["TokenMonitoringStatusChanged"], [monitoringToggles]); + } + + // Permission-neutrality: no ACM mutations expected. + await expectEvents(txResponse, [ACM_ABI], ["RoleGranted"], [0]); + await expectEvents(txResponse, [ACM_ABI], ["RoleRevoked"], [0]); + }; +}; + +// ────────────────────────────────────────────────────────────────────────── +// Total command count — guards against drift between commandsForMarket logic +// and the expected per-chain scope. +// ────────────────────────────────────────────────────────────────────────── + +export const runCommandCountAssertion = (ctx: ChainContext, expected: number) => { + describe(`VIP-658 [${ctx.name}] — Command count`, () => { + it(`emits exactly ${expected} commands for this chain`, () => { + // BSC commands carry no dstChainId; remote chains route by ctx.dstChainId. + const actual = buildAllCommands().filter(c => c.dstChainId === ctx.dstChainId).length; + expect(actual, `${ctx.name}: emitted command count`).to.equal(expected); + }); + }); +}; diff --git a/src/vip-framework/index.ts b/src/vip-framework/index.ts index 7fea70a06..84aed0e50 100644 --- a/src/vip-framework/index.ts +++ b/src/vip-framework/index.ts @@ -510,15 +510,30 @@ export const testForkedNetworkVipCommands = (description: string, proposal: Prop it("should be queued succesfully", async () => { await validateTargetAddresses(targets, signatures); - const impersonatedLibrary = await initMainnetUser( - NETWORK_ADDRESSES[FORKED_NETWORK as REMOTE_NETWORKS].LZ_LIBRARY, - ethers.utils.parseEther("100"), - ); - const endpoint = new ethers.Contract( - NETWORK_ADDRESSES[FORKED_NETWORK as REMOTE_NETWORKS].ENDPOINT, - ENDPOINT_ABI, - provider, - ); + const endpointAddress = NETWORK_ADDRESSES[FORKED_NETWORK as REMOTE_NETWORKS].ENDPOINT; + // Resolve the endpoint's *current* default receive library at the fork block. + // LayerZero periodically migrates the default messaging library, so the hardcoded + // LZ_LIBRARY goes stale for forks taken after such a migration and delivery reverts + // with "invalid default library". For any fork block where the hardcoded value is + // still current this resolves to the same address (no behavior change); it only + // self-heals when the fork post-dates a migration. Falls back to the configured + // LZ_LIBRARY if the endpoint does not expose the getter (e.g. zkSync). + let receiveLibrary: string = NETWORK_ADDRESSES[FORKED_NETWORK as REMOTE_NETWORKS].LZ_LIBRARY; + try { + const libResolver = new ethers.Contract( + endpointAddress, + ["function defaultReceiveLibraryAddress() view returns (address)"], + provider, + ); + const resolvedLibrary: string = await libResolver.defaultReceiveLibraryAddress(); + if (resolvedLibrary && resolvedLibrary !== ethers.constants.AddressZero) { + receiveLibrary = resolvedLibrary; + } + } catch { + // Endpoint variant without defaultReceiveLibraryAddress(); keep the configured LZ_LIBRARY. + } + const impersonatedLibrary = await initMainnetUser(receiveLibrary, ethers.utils.parseEther("100")); + const endpoint = new ethers.Contract(endpointAddress, ENDPOINT_ABI, provider); const srcAddress = ethers.utils.solidityPack( ["address", "address"], diff --git a/vips/vip-658/addresses/arbitrumone.ts b/vips/vip-658/addresses/arbitrumone.ts new file mode 100644 index 000000000..41dffe509 --- /dev/null +++ b/vips/vip-658/addresses/arbitrumone.ts @@ -0,0 +1,72 @@ +import type { MarketEntry } from "../config"; + +// ============================================================ +// DeviationSentinel infrastructure on Arbitrum One (deployed via VIP-616) +// ============================================================ +export const DEVIATION_SENTINEL = "0xb4CC54B33d34fD809E8fBD83A066158591ED7Fba"; +export const SENTINEL_ORACLE = "0x3563CAbc541a0432C66A64942ffB4070a9726226"; +export const UNISWAP_ORACLE = "0xB6CFbfe6834EF519f002DBc1a8B81Ea437Ca647D"; + +// ============================================================ +// Underlying token addresses (Arbitrum One) +// ============================================================ +export const WETH = "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"; +export const WBTC = "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f"; +export const USDC = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"; +export const USDT0 = "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"; // USD₮0 (Tether's bridged token) +export const ARB = "0x912CE59144191C1204E64559FE8253a0e49E6548"; + +// ============================================================ +// Pool addresses (Uniswap V3) +// ============================================================ +// Current pools (carried for documentation only). +const POOL_USDC_USDT0 = "0xbe3ad6a5669dc0b8b12febc03608860c31e2eef6"; // shared USDC / USD₮0 +const POOL_WBTC_USDC_005 = "0x0e4831319a50228b9e450861297ab92dee15b44f"; // current WBTC +const POOL_ARB_USDC_030 = "0xaebdca1bc8d89177ebe2308d62af5e74885dccc3"; // current ARB + +// Target pools (V2 doc). +const POOL_WBTC_WETH_005 = "0x2f5e87C9312fa29aed5c179E456625D79015299c"; // Uni V3 WBTC/WETH 0.05% +const POOL_ARB_WETH_005 = "0xC6F780497A95e246EB9449f5e4770916DCd6396A"; // Uni V3 ARB/WETH 0.05% + +// ============================================================ +// Arbitrum One market table +// currentPct: USDC = 1%, USD₮0 = 1%, WBTC = 3% (VIP-624); ARB = 10% (VIP-616, +// left as skip in VIP-624). Validated on the fork's pre-VIP assertions. +// ============================================================ +export const ARBITRUMONE_MARKETS: MarketEntry[] = [ + // ── Retune → 5% ─────────────────────────────────────────────────────── + { symbol: "USDC", token: USDC, pool: POOL_USDC_USDT0, currentPct: 1, targetPct: 5, action: "retune" }, + { + symbol: "USD₮0", + token: USDT0, + pool: POOL_USDC_USDT0, + currentPct: 1, + targetPct: 5, + action: "retune", + note: "co-trip with USDC on shared pool", + }, + + // ── Pool move + retune → 5% ─────────────────────────────────────────── + { + symbol: "WBTC", + token: WBTC, + pool: POOL_WBTC_WETH_005, + currentPct: 3, + targetPct: 5, + action: "poolSwap", + oracleType: "uniswap", + note: `moves off ${POOL_WBTC_USDC_005} (Uni V3 WBTC/USDC 0.05%) onto Uni V3 WBTC/WETH 0.05%`, + }, + + // ── Pool move only (threshold left unchanged; not in the doc's threshold table) ── + { + symbol: "ARB", + token: ARB, + pool: POOL_ARB_WETH_005, + currentPct: 10, + targetPct: 10, + action: "poolOnly", + oracleType: "uniswap", + note: `moves off ${POOL_ARB_USDC_030} (Uni V3 ARB/USDC 0.30%) onto Uni V3 ARB/WETH 0.05%; threshold unchanged`, + }, +]; diff --git a/vips/vip-658/addresses/basemainnet.ts b/vips/vip-658/addresses/basemainnet.ts new file mode 100644 index 000000000..e996ccdff --- /dev/null +++ b/vips/vip-658/addresses/basemainnet.ts @@ -0,0 +1,51 @@ +import type { MarketEntry } from "../config"; + +// ============================================================ +// DeviationSentinel infrastructure on Base mainnet (deployed via VIP-616) +// ============================================================ +export const DEVIATION_SENTINEL = "0x12D09d5b13A673269cdB624D17A42f45a5233076"; +export const SENTINEL_ORACLE = "0xCdD6D79Fd313C21967CED04C1b8bE70BDc27574D"; +export const UNISWAP_ORACLE = "0xc3b5169a7d5f6341403c74187Db3C4Fe6d447762"; +export const AERODROME_ORACLE = "0x5DE0B322A74088fD64CDD01042BE2fBc47FE82EC"; + +// ============================================================ +// Underlying token addresses (Base mainnet) +// ============================================================ +export const USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"; +export const CBBTC = "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf"; +export const WSTETH = "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452"; + +// ============================================================ +// Pool addresses (carried for documentation only — no pool changes on Base) +// ============================================================ +const POOL_WETH_USDC_UNIV3 = "0x6c561b446416e1a00e8e93e221854d6ea4171372"; +const POOL_CBBTC_USDC_AERO = "0x4e962bb3889bf030368f56810a9c96b83cb3e778"; +const POOL_WSTETH_WETH_AERO = "0x861a2922be165a5bd41b1e482b49216b465e1b5f"; + +// ============================================================ +// Base market table (threshold-only retune → 5%; no pool changes per V2 doc). +// currentPct verified on-chain (tokenConfigs on DeviationSentinel 0x12D0…3076, +// block 50503680, 2026-08-27): USDC / cbBTC / wstETH all = 3%. (USDC was retuned +// 1% → 3% by the Base Guardian at block 50298851; the V2 doc's 5% target stands.) +// ============================================================ +export const BASEMAINNET_MARKETS: MarketEntry[] = [ + { symbol: "USDC", token: USDC, pool: POOL_WETH_USDC_UNIV3, currentPct: 3, targetPct: 5, action: "retune" }, + { + symbol: "cbBTC", + token: CBBTC, + pool: POOL_CBBTC_USDC_AERO, + currentPct: 3, + targetPct: 5, + action: "retune", + oracleType: "aerodrome", + }, + { + symbol: "wstETH", + token: WSTETH, + pool: POOL_WSTETH_WETH_AERO, + currentPct: 3, + targetPct: 5, + action: "retune", + oracleType: "aerodrome", + }, +]; diff --git a/vips/vip-658/addresses/bscmainnet.ts b/vips/vip-658/addresses/bscmainnet.ts new file mode 100644 index 000000000..b363758f9 --- /dev/null +++ b/vips/vip-658/addresses/bscmainnet.ts @@ -0,0 +1,110 @@ +import type { MarketEntry } from "../config"; + +// ============================================================ +// DeviationSentinel infrastructure on BSC mainnet (deployed in VIP-590) +// ============================================================ +export const DEVIATION_SENTINEL = "0x6599C15cc8407046CD91E5c0F8B7f765fF914870"; +export const SENTINEL_ORACLE = "0x58eae0Cf4215590E19860b66b146C5d539cb6f14"; +export const PANCAKESWAP_ORACLE = "0x44B72078240A3509979faF450085Fa818401D32E"; + +// ============================================================ +// Underlying token addresses (BSC mainnet) +// ============================================================ +export const USDC = "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"; +export const U = "0xcE24439F2D9C6a2289F741120FE202248B666666"; +export const USDT = "0x55d398326f99059fF775485246999027B3197955"; +export const SOLVBTC = "0x4aae823a6a0b376De6A78e74eCC5b079d38cBCf7"; +export const USD1 = "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d"; +export const SLISBNB = "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B"; +export const WBETH = "0xa2e3356610840701bdf5611a53974510ae27e2e1"; +export const TUSD = "0x40af3827F39D0EAcBF4A168f8D4ee67c121D11c9"; +export const LISUSD = "0x0782b6d8c4551B9760e74c0545a9bCD90bdc41E5"; +export const FDUSD = "0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409"; +export const DAI = "0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3"; + +// ============================================================ +// PancakeSwap V3 pool addresses +// ============================================================ +// Pools currently bound (VIP-613 / VIP-624) — carried for documentation. +const POOL_USDT_USDC_001 = "0x92b7807bf19b7dddf89b706143896d05228f3121"; // current USDC pool +const POOL_USDT_WBNB_001 = "0x172fcd41e0913e95784454622d1c3724f546f849"; // current USDT pool +const POOL_U_USDT_001 = "0xa0909f81785f87f3e79309f0e73a7d82208094e4"; +const POOL_SOLVBTC_BTCB_005 = "0x12197d7a4fe2d67f9f97ae64d82a44c24b7ad407"; +const POOL_USD1_USDT_001 = "0x9c4ee895e4f6ce07ada631c508d1306db7502cce"; +const POOL_SLISBNB_WBNB_005 = "0x9474e972f49605315763c296b122cbb998b615cf"; +const POOL_WBETH_ETH_005 = "0x379044e32f5a162233e82de19da852255d0951b8"; +const POOL_TUSD_USDT_001 = "0xd881d9d0e0767719701305c614903f555d589586"; +const POOL_LISUSD_USDT_005 = "0x12e79eb21dcc5852f9c6ac1736d977312925da33"; +const POOL_FDUSD_USDT_001 = "0xbf72b6485e4b31601afe7b0a1210be2004d2b1d6"; +const POOL_DAI_USDT_001 = "0xe043558b77e2b4c262d7d6e579b005ceb7f4591c"; + +// Target pool for the USDC + USDT pool move (V2 doc): PancakeSwap V3 USDT/USDC 0.05%. +// Verified on-chain: token0 = USDT, token1 = USDC. +const POOL_USDT_USDC_005 = "0x4f31Fa980a675570939B737Ebdde0471a4Be40Eb"; + +// ============================================================ +// BSC market table +// currentPct values verified on-chain against DeviationSentinel.tokenConfigs +// (2026-08-26): USDC/U/USD1/lisUSD = 1%, USDT/SolvBTC/slisBNB/wBETH = 3%, +// FDUSD = 10%, TUSD = (1%, enabled), DAI = (10%, disabled by VIP-644). +// ============================================================ +export const BSC_MARKETS: MarketEntry[] = [ + // ── Retune → 5% (stables previously at 1%) ──────────────────────────── + { symbol: "U", token: U, pool: POOL_U_USDT_001, currentPct: 1, targetPct: 5, action: "retune" }, + { symbol: "USD1", token: USD1, pool: POOL_USD1_USDT_001, currentPct: 1, targetPct: 5, action: "retune" }, + { symbol: "lisUSD", token: LISUSD, pool: POOL_LISUSD_USDT_005, currentPct: 1, targetPct: 5, action: "retune" }, + + // ── Retune → 5% (wrappers / LSTs previously at 3%) ──────────────────── + { symbol: "SolvBTC", token: SOLVBTC, pool: POOL_SOLVBTC_BTCB_005, currentPct: 3, targetPct: 5, action: "retune" }, + { symbol: "slisBNB", token: SLISBNB, pool: POOL_SLISBNB_WBNB_005, currentPct: 3, targetPct: 5, action: "retune" }, + { symbol: "wBETH", token: WBETH, pool: POOL_WBETH_ETH_005, currentPct: 3, targetPct: 5, action: "retune" }, + + // ── Retune → 5% (FDUSD previously kept at 10% as a thin-pool exception) ─ + { symbol: "FDUSD", token: FDUSD, pool: POOL_FDUSD_USDT_001, currentPct: 10, targetPct: 5, action: "retune" }, + + // ── Pool move + retune → 5% (both onto the deeper USDT/USDC 0.05% pool) ─ + { + symbol: "USDC", + token: USDC, + pool: POOL_USDT_USDC_005, + currentPct: 1, + targetPct: 5, + action: "poolSwap", + oracleType: "uniswap", + note: `moves off ${POOL_USDT_USDC_001} (USDT/USDC 0.01%) onto USDT/USDC 0.05%; co-trip with USDT on shared pool`, + }, + { + symbol: "USDT", + token: USDT, + pool: POOL_USDT_USDC_005, + currentPct: 3, + targetPct: 5, + action: "poolSwap", + oracleType: "uniswap", + note: `moves off ${POOL_USDT_WBNB_001} (USDT/WBNB 0.01%) onto USDT/USDC 0.05%; removes the WBNB-quote noise source; co-trip with USDC on shared pool`, + }, + + // ── Configuration removals ──────────────────────────────────────────── + // TUSD: disable monitoring. Stored config is left intact (no removal function on the + // deployed DeviationSentinel; setTokenConfig rejects deviation = 0). + { + symbol: "TUSD", + token: TUSD, + pool: POOL_TUSD_USDT_001, + currentPct: 1, + targetPct: 1, + action: "disable", + note: "disable monitoring; config preserved (config-clear needs a contract change — deferred)", + }, + // DAI: already disabled on-chain by VIP-644 (tokenConfigs = (10, disabled)). No command emitted. + { + symbol: "DAI", + token: DAI, + pool: POOL_DAI_USDT_001, + currentPct: 10, + targetPct: 10, + action: "skip", + currentEnabled: false, + note: "already disabled by VIP-644; config-clear deferred (needs a contract change)", + }, +]; diff --git a/vips/vip-658/addresses/ethereum.ts b/vips/vip-658/addresses/ethereum.ts new file mode 100644 index 000000000..0eb2509a0 --- /dev/null +++ b/vips/vip-658/addresses/ethereum.ts @@ -0,0 +1,224 @@ +import type { MarketEntry } from "../config"; + +// ============================================================ +// DeviationSentinel infrastructure on Ethereum mainnet (deployed via VIP-616) +// ============================================================ +export const DEVIATION_SENTINEL = "0x7D0EFA41eBF1aF242A37174E1E047bD6ea1b1B9c"; +export const SENTINEL_ORACLE = "0x444C53E194B40c272fAd683210e2cB1c16Ab132e"; +export const UNISWAP_ORACLE = "0x873993F8f5f5Ddbae0952e939ab3005Af363Af00"; +export const CURVE_ORACLE = "0x9F508F3146cb03276282f9237c6eE64f76E3261D"; + +// ============================================================ +// Underlying token addresses (Ethereum mainnet) +// ============================================================ +export const WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; +export const WBTC = "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"; +export const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; +export const USDT = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; +export const LBTC = "0x8236a87084f8B84306f72007F36F2618A5634494"; +export const USDE = "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3"; +export const DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; +export const TBTC = "0x18084fbA666a33d37592fA2633fD49a74DD93a88"; +export const USDS = "0xdC035D45d973E3EC169d2276DDab16f1e407384F"; +export const CRVUSD = "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E"; +export const SUSDE = "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497"; +export const SUSDS = "0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD"; + +// ============================================================ +// Pool addresses — Ethereum mainnet +// All coin indexes / token0-token1 verified on-chain (2026-08-26). +// ============================================================ +// Current pools (carried for documentation only). +const POOL_USDC_USDT_UNI = "0x3416cf6c708da44db2624d63ea0aaef7113527c6"; // current USDC/USDT +const POOL_DAI_USDC_UNI = "0x5777d92f208679db4b9778590fa3cab3ac9e2168"; // current DAI +const POOL_CRVUSD_USDC_CURVE = "0x4dece678ceceb27446b35c672dc7d61f30bad69e"; // current crvUSD +const POOL_SUSDE_USDT_UNI = "0x7eb59373d63627be64b42406b108b602174b4ccc"; // current sUSDe +const POOL_SUSDS_USDT_CURVE = "0x00836fe54625be242bcfa286207795405ca4fd10"; // current sUSDS +const POOL_WBTC_USDC_UNI = "0x99ac8ca7087fa4a2a1fb6357269965a2014abc35"; // current WBTC +const POOL_LBTC_WBTC_UNI = "0x87428a53e14d24ab19c6ca4939b4df93b8996ca9"; // current LBTC +const POOL_WBTC_TBTC_UNI = "0x73a38006d23517a1d383c88929b2014f8835b38b"; // current tBTC +const POOL_WETH_USDC_UNI = "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"; // current WETH + +// Target pools (V2 doc). +// Curve 3pool — coins(0)=DAI, coins(1)=USDC, coins(2)=USDT. +const POOL_CURVE_3POOL = "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7"; +// Curve USDT/crvUSD — coins(0)=USDT, coins(1)=crvUSD. +const POOL_CURVE_USDT_CRVUSD = "0x390f3595bCa2Df7d23783dFd126427CCeb997BF4"; +// Curve crvUSD/sUSDe — coins(0)=crvUSD, coins(1)=sUSDe. +const POOL_CURVE_CRVUSD_SUSDE = "0x57064F49Ad7123C92560882a45518374ad982e85"; +// Curve sUSDe/sUSDS — coins(0)=sUSDe, coins(1)=sUSDS. +const POOL_CURVE_SUSDE_SUSDS = "0x3CEf1AFC0E8324b57293a6E7cE663781bbEFBB79"; +// Curve WBTC/tBTC — coins(0)=WBTC, coins(1)=tBTC. +const POOL_CURVE_WBTC_TBTC = "0xB7ECB2AA52AA64a717180E030241bC75Cd946726"; +// Uniswap V3 USDT/WBTC 0.30% — token0 = WBTC, token1 = USDT. +const POOL_WBTC_USDT_030 = "0x9Db9e0e53058C89e5B94e29621a205198648425B"; +// Uniswap V3 WBTC/LBTC 0.01% — token0 = WBTC, token1 = LBTC. +const POOL_WBTC_LBTC_001 = "0x0b599ebf4E05af48b56D38E2DDe520570C366460"; +// Uniswap V3 WETH/USDT 0.30% — token0 = WETH, token1 = USDT. +const POOL_WETH_USDT_030 = "0x4e68Ccd3E89f51C3074ca5072bbAC773960dFa36"; + +// ============================================================ +// Ethereum market table +// currentPct verified on-chain (2026-08-26): USDC/USDT/USDe/DAI/crvUSD/sUSDe/sUSDS = 1%, +// WBTC/LBTC/tBTC = 3%, USDS = 10%, WETH = 10%. sUSDe/sUSDS were wired by VIP-624. +// ============================================================ +export const ETHEREUM_MARKETS: MarketEntry[] = [ + // ── Pool move + retune → 5% (Curve 3pool for the core stables) ───────── + { + symbol: "USDC", + token: USDC, + pool: POOL_CURVE_3POOL, + currentPct: 1, + targetPct: 5, + action: "poolSwap", + oracleType: "curve", + coinIndex: 1, // USDC = coins(1) + refCoinIndex: 2, // USDT = coins(2) + referenceToken: USDT, + assetDecimals: 6, + note: `moves off ${POOL_USDC_USDT_UNI} (Uni V3 USDC/USDT) onto Curve 3pool; co-trip with USDT/DAI on shared pool`, + }, + { + symbol: "USDT", + token: USDT, + pool: POOL_CURVE_3POOL, + currentPct: 1, + targetPct: 5, + action: "poolSwap", + oracleType: "curve", + coinIndex: 2, // USDT = coins(2) + refCoinIndex: 1, // USDC = coins(1) + referenceToken: USDC, + assetDecimals: 6, + note: `moves off ${POOL_USDC_USDT_UNI} (Uni V3 USDC/USDT) onto Curve 3pool; co-trip with USDC/DAI on shared pool`, + }, + { + symbol: "USDe", + token: USDE, + pool: "0xe6d7ebb9f1a9519dc06d557e03c522d53520e76a", + currentPct: 1, + targetPct: 5, + action: "retune", + note: "threshold only (pool unchanged in V2 doc)", + }, + { + symbol: "DAI", + token: DAI, + pool: POOL_CURVE_3POOL, + currentPct: 1, + targetPct: 5, + action: "poolSwap", + oracleType: "curve", + coinIndex: 0, // DAI = coins(0) + refCoinIndex: 1, // USDC = coins(1) + referenceToken: USDC, + assetDecimals: 18, + note: `moves off ${POOL_DAI_USDC_UNI} (Uni V3 DAI/USDC) onto Curve 3pool; co-trip with USDC/USDT on shared pool`, + }, + { + symbol: "crvUSD", + token: CRVUSD, + pool: POOL_CURVE_USDT_CRVUSD, + currentPct: 1, + targetPct: 5, + action: "poolSwap", + oracleType: "curve", + coinIndex: 1, // crvUSD = coins(1) + refCoinIndex: 0, // USDT = coins(0) + referenceToken: USDT, + assetDecimals: 18, + skipOracleRepoint: true, // SentinelOracle already routes to the target CurveOracle (verified on-chain) + note: `moves off ${POOL_CRVUSD_USDC_CURVE} (Curve crvUSD/USDC) onto Curve USDT/crvUSD`, + }, + { + symbol: "sUSDe", + token: SUSDE, + pool: POOL_CURVE_CRVUSD_SUSDE, + currentPct: 1, + targetPct: 5, + action: "poolSwap", + oracleType: "curve", + coinIndex: 1, // sUSDe = coins(1) + refCoinIndex: 0, // crvUSD = coins(0) + referenceToken: CRVUSD, + assetDecimals: 18, + note: `moves off ${POOL_SUSDE_USDT_UNI} (Uni V3 USDT/sUSDe) onto Curve crvUSD/sUSDe`, + }, + { + symbol: "sUSDS", + token: SUSDS, + pool: POOL_CURVE_SUSDE_SUSDS, + currentPct: 1, + targetPct: 5, + action: "poolSwap", + oracleType: "curve", + coinIndex: 1, // sUSDS = coins(1) + refCoinIndex: 0, // sUSDe = coins(0) + referenceToken: SUSDE, + assetDecimals: 18, + skipOracleRepoint: true, // SentinelOracle already routes to the target CurveOracle (verified on-chain) + note: `moves off ${POOL_SUSDS_USDT_CURVE} (Curve sUSDS/USDT) onto Curve sUSDe/sUSDS`, + }, + + // ── Pool move + retune → 5% (BTC markets) ───────────────────────────── + { + symbol: "WBTC", + token: WBTC, + pool: POOL_WBTC_USDT_030, + currentPct: 3, + targetPct: 5, + action: "poolSwap", + oracleType: "uniswap", + skipOracleRepoint: true, // SentinelOracle already routes to the target UniswapOracle (verified on-chain) + note: `moves off ${POOL_WBTC_USDC_UNI} (Uni V3 WBTC/USDC 0.30%) onto Uni V3 USDT/WBTC 0.30%`, + }, + { + symbol: "LBTC", + token: LBTC, + pool: POOL_WBTC_LBTC_001, + currentPct: 3, + targetPct: 5, + action: "poolSwap", + oracleType: "uniswap", + skipOracleRepoint: true, // SentinelOracle already routes to the target UniswapOracle (verified on-chain) + note: `moves off ${POOL_LBTC_WBTC_UNI} (Uni V3 WBTC/LBTC 0.05%) onto the deeper WBTC/LBTC 0.01%`, + }, + { + symbol: "tBTC", + token: TBTC, + pool: POOL_CURVE_WBTC_TBTC, + currentPct: 3, + targetPct: 5, + action: "poolSwap", + oracleType: "curve", + coinIndex: 1, // tBTC = coins(1) + refCoinIndex: 0, // WBTC = coins(0) + referenceToken: WBTC, + assetDecimals: 18, + note: `moves off ${POOL_WBTC_TBTC_UNI} (Uni V3 WBTC/tBTC 0.01%) onto Curve WBTC/tBTC`, + }, + + // ── Retune → 5% (USDS previously kept at 10%) ───────────────────────── + { + symbol: "USDS", + token: USDS, + pool: "0xe9f1e2ef814f5686c30ce6fb7103d0f780836c67", + currentPct: 10, + targetPct: 5, + action: "retune", + note: "threshold only (pool unchanged in V2 doc)", + }, + + // ── Pool move only (threshold left at 10%; not in the doc's threshold table) ── + { + symbol: "WETH", + token: WETH, + pool: POOL_WETH_USDT_030, + currentPct: 10, + targetPct: 10, + action: "poolOnly", + oracleType: "uniswap", + skipOracleRepoint: true, // SentinelOracle already routes to the target UniswapOracle (verified on-chain) + note: `moves off ${POOL_WETH_USDC_UNI} (Uni V3 USDC/WETH 0.05%) onto Uni V3 WETH/USDT 0.30%; threshold unchanged`, + }, +]; diff --git a/vips/vip-658/bscmainnet.ts b/vips/vip-658/bscmainnet.ts new file mode 100644 index 000000000..dd10097d1 --- /dev/null +++ b/vips/vip-658/bscmainnet.ts @@ -0,0 +1,207 @@ +import { Command, LzChainId, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +import * as ARBITRUM from "./addresses/arbitrumone"; +import * as BASE from "./addresses/basemainnet"; +import * as BSC from "./addresses/bscmainnet"; +import * as ETHEREUM from "./addresses/ethereum"; +import { ChainContext, MarketEntry } from "./config"; + +// ────────────────────────────────────────────────────────────────────────── +// Per-chain contexts +// ────────────────────────────────────────────────────────────────────────── + +export const BSC_CTX: ChainContext = { + name: "BSC", + deviationSentinel: BSC.DEVIATION_SENTINEL, + sentinelOracle: BSC.SENTINEL_ORACLE, + uniswapOracle: BSC.PANCAKESWAP_ORACLE, + markets: BSC.BSC_MARKETS, +}; + +export const ETHEREUM_CTX: ChainContext = { + name: "Ethereum", + deviationSentinel: ETHEREUM.DEVIATION_SENTINEL, + sentinelOracle: ETHEREUM.SENTINEL_ORACLE, + uniswapOracle: ETHEREUM.UNISWAP_ORACLE, + curveOracle: ETHEREUM.CURVE_ORACLE, + markets: ETHEREUM.ETHEREUM_MARKETS, + dstChainId: LzChainId.ethereum, +}; + +export const ARBITRUMONE_CTX: ChainContext = { + name: "Arbitrum One", + deviationSentinel: ARBITRUM.DEVIATION_SENTINEL, + sentinelOracle: ARBITRUM.SENTINEL_ORACLE, + uniswapOracle: ARBITRUM.UNISWAP_ORACLE, + markets: ARBITRUM.ARBITRUMONE_MARKETS, + dstChainId: LzChainId.arbitrumone, +}; + +export const BASEMAINNET_CTX: ChainContext = { + name: "Base", + deviationSentinel: BASE.DEVIATION_SENTINEL, + sentinelOracle: BASE.SENTINEL_ORACLE, + uniswapOracle: BASE.UNISWAP_ORACLE, + aerodromeOracle: BASE.AERODROME_ORACLE, + markets: BASE.BASEMAINNET_MARKETS, + dstChainId: LzChainId.basemainnet, +}; + +const CHAINS: readonly ChainContext[] = [BSC_CTX, ETHEREUM_CTX, ARBITRUMONE_CTX, BASEMAINNET_CTX]; + +// ────────────────────────────────────────────────────────────────────────── +// Command builders +// ────────────────────────────────────────────────────────────────────────── + +const assertNever = (x: never, message: string): never => { + throw new Error(`${message}: ${JSON.stringify(x)}`); +}; + +export const dexOracleFor = (ctx: ChainContext, m: MarketEntry): string => { + const t = m.oracleType ?? "uniswap"; + switch (t) { + case "uniswap": + return ctx.uniswapOracle; + case "curve": + if (!ctx.curveOracle) throw new Error(`${ctx.name}: ${m.symbol} requires CurveOracle but none configured`); + return ctx.curveOracle; + case "aerodrome": + if (!ctx.aerodromeOracle) + throw new Error(`${ctx.name}: ${m.symbol} requires AerodromeSlipstreamOracle but none configured`); + return ctx.aerodromeOracle; + default: + return assertNever(t, `${ctx.name}: ${m.symbol} has unknown oracleType`); + } +}; + +const buildPoolConfigCmd = (ctx: ChainContext, m: MarketEntry): Command => { + const target = dexOracleFor(ctx, m); + if (m.oracleType === "curve") { + if (m.coinIndex === undefined || m.refCoinIndex === undefined || !m.referenceToken || m.assetDecimals === undefined) + throw new Error( + `${ctx.name}: ${m.symbol} curve entry missing coinIndex/refCoinIndex/referenceToken/assetDecimals`, + ); + return { + target, + signature: "setPoolConfig(address,address,uint8,uint8,address,uint8)", + params: [m.token, m.pool, m.coinIndex, m.refCoinIndex, m.referenceToken, m.assetDecimals], + dstChainId: ctx.dstChainId, + }; + } + return { + target, + signature: "setPoolConfig(address,address)", + params: [m.token, m.pool], + dstChainId: ctx.dstChainId, + }; +}; + +const buildSentinelOracleCmd = (ctx: ChainContext, m: MarketEntry): Command => ({ + target: ctx.sentinelOracle, + signature: "setTokenOracleConfig(address,address)", + params: [m.token, dexOracleFor(ctx, m)], + dstChainId: ctx.dstChainId, +}); + +const buildSetTokenConfigCmd = (ctx: ChainContext, m: MarketEntry, pct: number, enabled: boolean): Command => ({ + target: ctx.deviationSentinel, + signature: "setTokenConfig(address,(uint8,bool))", + params: [m.token, [pct, enabled]], + dstChainId: ctx.dstChainId, +}); + +const buildDisableCmd = (ctx: ChainContext, m: MarketEntry): Command => ({ + target: ctx.deviationSentinel, + signature: "setTokenMonitoringEnabled(address,bool)", + params: [m.token, false], + dstChainId: ctx.dstChainId, +}); + +const commandsForMarket = (ctx: ChainContext, m: MarketEntry): Command[] => { + switch (m.action) { + case "skip": + return []; + case "retune": + return [buildSetTokenConfigCmd(ctx, m, m.targetPct, true)]; + case "poolSwap": { + const cmds = [buildPoolConfigCmd(ctx, m)]; + if (!m.skipOracleRepoint) cmds.push(buildSentinelOracleCmd(ctx, m)); + cmds.push(buildSetTokenConfigCmd(ctx, m, m.targetPct, true)); + return cmds; + } + case "poolOnly": { + // Re-register the pool + (optionally) repoint the SentinelOracle but leave the + // DeviationSentinel threshold untouched (these markets are not in the doc's threshold tables). + const cmds = [buildPoolConfigCmd(ctx, m)]; + if (!m.skipOracleRepoint) cmds.push(buildSentinelOracleCmd(ctx, m)); + return cmds; + } + case "disable": + return [buildDisableCmd(ctx, m)]; + default: + return assertNever(m.action, `${ctx.name}: ${m.symbol} has unknown action`); + } +}; + +const buildChainCommands = (ctx: ChainContext): Command[] => ctx.markets.flatMap(m => commandsForMarket(ctx, m)); + +export const buildAllCommands = (): Command[] => CHAINS.flatMap(buildChainCommands); + +export const vip658 = () => { + const meta = { + version: "v2", + title: "VIP-658 [BNB Chain, Ethereum, Arbitrum One, Base] DeviationSentinel 2026-08 Parameter Adjustment", + description: `#### Summary + +Retunes **DeviationSentinel** thresholds to a unified **5%** across BNB Chain, Ethereum, Arbitrum One and Base, repoints several markets' price-source pools to deeper DEX pools, and disables monitoring for BSC TUSD. No new contracts are deployed and no ACM grants change — every setter used was permissioned in VIP-590 (BSC) / VIP-616 (remote chains), and the Curve/Uniswap targets are compatible with the already-deployed CurveOracle / UniswapOracle (as in VIP-624). + +#### Scope + +**BNB Chain — 14 commands** + +- Retune to **5%**: U, USD1, lisUSD (1% → 5%); SolvBTC, slisBNB, wBETH (3% → 5%); FDUSD (10% → 5%) +- Pool move + retune to **5%**: USDC (1% → 5%) and USDT (3% → 5%) → PancakeSwap V3 USDT/USDC 0.05% (0x4f31Fa980a675570939B737Ebdde0471a4Be40Eb) +- Disable monitoring: **TUSD** (setTokenMonitoringEnabled(TUSD, false)); **DAI** is already disabled on-chain (VIP-644), so no command is emitted for it + +**Ethereum — 26 commands** + +- Retune to **5%**: USDe (1% → 5%); USDS (10% → 5%) +- Pool move + retune to **5%**: USDC / USDT / DAI → Curve 3pool (0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7); crvUSD → Curve USDT/crvUSD (0x390f3595bCa2Df7d23783dFd126427CCeb997BF4); sUSDe → Curve crvUSD/sUSDe (0x57064F49Ad7123C92560882a45518374ad982e85); sUSDS → Curve sUSDe/sUSDS (0x3CEf1AFC0E8324b57293a6E7cE663781bbEFBB79); WBTC → Uniswap V3 USDT/WBTC 0.30% (0x9Db9e0e53058C89e5B94e29621a205198648425B); LBTC → Uniswap V3 WBTC/LBTC 0.01% (0x0b599ebf4E05af48b56D38E2DDe520570C366460); tBTC → Curve WBTC/tBTC (0xB7ECB2AA52AA64a717180E030241bC75Cd946726) +- Pool move only (threshold left at 10%): **WETH** → Uniswap V3 WETH/USDT 0.30% (0x4e68Ccd3E89f51C3074ca5072bbAC773960dFa36) + +Note: for crvUSD, sUSDS, WBTC, LBTC and WETH the SentinelOracle already routes to the target DEX oracle (curve→curve / uniswap→uniswap), so only the pool binding (and, where applicable, the threshold) is updated — the redundant SentinelOracle repoint is elided, which also keeps the single cross-chain LayerZero message within its payload-size cap. + +**Arbitrum One — 7 commands** + +- Retune to **5%**: USDC, USD₮0 (1% → 5%) +- Pool move + retune to **5%**: WBTC (3% → 5%) → Uniswap V3 WBTC/WETH 0.05% (0x2f5e87C9312fa29aed5c179E456625D79015299c) +- Pool move only (threshold unchanged): **ARB** → Uniswap V3 ARB/WETH 0.05% (0xC6F780497A95e246EB9449f5e4770916DCd6396A) + +**Base — 3 commands** + +- Retune to **5%**: USDC, cbBTC, wstETH (3% → 5%). No pool changes. + +#### Notes + +- **Shared-pool co-trip:** moving BSC USDC + USDT onto the same PancakeSwap USDT/USDC pool, and Ethereum USDC / USDT / DAI onto the Curve 3pool, means those stables share a price source and can trip together (opposite directions) on a shared-pool deviation. This is the same design property documented in VIP-624 for pre-existing shared pools. +- **FDUSD (BSC) and USDS (Ethereum)** were previously kept at 10% (thin-pool exceptions); this VIP retunes both to 5% per the recommendation. +- **WETH (Ethereum) and ARB (Arbitrum One)** get a pool move but keep their existing thresholds — they are not in the recommendation's threshold tables. +- **TUSD (BSC)** monitoring is disabled; its stored config is left intact (the DeviationSentinel has no removal function, and setTokenConfig rejects deviation = 0). A disabled market can neither be tripped nor report a deviation. **DAI (BSC)** was already disabled by VIP-644, so no command is emitted for it. + +#### References + +- [VIP-590 (BSC DeviationSentinel initial wire)](https://app.venus.io/#/governance/proposal/590?chainId=56) +- [VIP-616 (Ethereum / Arbitrum / Base initial wire)](https://app.venus.io/#/governance/proposal/616?chainId=56) +- [VIP-624 (DeviationSentinel Parameter Recommendation)](https://app.venus.io/#/governance/proposal/624?chainId=56) +- [VIP-644 (BSC DAI monitoring disabled)](https://app.venus.io/#/governance/proposal/644?chainId=56) +- [DeviationSentinel contract source](https://github.com/VenusProtocol/venus-periphery/tree/develop/contracts/DeviationSentinel)`, + forDescription: "I agree that Venus Protocol should proceed with this proposal", + againstDescription: "I do not think that Venus Protocol should proceed with this proposal", + abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", + }; + + return makeProposal(buildAllCommands(), meta, ProposalType.REGULAR); +}; + +export default vip658; diff --git a/vips/vip-658/config.ts b/vips/vip-658/config.ts new file mode 100644 index 000000000..194b63035 --- /dev/null +++ b/vips/vip-658/config.ts @@ -0,0 +1,72 @@ +import type { LzChainId } from "src/types"; + +// DeviationSentinel 2026-08 parameter adjustment (VIP-658) +// +// Shared shapes used by the proposal builder, address files, and the simulation +// suite. Per-chain market tables live in `addresses/.ts` and each entry +// describes one in-scope market — even no-op ones — so the chain manifest is +// self-documenting. The proposal builder filters by `action` and emits commands +// only for entries that require an on-chain write. +// +// Action semantics: +// retune — market is already wired. Change threshold only. +// 1 call: DeviationSentinel.setTokenConfig(token, (newPct, true)) +// poolSwap — wired, but moving to a different pool (and possibly different DEX oracle), +// and also retuning the threshold. +// 3 calls: re-register pool, repoint SentinelOracle, set new threshold. +// poolOnly — wired, moving to a different pool WITHOUT changing the threshold. Used for +// markets that are not in the doc's threshold tables (ETH WETH, Arbitrum ARB). +// 2 calls: .setPoolConfig(...) → SentinelOracle.setTokenOracleConfig. +// The existing DeviationSentinel threshold is left untouched. +// disable — stop monitoring the market without clearing its stored config. +// 1 call: DeviationSentinel.setTokenMonitoringEnabled(token, false). +// (Config *clearing* would need a new contract function; see VIP-658 spec.) +// skip — no on-chain action; entry exists for documentation only. + +export type MarketAction = "retune" | "poolSwap" | "poolOnly" | "disable" | "skip"; + +export type OracleType = "uniswap" | "curve" | "aerodrome"; + +// Common shape for every market entry. `targetPct` is the post-VIP threshold; +// `currentPct` is the pre-VIP value (for documentation + simulation pre-assertions only). +export interface MarketEntry { + symbol: string; + token: string; + pool: string; + currentPct: number; // pre on-chain threshold (0 if never wired) + targetPct: number; // post on-chain threshold (ignored when action = skip/disable; == currentPct for poolOnly) + action: MarketAction; + // Pre-VIP `enabled` flag of tokenConfigs. Defaults to (currentPct > 0). Set explicitly for a + // market that is wired (deviation != 0) yet disabled — e.g. BSC DAI, disabled by VIP-644. + currentEnabled?: boolean; + // Required for poolSwap / poolOnly. + oracleType?: OracleType; + // When the SentinelOracle already routes this token to the target DEX oracle (the oracle + // *type* is unchanged — e.g. curve→curve or uniswap→uniswap), the setTokenOracleConfig call + // is a pure no-op. Set true to elide it. Used on Ethereum to keep the single cross-chain + // LayerZero message within its payload-size cap; the elision is only valid because the + // current binding is verified on-chain (and re-asserted pre-VIP in the simulation). + skipOracleRepoint?: boolean; + // Curve-only (StableSwap / StableSwap-NG): index of priced asset in pool.coins(). + coinIndex?: number; + // Curve-only: index of the reference asset (its USD price feeds the protected quote). + refCoinIndex?: number; + // Curve-only: address of the reference asset; must match pool.coins(refCoinIndex). + referenceToken?: string; + // Curve-only: ERC-20 decimals of the priced asset. + assetDecimals?: number; + // Free-form note (TVL, delist status, co-trip pool, etc.). + note?: string; +} + +// Per-chain runtime context — bundles the addresses + market table + LayerZero dest. +export interface ChainContext { + name: string; + deviationSentinel: string; + sentinelOracle: string; + uniswapOracle: string; + curveOracle?: string; + aerodromeOracle?: string; + markets: MarketEntry[]; + dstChainId?: LzChainId; // omitted for BSC +}