From d8738922fb51560f79dbffa214c1f71692b41396 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Tue, 14 Jul 2026 17:10:54 +0530 Subject: [PATCH 01/11] feat: reduce CriticalTimelock privileges across all mainnets --- .../vip-665/abi/ACMCommandsAggregator.json | 118 + .../vip-665/abi/AccessControlManager.json | 360 ++ simulations/vip-665/abi/Comptroller.json | 3091 +++++++++++++++++ simulations/vip-665/arbitrumone.ts | 4 + simulations/vip-665/basemainnet.ts | 4 + simulations/vip-665/bscmainnet.ts | 205 ++ simulations/vip-665/ethereum.ts | 4 + simulations/vip-665/opbnbmainnet.ts | 4 + simulations/vip-665/opmainnet.ts | 4 + simulations/vip-665/unichainmainnet.ts | 4 + simulations/vip-665/utils/remoteSim.ts | 103 + simulations/vip-665/zksyncmainnet.ts | 4 + vips/vip-665/bscmainnet.ts | 92 + vips/vip-665/data/bnb.ts | 2041 +++++++++++ vips/vip-665/data/remote.ts | 184 + vips/vip-665/data/staleness.ts | 49 + vips/vip-665/scripts/seedAggregators.ts | 40 + vips/vip-665/utils/commands.ts | 94 + vips/vip-665/utils/seed.ts | 33 + 19 files changed, 6438 insertions(+) create mode 100644 simulations/vip-665/abi/ACMCommandsAggregator.json create mode 100644 simulations/vip-665/abi/AccessControlManager.json create mode 100644 simulations/vip-665/abi/Comptroller.json create mode 100644 simulations/vip-665/arbitrumone.ts create mode 100644 simulations/vip-665/basemainnet.ts create mode 100644 simulations/vip-665/bscmainnet.ts create mode 100644 simulations/vip-665/ethereum.ts create mode 100644 simulations/vip-665/opbnbmainnet.ts create mode 100644 simulations/vip-665/opmainnet.ts create mode 100644 simulations/vip-665/unichainmainnet.ts create mode 100644 simulations/vip-665/utils/remoteSim.ts create mode 100644 simulations/vip-665/zksyncmainnet.ts create mode 100644 vips/vip-665/bscmainnet.ts create mode 100644 vips/vip-665/data/bnb.ts create mode 100644 vips/vip-665/data/remote.ts create mode 100644 vips/vip-665/data/staleness.ts create mode 100644 vips/vip-665/scripts/seedAggregators.ts create mode 100644 vips/vip-665/utils/commands.ts create mode 100644 vips/vip-665/utils/seed.ts diff --git a/simulations/vip-665/abi/ACMCommandsAggregator.json b/simulations/vip-665/abi/ACMCommandsAggregator.json new file mode 100644 index 000000000..0974d4ab3 --- /dev/null +++ b/simulations/vip-665/abi/ACMCommandsAggregator.json @@ -0,0 +1,118 @@ +[ + { + "inputs": [{ "internalType": "contract IAccessControlManagerV8", "name": "_acm", "type": "address" }], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "EmptyPermissions", "type": "error" }, + { "inputs": [], "name": "ZeroAddressNotAllowed", "type": "error" }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "index", "type": "uint256" }], + "name": "GrantPermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "index", "type": "uint256" }], + "name": "GrantPermissionsExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "index", "type": "uint256" }], + "name": "RevokePermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "index", "type": "uint256" }], + "name": "RevokePermissionsExecuted", + "type": "event" + }, + { + "inputs": [], + "name": "ACM", + "outputs": [{ "internalType": "contract IAccessControlManagerV8", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }], + "name": "executeGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "index", "type": "uint256" }], + "name": "executeRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "name": "grantPermissions", + "outputs": [ + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "name": "revokePermissions", + "outputs": [ + { "internalType": "address", "name": "contractAddress", "type": "address" }, + { "internalType": "string", "name": "functionSig", "type": "string" }, + { "internalType": "address", "name": "account", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-665/abi/AccessControlManager.json b/simulations/vip-665/abi/AccessControlManager.json new file mode 100644 index 000000000..4a118fcc4 --- /dev/null +++ b/simulations/vip-665/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-665/abi/Comptroller.json b/simulations/vip-665/abi/Comptroller.json new file mode 100644 index 000000000..c1e0cc553 --- /dev/null +++ b/simulations/vip-665/abi/Comptroller.json @@ -0,0 +1,3091 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "enum ComptrollerV9Storage.Action", + "name": "action", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bool", + "name": "pauseState", + "type": "bool" + } + ], + "name": "ActionPausedMarket", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "state", + "type": "bool" + } + ], + "name": "ActionProtocolPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "allowDelegatedBorrows", + "type": "bool" + } + ], + "name": "DelegateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamondCut.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "indexed": false, + "internalType": "struct IDiamondCut.FacetCut[]", + "name": "_diamondCut", + "type": "tuple[]" + } + ], + "name": "DiamondCut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "venusDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "venusBorrowIndex", + "type": "uint256" + } + ], + "name": "DistributedBorrowerVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "supplier", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "venusDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "venusSupplyIndex", + "type": "uint256" + } + ], + "name": "DistributedSupplierVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DistributedVAIVaultVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "IsForcedLiquidationEnabledForUserUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "IsForcedLiquidationEnabledUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlAddress", + "type": "address" + } + ], + "name": "NewAccessControl", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newBorrowCap", + "type": "uint256" + } + ], + "name": "NewBorrowCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldComptrollerLens", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newComptrollerLens", + "type": "address" + } + ], + "name": "NewComptrollerLens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": 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": "address", + "name": "oldLiquidatorContract", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newLiquidatorContract", + "type": "address" + } + ], + "name": "NewLiquidatorContract", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldPauseGuardian", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newPauseGuardian", + "type": "address" + } + ], + "name": "NewPauseGuardian", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract PriceOracle", + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract PriceOracle", + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IPrime", + "name": "oldPrimeToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IPrime", + "name": "newPrimeToken", + "type": "address" + } + ], + "name": "NewPrimeToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newSupplyCap", + "type": "uint256" + } + ], + "name": "NewSupplyCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldTreasuryAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newTreasuryAddress", + "type": "address" + } + ], + "name": "NewTreasuryAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldTreasuryGuardian", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newTreasuryGuardian", + "type": "address" + } + ], + "name": "NewTreasuryGuardian", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldTreasuryPercent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTreasuryPercent", + "type": "uint256" + } + ], + "name": "NewTreasuryPercent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract VAIControllerInterface", + "name": "oldVAIController", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract VAIControllerInterface", + "name": "newVAIController", + "type": "address" + } + ], + "name": "NewVAIController", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldVAIMintRate", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newVAIMintRate", + "type": "uint256" + } + ], + "name": "NewVAIMintRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vault_", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "releaseStartBlock_", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "releaseInterval_", + "type": "uint256" + } + ], + "name": "NewVAIVaultInfo", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldVenusVAIVaultRate", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newVenusVAIVaultRate", + "type": "uint256" + } + ], + "name": "NewVenusVAIVaultRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newSpeed", + "type": "uint256" + } + ], + "name": "VenusBorrowSpeedUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "VenusGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newSpeed", + "type": "uint256" + } + ], + "name": "VenusSupplySpeedUpdated", + "type": "event" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract Unitroller", + "name": "unitroller", + "type": "address" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "_grantXVS", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newAccessControlAddress", + "type": "address" + } + ], + "name": "_setAccessControl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address[]", + "name": "markets_", + "type": "address[]" + }, + { + "internalType": "enum ComptrollerV9Storage.Action[]", + "name": "actions_", + "type": "uint8[]" + }, + { + "internalType": "bool", + "name": "paused_", + "type": "bool" + } + ], + "name": "_setActionsPaused", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract ComptrollerLensInterface", + "name": "comptrollerLens_", + "type": "address" + } + ], + "name": "_setComptrollerLens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "_setForcedLiquidation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "_setForcedLiquidationForUser", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newLiquidatorContract_", + "type": "address" + } + ], + "name": "_setLiquidatorContract", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newBorrowCaps", + "type": "uint256[]" + } + ], + "name": "_setMarketBorrowCaps", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newSupplyCaps", + "type": "uint256[]" + } + ], + "name": "_setMarketSupplyCaps", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newPauseGuardian", + "type": "address" + } + ], + "name": "_setPauseGuardian", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract PriceOracle", + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract IPrime", + "name": "_prime", + "type": "address" + } + ], + "name": "_setPrimeToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "bool", + "name": "state", + "type": "bool" + } + ], + "name": "_setProtocolPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newTreasuryGuardian", + "type": "address" + }, + { + "internalType": "address", + "name": "newTreasuryAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "newTreasuryPercent", + "type": "uint256" + } + ], + "name": "_setTreasuryData", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract VAIControllerInterface", + "name": "vaiController_", + "type": "address" + } + ], + "name": "_setVAIController", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "newVAIMintRate", + "type": "uint256" + } + ], + "name": "_setVAIMintRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vault_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "releaseStartBlock_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minReleaseAmount_", + "type": "uint256" + } + ], + "name": "_setVAIVaultInfo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "supplySpeeds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "borrowSpeeds", + "type": "uint256[]" + } + ], + "name": "_setVenusSpeeds", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "venusVAIVaultRate_", + "type": "uint256" + } + ], + "name": "_setVenusVAIVaultRate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "internalType": "contract VToken", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "enum ComptrollerV9Storage.Action", + "name": "action", + "type": "uint8" + } + ], + "name": "actionPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "allMarkets", + "outputs": [ + { + "internalType": "contract VToken", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "approvedDelegates", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "borrowCapGuardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "borrowCaps", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address[]", + "name": "holders", + "type": "address[]" + }, + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "borrowers", + "type": "bool" + }, + { + "internalType": "bool", + "name": "suppliers", + "type": "bool" + }, + { + "internalType": "bool", + "name": "collateral", + "type": "bool" + } + ], + "name": "claimVenus", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + } + ], + "name": "claimVenus", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + } + ], + "name": "claimVenus", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address[]", + "name": "holders", + "type": "address[]" + }, + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "borrowers", + "type": "bool" + }, + { + "internalType": "bool", + "name": "suppliers", + "type": "bool" + } + ], + "name": "claimVenus", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + } + ], + "name": "claimVenusAsCollateral", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerLens", + "outputs": [ + { + "internalType": "contract ComptrollerLensInterface", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "enum IDiamondCut.FacetCutAction", + "name": "action", + "type": "uint8" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct IDiamondCut.FacetCut[]", + "name": "diamondCut_", + "type": "tuple[]" + } + ], + "name": "diamondCut", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address[]", + "name": "vTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + } + ], + "name": "facetAddress", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "uint96", + "name": "functionSelectorPosition", + "type": "uint96" + } + ], + "internalType": "struct ComptrollerV13Storage.FacetAddressAndPosition", + "name": "", + "type": "tuple" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "facetAddresses", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + } + ], + "name": "facetFunctionSelectors", + "outputs": [ + { + "internalType": "bytes4[]", + "name": "", + "type": "bytes4[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "facet", + "type": "address" + } + ], + "name": "facetPosition", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "facets", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "facetAddress", + "type": "address" + }, + { + "internalType": "bytes4[]", + "name": "functionSelectors", + "type": "bytes4[]" + } + ], + "internalType": "struct Diamond.Facet[]", + "name": "", + "type": "tuple[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getAllMarkets", + "outputs": [ + { + "internalType": "contract VToken[]", + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "internalType": "contract VToken[]", + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenModify", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "getHypotheticalAccountLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getXVSAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getXVSVTokenAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isForcedLiquidationEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isForcedLiquidationEnabledForUser", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "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": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + } + ], + "name": "liquidateVAICalculateSeizeTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "liquidatorContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "internalType": "bool", + "name": "isListed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "collateralFactorMantissa", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isVenus", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "minReleaseAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "mintVAIGuardianPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "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": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mintedVAIs", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "internalType": "contract PriceOracle", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pauseGuardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "prime", + "outputs": [ + { + "internalType": "contract IPrime", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "protocolPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "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": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "releaseStartBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "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": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "repayVAIGuardianPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "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": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "setMintedVAIOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "supplyCaps", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "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": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "treasuryAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "treasuryGuardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "treasuryPercent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowBorrows", + "type": "bool" + } + ], + "name": "updateDelegate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "vaiController", + "outputs": [ + { + "internalType": "contract VAIControllerInterface", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "vaiMintRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "vaiVaultAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusAccrued", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusBorrowSpeeds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusBorrowState", + "outputs": [ + { + "internalType": "uint224", + "name": "index", + "type": "uint224" + }, + { + "internalType": "uint32", + "name": "block", + "type": "uint32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusBorrowerIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "venusInitialIndex", + "outputs": [ + { + "internalType": "uint224", + "name": "", + "type": "uint224" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusSupplierIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusSupplySpeeds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "venusSupplyState", + "outputs": [ + { + "internalType": "uint224", + "name": "index", + "type": "uint224" + }, + { + "internalType": "uint32", + "name": "block", + "type": "uint32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "venusVAIVaultRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-665/arbitrumone.ts b/simulations/vip-665/arbitrumone.ts new file mode 100644 index 000000000..f7ecc3a0f --- /dev/null +++ b/simulations/vip-665/arbitrumone.ts @@ -0,0 +1,4 @@ +import { runRemoteSim } from "./utils/remoteSim"; + +// Recent arbitrumone block where the CriticalTimelock still holds the permissions this VIP revokes. +runRemoteSim("arbitrumone", 483738162); diff --git a/simulations/vip-665/basemainnet.ts b/simulations/vip-665/basemainnet.ts new file mode 100644 index 000000000..7685ffd12 --- /dev/null +++ b/simulations/vip-665/basemainnet.ts @@ -0,0 +1,4 @@ +import { runRemoteSim } from "./utils/remoteSim"; + +// Recent basemainnet block where the CriticalTimelock still holds the permissions this VIP revokes. +runRemoteSim("basemainnet", 48618074); diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts new file mode 100644 index 000000000..9d0e9cd74 --- /dev/null +++ b/simulations/vip-665/bscmainnet.ts @@ -0,0 +1,205 @@ +import { TransactionResponse } from "@ethersproject/abstract-provider"; +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents, initMainnetUser } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import vip665 from "../../vips/vip-665/bscmainnet"; +import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, BNB_ROWS, ZERO } from "../../vips/vip-665/data/bnb"; +import { STALE_ROWS } from "../../vips/vip-665/data/staleness"; +import { AGGREGATOR, grantPermissions, revokePermissions, roleChangeCounts } from "../../vips/vip-665/utils/commands"; +import { seedAggregator } from "../../vips/vip-665/utils/seed"; +import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import COMPTROLLER_ABI from "./abi/Comptroller.json"; + +const { bscmainnet } = NETWORK_ADDRESSES; +// Recent BSC block where the ACMCommandsAggregator batch lengths match GRANT_INDEX / REVOKE_INDEX. +const FORK_BLOCK = 109924798; + +// A long-listed core-pool market, used to exercise the swapped _setForcedLiquidation permission. +const vUSDT = "0xfD5840Cd36d94D7229439859C0112a4185BC0255"; + +const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["address", "string"], [at, fn]); + +// One row bucket per action so every category (no-change / revoke / swap / grant / stale) is asserted +// explicitly. Each bucket is guarded to be non-empty so a data regression that empties a category fails +// loudly instead of passing vacuously. +const NO_CHANGE = BNB_ROWS.filter(r => r.action === "none"); +const REVOKE = BNB_ROWS.filter(r => r.action === "revoke"); +const SWAP = BNB_ROWS.filter(r => r.action === "swap"); +const GRANT = BNB_ROWS.filter(r => r.action === "grant"); +const STALE = BNB_ROWS.filter(r => r.action === "stale"); + +forking(FORK_BLOCK, async () => { + const acm = () => new Contract(BNB_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + const holds = (who: string, r: { target: string; signature: string }) => + acm().hasRole(role(r.target, r.signature), who); + const guardianAddr = (r: { grantTo?: "guardian1" | "guardian2" | "guardian3" }) => + BNB_GUARDIANS[r.grantTo ?? "guardian1"]; + + before(async () => { + const signer = await initMainnetUser(bscmainnet.NORMAL_TIMELOCK, ethers.utils.parseEther("2")); + await seedAggregator( + signer, + AGGREGATOR.bscmainnet, + grantPermissions("bscmainnet"), + revokePermissions("bscmainnet"), + ); + }); + + describe("VIP-665 pre-execution permissions (bscmainnet)", () => { + it("the action plan covers every category (no-change / revoke / swap / grant / stale)", () => { + expect(NO_CHANGE.length, "no-change rows").to.be.greaterThan(0); + expect(REVOKE.length, "revoke rows").to.be.greaterThan(0); + expect(SWAP.length, "swap rows").to.be.greaterThan(0); + expect(GRANT.length, "grant rows").to.be.greaterThan(0); + expect(STALE.length, "stale (BNB) rows").to.be.greaterThan(0); + expect(STALE_ROWS.length, "stale (dangling cleanup) rows").to.be.greaterThan(0); + }); + + it("no-change: Critical holds each one and Guardian flags match the plan", async () => { + for (const r of NO_CHANGE) { + expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.equal(r.critical); + expect(await holds(BNB_GUARDIANS.guardian1, r), `pre g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); + expect(await holds(BNB_GUARDIANS.guardian2, r), `pre g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); + expect(await holds(BNB_GUARDIANS.guardian3, r), `pre g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + } + }); + + it("revoke: Critical currently holds every permission to be revoked", async () => { + for (const r of REVOKE) { + expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.be.true; + expect(await holds(BNB_GUARDIANS.guardian1, r), `pre g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); + expect(await holds(BNB_GUARDIANS.guardian2, r), `pre g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); + expect(await holds(BNB_GUARDIANS.guardian3, r), `pre g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + } + }); + + it("swap: Critical holds each one and the target Guardian does not yet", async () => { + for (const r of SWAP) { + expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.be.true; + expect(await holds(guardianAddr(r), r), `pre guardian ${r.signature}@${r.target}`).to.be.false; + } + }); + + it("grant: Critical holds each one and the target Guardian does not yet", async () => { + for (const r of GRANT) { + expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.be.true; + expect(await holds(guardianAddr(r), r), `pre guardian ${r.signature}@${r.target}`).to.be.false; + } + }); + + it("stale (BNB rows): Critical currently holds each dangling permission", async () => { + for (const r of STALE) { + expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.be.true; + expect(await holds(BNB_GUARDIANS.guardian1, r), `pre g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); + expect(await holds(BNB_GUARDIANS.guardian2, r), `pre g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); + expect(await holds(BNB_GUARDIANS.guardian3, r), `pre g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + } + }); + + it("stale (dangling cleanup): every listed grantee currently holds the dangling permission", async () => { + for (const s of STALE_ROWS) + for (const who of s.revokeFrom) + expect(await holds(who, s), `pre stale ${s.signature}@${s.target} ${who}`).to.be.true; + }); + }); + + const counts = roleChangeCounts("bscmainnet"); + // The BNB ACM (legacy) emits only the OZ Role events, not PermissionGranted/Revoked. Each giveCallPermission + // grants a role and each revokeCallPermission revokes one; the aggregator wrapper adds exactly one more of + // each (grant/revoke of DEFAULT_ADMIN_ROLE to the aggregator). So counts = batch counts + 1. + testVip("VIP-665 Reduce CriticalTimelock privileges — BNB Chain", await vip665(), { + callbackAfterExecution: async (txResponse: TransactionResponse) => { + await expectEvents( + txResponse, + [ACCESS_CONTROL_MANAGER_ABI], + ["RoleGranted", "RoleRevoked"], + [counts.granted + 1, counts.revoked + 1], + ); + await expectEvents( + txResponse, + [ACM_COMMANDS_AGGREGATOR_ABI], + ["GrantPermissionsExecuted", "RevokePermissionsExecuted"], + [1, 1], + ); + }, + }); + + describe("VIP-665 post-execution permissions (bscmainnet)", () => { + it("no-change: holders are untouched (Critical and every Guardian flag unchanged)", async () => { + for (const r of NO_CHANGE) { + expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.equal(r.critical); + expect(await holds(BNB_GUARDIANS.guardian1, r), `post g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); + expect(await holds(BNB_GUARDIANS.guardian2, r), `post g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); + expect(await holds(BNB_GUARDIANS.guardian3, r), `post g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + } + }); + + it("revoke: Critical lost each one; Guardian flags unchanged", async () => { + for (const r of REVOKE) { + expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.be.false; + expect(await holds(BNB_GUARDIANS.guardian1, r), `post g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); + expect(await holds(BNB_GUARDIANS.guardian2, r), `post g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); + expect(await holds(BNB_GUARDIANS.guardian3, r), `post g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + } + }); + + it("swap: Critical lost each one and the target Guardian gained it", async () => { + for (const r of SWAP) { + expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.be.false; + expect(await holds(guardianAddr(r), r), `post guardian ${r.signature}@${r.target}`).to.be.true; + } + }); + + it("grant: the target Guardian gained each one while Critical kept it", async () => { + for (const r of GRANT) { + expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.be.true; + expect(await holds(guardianAddr(r), r), `post guardian ${r.signature}@${r.target}`).to.be.true; + } + }); + + it("stale (BNB rows): Critical lost each dangling permission; Guardian flags unchanged", async () => { + for (const r of STALE) { + expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.be.false; + expect(await holds(BNB_GUARDIANS.guardian1, r), `post g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); + expect(await holds(BNB_GUARDIANS.guardian2, r), `post g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); + expect(await holds(BNB_GUARDIANS.guardian3, r), `post g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + } + }); + + it("stale (dangling cleanup): every listed grantee lost the dangling permission", async () => { + for (const s of STALE_ROWS) + for (const who of s.revokeFrom) + expect(await holds(who, s), `post stale ${s.signature}@${s.target} ${who}`).to.be.false; + }); + }); + + describe("Post-VIP behavioral: swapped permissions follow the ACM authorization checks", () => { + it("every swapped function is allowed for the target Guardian and denied for Critical", async () => { + for (const r of SWAP.filter(x => x.target !== ZERO)) { + expect( + await acm().isAllowedToCall(BNB_CRITICAL, r.signature, { from: r.target }), + `crit !allowed ${r.signature}`, + ).to.be.false; + expect( + await acm().isAllowedToCall(guardianAddr(r), r.signature, { from: r.target }), + `guardian allowed ${r.signature}`, + ).to.be.true; + } + }); + + it("Guardian 1 can call Unitroller._setForcedLiquidation; the CriticalTimelock can no longer", async () => { + const guardianSigner = await initMainnetUser(BNB_GUARDIANS.guardian1, ethers.utils.parseEther("1")); + const criticalSigner = await initMainnetUser(bscmainnet.CRITICAL_TIMELOCK, ethers.utils.parseEther("1")); + const asGuardian = new Contract(bscmainnet.UNITROLLER, COMPTROLLER_ABI, guardianSigner); + const asCritical = new Contract(bscmainnet.UNITROLLER, COMPTROLLER_ABI, criticalSigner); + + await expect(asGuardian._setForcedLiquidation(vUSDT, true)).to.not.be.reverted; + await expect(asCritical._setForcedLiquidation(vUSDT, true)).to.be.reverted; + }); + }); +}); diff --git a/simulations/vip-665/ethereum.ts b/simulations/vip-665/ethereum.ts new file mode 100644 index 000000000..67e84075c --- /dev/null +++ b/simulations/vip-665/ethereum.ts @@ -0,0 +1,4 @@ +import { runRemoteSim } from "./utils/remoteSim"; + +// Recent ethereum block where the CriticalTimelock still holds the permissions this VIP revokes. +runRemoteSim("ethereum", 25530333); diff --git a/simulations/vip-665/opbnbmainnet.ts b/simulations/vip-665/opbnbmainnet.ts new file mode 100644 index 000000000..466858458 --- /dev/null +++ b/simulations/vip-665/opbnbmainnet.ts @@ -0,0 +1,4 @@ +import { runRemoteSim } from "./utils/remoteSim"; + +// Recent opbnbmainnet block where the CriticalTimelock still holds the permissions this VIP revokes. +runRemoteSim("opbnbmainnet", 163634294); diff --git a/simulations/vip-665/opmainnet.ts b/simulations/vip-665/opmainnet.ts new file mode 100644 index 000000000..c1399bf60 --- /dev/null +++ b/simulations/vip-665/opmainnet.ts @@ -0,0 +1,4 @@ +import { runRemoteSim } from "./utils/remoteSim"; + +// Recent opmainnet block where the CriticalTimelock still holds the permissions this VIP revokes. +runRemoteSim("opmainnet", 154213361); diff --git a/simulations/vip-665/unichainmainnet.ts b/simulations/vip-665/unichainmainnet.ts new file mode 100644 index 000000000..72a562377 --- /dev/null +++ b/simulations/vip-665/unichainmainnet.ts @@ -0,0 +1,4 @@ +import { runRemoteSim } from "./utils/remoteSim"; + +// Recent unichainmainnet block where the CriticalTimelock still holds the permissions this VIP revokes. +runRemoteSim("unichainmainnet", 53277143); diff --git a/simulations/vip-665/utils/remoteSim.ts b/simulations/vip-665/utils/remoteSim.ts new file mode 100644 index 000000000..069b0a4a9 --- /dev/null +++ b/simulations/vip-665/utils/remoteSim.ts @@ -0,0 +1,103 @@ +import { TransactionResponse } from "@ethersproject/abstract-provider"; +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents, initMainnetUser } from "src/utils"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import vip665 from "../../../vips/vip-665/bscmainnet"; +import { ZERO } from "../../../vips/vip-665/data/bnb"; +import { REMOTE_ACM, remoteRowsFor } from "../../../vips/vip-665/data/remote"; +import { + AGGREGATOR, + Chain, + grantPermissions, + revokePermissions, + roleChangeCounts, +} from "../../../vips/vip-665/utils/commands"; +import { seedAggregator } from "../../../vips/vip-665/utils/seed"; +import ACCESS_CONTROL_MANAGER_ABI from "../abi/AccessControlManager.json"; + +type RemoteChain = Exclude; + +const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["address", "string"], [at, fn]); + +// RoleGranted / RoleRevoked are emitted by every ACM version. Remotes have no grants, so the only +// RoleGranted is the wrapper grantRole(DEFAULT_ADMIN_ROLE) and RoleRevoked = revokes + the wrapper +// revokeRole. + +// Shared body for the 7 remote-chain simulations. Run each with its matching --fork. +export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { + const critical = NETWORK_ADDRESSES[chain].CRITICAL_TIMELOCK; + const guardian = NETWORK_ADDRESSES[chain].GUARDIAN; + + forking(forkBlock, async () => { + before(async () => { + const signer = await initMainnetUser(NETWORK_ADDRESSES[chain].NORMAL_TIMELOCK, ethers.utils.parseEther("2")); + await seedAggregator(signer, AGGREGATOR[chain], grantPermissions(chain), revokePermissions(chain)); + }); + + const rows = remoteRowsFor(chain); + + describe(`VIP-665 pre-execution permissions (${chain})`, () => { + it("the plan has at least one revoke row for this chain", () => { + expect(rows.length, `revoke rows for ${chain}`).to.be.greaterThan(0); + }); + + it("revoke: Critical currently holds every permission to be revoked", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const r of rows) + expect(await acm.hasRole(role(r.target, r.signature), critical), `pre critical ${r.signature}@${r.target}`).to + .be.true; + }); + + it("no-change: the Guardian flag matches the plan for every row", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const r of rows) + expect( + await acm.hasRole(role(r.target, r.signature), guardian), + `pre guardian ${r.signature}@${r.target}`, + ).to.equal(r.guardian); + }); + }); + + const counts = roleChangeCounts(chain); + testForkedNetworkVipCommands(`VIP-665 ${chain}`, await vip665(), { + callbackAfterExecution: async (txResponse: TransactionResponse) => { + await expectEvents( + txResponse, + [ACCESS_CONTROL_MANAGER_ABI], + ["RoleGranted", "RoleRevoked"], + [counts.granted + 1, counts.revoked + 1], + ); + }, + }); + + describe(`VIP-665 post-execution permissions (${chain})`, () => { + it("revoke: Critical lost every revoked permission", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const r of rows) + expect(await acm.hasRole(role(r.target, r.signature), critical), `post critical ${r.signature}@${r.target}`) + .to.be.false; + }); + + it("no-change: the Guardian flag is unchanged for every row", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const r of rows) + expect( + await acm.hasRole(role(r.target, r.signature), guardian), + `post guardian ${r.signature}@${r.target}`, + ).to.equal(r.guardian); + }); + + it("behavioral: Critical is no longer allowed to call any revoked function", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const r of rows) + if (r.target !== ZERO) + expect(await acm.isAllowedToCall(critical, r.signature, { from: r.target }), `crit !allowed ${r.signature}`) + .to.be.false; + }); + }); + }); +}; diff --git a/simulations/vip-665/zksyncmainnet.ts b/simulations/vip-665/zksyncmainnet.ts new file mode 100644 index 000000000..c33d4f995 --- /dev/null +++ b/simulations/vip-665/zksyncmainnet.ts @@ -0,0 +1,4 @@ +import { runRemoteSim } from "./utils/remoteSim"; + +// Recent zksyncmainnet block where the CriticalTimelock still holds the permissions this VIP revokes. +runRemoteSim("zksyncmainnet", 71165006); diff --git a/vips/vip-665/bscmainnet.ts b/vips/vip-665/bscmainnet.ts new file mode 100644 index 000000000..10c17aecf --- /dev/null +++ b/vips/vip-665/bscmainnet.ts @@ -0,0 +1,92 @@ +import { Command, ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +import { LZ_CHAIN_ID, RemoteChain } from "./data/remote"; +import { + AGGREGATOR, + Chain, + DEFAULT_ADMIN_ROLE, + GRANT_INDEX, + REVOKE_INDEX, + acmOf, + grantPermissions, + revokePermissions, +} from "./utils/commands"; + +// The commands the VIP emits per chain: grant the aggregator DEFAULT_ADMIN_ROLE, execute the grant and/or +// revoke batch, revoke the role. Local on BNB; wrapped with dstChainId (LayerZero) on remotes. +const aggregatorCommands = (chain: Chain): Command[] => { + const acm = acmOf(chain); + const agg = AGGREGATOR[chain]; + const route = chain === "bscmainnet" ? {} : { dstChainId: LZ_CHAIN_ID[chain as RemoteChain] }; + const commands: Command[] = [ + { target: acm, signature: "grantRole(bytes32,address)", params: [DEFAULT_ADMIN_ROLE, agg], ...route }, + ]; + if (grantPermissions(chain).length > 0) + commands.push({ + target: agg, + signature: "executeGrantPermissions(uint256)", + params: [GRANT_INDEX[chain]], + ...route, + }); + if (revokePermissions(chain).length > 0) + commands.push({ + target: agg, + signature: "executeRevokePermissions(uint256)", + params: [REVOKE_INDEX[chain]], + ...route, + }); + commands.push({ target: acm, signature: "revokeRole(bytes32,address)", params: [DEFAULT_ADMIN_ROLE, agg], ...route }); + return commands; +}; + +const meta = { + version: "v2", + title: "VIP-665 [Multi-Chain] Reduce CriticalTimelock privileges", + description: `#### Summary + +This proposal hardens governance by removing high-severity powers from the CriticalTimelock on every mainnet, and — for a small set of BNB Chain functions where a Guardian multisig does not already hold them — moving them to the Guardian. It also cleans up dangling permissions left on removed setters and retired contracts. + +#### Description + +A proposal routed through the Critical route executes in roughly 7 hours on BNB Chain and 8 hours on remote chains once voting, queue and timelock delays are counted. To shrink that fast-path attack surface, this VIP takes the high-severity powers off the CriticalTimelock across BNB Chain, Ethereum, Arbitrum One, Base, zkSync Era, OP Mainnet, Unichain and opBNB. The full per-contract, per-chain list of permissions changed is in the accompanying community post and the pull request. + +Actions per chain: revoke the listed permissions from the CriticalTimelock; on BNB Chain, grant a few functions to Guardian 1 (swap) and grant one to Guardian 1 while keeping Critical (add); and revoke dangling grants on removed setters and retired contracts from every current holder. + +#### Execution model + +To keep the whole change in one proposal within the BNB Chain per-transaction gas limit, every chain is executed through its pre-seeded ACMCommandsAggregator. For each chain the proposal grants the aggregator the ACM DEFAULT_ADMIN_ROLE, calls executeGrantPermissions and/or executeRevokePermissions by batch index, and revokes the role — all in the same proposal. Each batch contains only the giveCallPermission / revokeCallPermission calls for that chain. + +#### Security and additional considerations + +- **Scoped privilege**: the aggregator's DEFAULT_ADMIN_ROLE grant is scoped to this proposal — granted, used once, and revoked in the same transaction sequence, per chain. +- **VIP execution simulation**: validated in a fork environment that every listed permission moved as intended (revoke / swap / grant), that "No change" permissions are untouched, and that the expected ACM events fire. +- **Cross-chain payload size**: each LayerZero message carries only 3 commands, well under the Relayer cap. + +#### Voting options + +- **For** — Execute the proposal +- **Against** — Do not execute the proposal +- **Abstain** — Indifferent to execution`, + 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", +}; + +export const vip665 = () => + makeProposal( + [ + ...aggregatorCommands("bscmainnet"), + ...aggregatorCommands("ethereum"), + ...aggregatorCommands("arbitrumone"), + ...aggregatorCommands("basemainnet"), + ...aggregatorCommands("zksyncmainnet"), + ...aggregatorCommands("opmainnet"), + ...aggregatorCommands("unichainmainnet"), + ...aggregatorCommands("opbnbmainnet"), + ], + meta, + ProposalType.REGULAR, + ); + +export default vip665; diff --git a/vips/vip-665/data/bnb.ts b/vips/vip-665/data/bnb.ts new file mode 100644 index 000000000..e4fe10270 --- /dev/null +++ b/vips/vip-665/data/bnb.ts @@ -0,0 +1,2041 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +const { bscmainnet } = NETWORK_ADDRESSES; +export const ZERO = "0x0000000000000000000000000000000000000000"; + +export const BNB_ACM = bscmainnet.ACCESS_CONTROL_MANAGER; +export const BNB_CRITICAL = bscmainnet.CRITICAL_TIMELOCK; +// Guardian 1 = CRITICAL_GUARDIAN (swap/grant target), 2 = GUARDIAN (pause), 3 = oracles. +export const BNB_GUARDIANS = { + guardian1: bscmainnet.CRITICAL_GUARDIAN, + guardian2: bscmainnet.GUARDIAN, + guardian3: "0x3a3284dC0FaFfb0b5F0d074c4C704D14326C98cF", +}; + +// Contract addresses the action plan is scoped to (verified on-chain). +const CONTRACTS = { + Liquidator: "0x0870793286aaDA55D39CE7f82fb2766e8004cF43", + PegStability_USDT: "0xC138aa4E424D1A8539e8F38Af5a754a2B7c3Cc36", + Prime: "0xBbCD063efE506c3D42a0Fa2dB5C08430288C71FC", + PrimeLiquidityProvider: "0x23c4F844ffDdC6161174eB32c770D4D8C07833F2", + PrimeV2: "0x059EabA8676b03e4e8f009eFb7F587C28450F50f", + Unitroller: "0xfD36E2c2a6789Db23113685031d7F16329158384", + VaiUnitroller: "0x004065D34C6b18cE4370ced1CeBDE94865DbFAFE", + VAIVaultProxy: "0x0667Eed0a0aAb930af74a3dfeDD263A73994f216", + VBNBAdmin: "0x9A7890534d9d91d473F28cB97962d176e2B65f1d", + VRTVaultProxy: "0x98bF4786D72AAEF6c714425126Dd92f149e3F334", + XVSVaultProxy: "0x051100480289e704d20e9DB4804837068f3f9204", + BinanceOracle: "0x594810b741d136f1960141C0d8Fb4a91bE78A820", + ChainlinkOracle: "0x1B2103441A0A108daD8848D8F5d790e4D402921F", + DeviationBoundedOracle: "0xc79Cb7efEBd121DC4B39eA141C214606595D665A", + PythOracle: "0xb893E38162f55fb80B18Aa44da76FaDf8E9B2262", + RedStoneOracle: "0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a", + ResilientOracle: "0x6592b5DE802159F3E74B2486b091D11a8256ab8A", + USDTChainlinkOracle: "0x22Dc2BAEa32E95AB07C2F5B8F63336CbF61aB6b8", + BTCBPrimeConverter: "0xE8CeAa79f082768f99266dFd208d665d2Dd18f53", + ConverterNetwork: "0xF7Caad5CeB0209165f2dFE71c92aDe14d0F15995", + ETHPrimeConverter: "0xca430B8A97Ea918fF634162acb0b731445B8195E", + ProtocolShareReserve: "0xCa01D5A9A248a830E9D93231e791B1afFed7c446", + RiskFundConverter: "0xA5622D276CcbB8d9BBE3D1ffd1BB11a0032E53F0", + RiskFundV2: "0xdF31a28D68A2AB381D42b380649Ead7ae2A76E42", + USDCPrimeConverter: "0xa758c9C215B6c4198F0a0e3FA46395Fa15Db691b", + USDTPrimeConverter: "0xD9f101AA67F3D72662609a2703387242452078C3", + WBNBBurnConverter: "0x9eF79830e626C8ccA7e46DCEd1F90e51E7cFCeBE", + XVSVaultConverter: "0xd5b9AE835F4C59272032B3B954417179573331E0", + XVSVaultTreasury: "0x269ff7818DB317f60E386D2be0B259e1a324a40a", + Comptroller_DeFi: "0x3344417c9360b963ca93A4e8305361AEde340Ab9", + Comptroller_GameFi: "0x1b43ea8622e76627B81665B1eCeBB4867566B963", + Comptroller_LiquidStakedBNB: "0xd933909A4a2b7A4638903028f44D1d38ce27c352", + Comptroller_Stablecoins: "0x94c1495cD4c557f1560Cbd68EAB0d197e6291571", + Comptroller_Tron: "0x23b4404E4E5eC5FF5a6FFb70B7d14E3FabF237B0", + Shortfall: "0xf37530A8a810Fcb501AA0Ecd0B0699388F0F2209", + DeviationSentinel: "0x6599C15cc8407046CD91E5c0F8B7f765fF914870", + EBrake: "0x35eBaBB99c7Fb7ba0C90bCc26e5d55Cdf89C23Ec", + Executor: "0xDd541A1b065F9587b01815a390a4d4559D7b630F", + PancakeSwapOracle: "0x44B72078240A3509979faF450085Fa818401D32E", + PendlePTVaultAdapter: "0x60Db419d8ea13C5827072Cf693D13cA1Ec6E0B4a", + RelativePositionManager: "0x1525D804DFff218DcC8B9359940F423209356C42", + SentinelOracle: "0x58eae0Cf4215590E19860b66b146C5d539cb6f14", + UniswapOracle: "0x8FD05458faf220B2324c4BFbb29DBC4B3CF6f23f", + AuxiliaryCommandsAggregator: "0x528A428748dfE73DFcc844176B401475D1831057", + OmnichainProposalSender: "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6", + RiskOracle: "0x0E3E51958b0Daa8C57c949675975CBEDd7b5a1a1", + RiskStewardReceiver: "0x47856bFa74B71d24a5545c7506862B8FddE52baB", + XVSBridgeAdmin: "0x70d644877b7b73800E9073BCFCE981eAaB6Dbc21", + InstitutionalVaultControllerProxy: "0x6D9e91cB766259af42619c14c994E694E57e6E85", + LiquidationAdapterProxy: "0x17A6222fB8b4b6D852cA54f5bc376a6A2c6224Bd", +}; + +export type Action = "none" | "revoke" | "swap" | "grant" | "stale"; +// signature = ACM-registered function signature; target = contract it is scoped to; +// critical/guardian1/guardian2/guardian3 = current holders; action = final action; +// grantTo = destination guardian for swap/grant actions. +export const BNB_ROWS: { + signature: string; + target: string; + critical: boolean; + guardian1: boolean; + guardian2: boolean; + guardian3: boolean; + action: Action; + grantTo?: "guardian1" | "guardian2" | "guardian3"; +}[] = [ + { + signature: "addToAllowlist(address,address)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "removeFromAllowlist(address,address)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "restrictLiquidation(address)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTreasuryPercent(uint256)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "unrestrictLiquidation(address)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseForceVAILiquidate()", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeForceVAILiquidate()", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setVAIMintCap(uint256)", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setFeeIn(uint256)", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setFeeOut(uint256)", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resume()", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addMarket(address,address,uint256,uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "addMarket(address,uint256,uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "burn(address)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "issue(bool,address[])", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateMultipliers(address,uint256,uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLimit(uint256,uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMaxLoopsLimit(uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setStakedAt(address[],uint256[])", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateAlpha(uint128,uint128)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "togglePause()", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMaxLoopsLimit(uint256)", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMaxTokensDistributionSpeed(address[],uint256[])", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setTokensDistributionSpeed(address[],uint256[])", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseFundsTransfer()", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeFundsTransfer()", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.PrimeV2, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.PrimeV2, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addPoolMarkets(uint96[],address[])", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "createPool(string)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "seizeVenus(address[],address)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "seizeVenus(address[],address,address[])", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setCollateralFactor(address,uint256,uint256)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "revoke", + }, + { + signature: "setCollateralFactor(uint96,address,uint256,uint256)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "revoke", + }, + { + signature: "setWhiteListFlashLoanAccount(address,bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "_setMarketBorrowCaps(address[],uint256[])", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "revoke", + }, + { + signature: "_setMarketSupplyCaps(address[],uint256[])", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "revoke", + }, + { + signature: "removePoolMarket(uint96,address)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setAllowCorePoolFallback(uint96,bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setFlashLoanPaused(bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setIsBorrowAllowed(uint96,address,bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "setPoolActive(uint96,bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setPoolLabel(uint96,string)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "unlistMarket(address)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "_setActionsPaused(address[],uint8[],bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "_setForcedLiquidation(address,bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "swap", + grantTo: "guardian1", + }, + { + signature: "_setForcedLiquidationForUser(address,address,bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "swap", + grantTo: "guardian1", + }, + { + signature: "_setProtocolPaused(bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setBaseRate(uint256)", + target: CONTRACTS.VaiUnitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setFloatRate(uint256)", + target: CONTRACTS.VaiUnitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMintCap(uint256)", + target: CONTRACTS.VaiUnitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "toggleOnlyPrimeHolderMint()", + target: CONTRACTS.VaiUnitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.VAIVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resume()", + target: CONTRACTS.VAIVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setInterestRateModel(address)", + target: CONTRACTS.VBNBAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.VRTVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resume()", + target: CONTRACTS.VRTVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setRewardAmountPerBlockOrSecond(address,uint256)", + target: CONTRACTS.XVSVaultProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.XVSVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resume()", + target: CONTRACTS.XVSVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "setMaxStalePeriod(string,uint256)", + target: CONTRACTS.BinanceOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "none", + }, + { + signature: "setSymbolOverride(string,string)", + target: CONTRACTS.BinanceOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "none", + }, + { + signature: "setDirectPrice(address,uint256)", + target: CONTRACTS.ChainlinkOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.ChainlinkOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "setUnderlyingPrice(address,uint256)", + target: CONTRACTS.ChainlinkOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "setThresholds(address,uint256,uint256)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "grant", + grantTo: "guardian1", + }, + { + signature: "setTokenConfig((address,uint64,uint256,uint256,bool,bool))", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setTokenConfigs((address,uint64,uint256,uint256,bool,bool)[])", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateMaxPrice(address,uint128)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "updateMinPrice(address,uint128)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setAssetBoundedPricingEnabled(address,bool)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setCachingEnabled(address,bool)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setCooldownPeriod(address,uint64)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "syncPriceBoundsAndProtections((address,uint8,uint256)[])", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "exitProtectionMode(address)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.PythOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "setDirectPrice(address,uint256)", + target: CONTRACTS.RedStoneOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.RedStoneOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.ResilientOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "pause()", + target: CONTRACTS.ResilientOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.ResilientOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "none", + }, + { + signature: "setDirectPrice(address,uint256)", + target: CONTRACTS.USDTChainlinkOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.USDTChainlinkOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "revoke", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.BTCBPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.BTCBPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.BTCBPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.BTCBPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addTokenConverter(address)", + target: CONTRACTS.ConverterNetwork, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removeTokenConverter(address)", + target: CONTRACTS.ConverterNetwork, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.ETHPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.ETHPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.ETHPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.ETHPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addOrUpdateDistributionConfigs(DistributionConfig[])", + target: CONTRACTS.ProtocolShareReserve, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "revoke", + }, + { + signature: "removeDistributionConfig(Schema,address)", + target: CONTRACTS.ProtocolShareReserve, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setPoolsAssetsDirectTransfer(address[],address[][],bool[][])", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.RiskFundV2, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.USDCPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.USDCPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.USDCPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.USDCPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.USDTPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.USDTPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "stale", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.USDTPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.USDTPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.WBNBBurnConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.WBNBBurnConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.WBNBBurnConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.WBNBBurnConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.XVSVaultConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.XVSVaultConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.XVSVaultConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.XVSVaultConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "fundXVSVault(uint256)", + target: CONTRACTS.XVSVaultTreasury, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_DeFi, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_GameFi, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_LiquidStakedBNB, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_Stablecoins, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_Tron, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateIncentiveBps(uint256)", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateMinimumPoolBadDebt(uint256)", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateNextBidderBlockLimit(uint256)", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateWaitForFirstBidder(uint256)", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseAuctions()", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeAuctions()", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTokenConfig(address,(uint8,bool))", + target: CONTRACTS.DeviationSentinel, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resetMarketState(address)", + target: CONTRACTS.DeviationSentinel, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTokenMonitoringEnabled(address,bool)", + target: CONTRACTS.DeviationSentinel, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTrustedKeeper(address,bool)", + target: CONTRACTS.DeviationSentinel, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "decreaseCF(address,uint256)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "decreaseCF(address,uint96,uint256)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "revokeFlashLoanAccess(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMarketBorrowCaps(address[],uint256[])", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMarketSupplyCaps(address[],uint256[])", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "disablePoolBorrow(uint96,address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseActions(address[],uint8[])", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseBorrow(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseFlashLoan()", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseRedeem(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseSupply(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseTransfer(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resetBorrowCapSnapshot(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resetCFSnapshot(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resetSupplyCapSnapshot(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMarketConfig(address,(uint256,uint256,bool))", + target: CONTRACTS.Executor, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setPoolConfig(address,address)", + target: CONTRACTS.PancakeSwapOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.PendlePTVaultAdapter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.PendlePTVaultAdapter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "executePositionAccountCall(address,address[],bytes[])", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "addDSAVToken(address)", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setDSAVTokenActive(uint8,bool)", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setProportionalCloseTolerance(uint256)", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "completePause()", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "completeUnpause()", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "partialPause()", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "partialUnpause()", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setDirectPrice(address,uint256)", + target: CONTRACTS.SentinelOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "setTokenOracleConfig(address,address)", + target: CONTRACTS.SentinelOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "setPoolConfig(address,address)", + target: CONTRACTS.UniswapOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addAuthorizedBatchers(address[])", + target: CONTRACTS.AuxiliaryCommandsAggregator, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "executeBatch(uint256)", + target: CONTRACTS.AuxiliaryCommandsAggregator, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removeAuthorizedBatchers(address[])", + target: CONTRACTS.AuxiliaryCommandsAggregator, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "execute(uint16,bytes,bytes,address)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "retryExecute(uint256,uint16,bytes,bytes,address,uint256)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConfig(uint16,uint16,uint256,bytes)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removeTrustedRemote(uint16)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMaxDailyLimit(uint16,uint256)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setSendVersion(uint16)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "removeAuthorizedSender(address)", + target: CONTRACTS.RiskOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setUpdateTypeActive(string,bool)", + target: CONTRACTS.RiskOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setWhitelistedExecutor(address,bool)", + target: CONTRACTS.RiskStewardReceiver, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConfigActive(string,bool)", + target: CONTRACTS.RiskStewardReceiver, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setPaused(bool)", + target: CONTRACTS.RiskStewardReceiver, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConfig(uint16,uint16,uint256,bytes)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setWhitelist(address,bool)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "swap", + grantTo: "guardian1", + }, + { + signature: "dropFailedMessage(uint16,bytes,uint64)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "forceResumeReceive(uint16,bytes)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removeTrustedRemote(uint16)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMaxDailyLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "setMaxDailyReceiveLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "setMaxSingleReceiveTransactionLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "setMaxSingleTransactionLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "setMinDstGas(uint16,uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setPayloadSizeLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setReceiveVersion(uint16)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setSendVersion(uint16)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateSendAndCallEnabled(bool)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "revoke", + }, + { + signature: "createVault(VaultConfig,InstitutionalConfig,RiskConfig,string,string,string)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLiquidationIncentive(address,uint256)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLiquidationThreshold(address,uint256)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "swap", + grantTo: "guardian1", + }, + { + signature: "setVaultImplementation(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "sweep(address,address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "revoke", + }, + { + signature: "approvePositionTransfer(address,address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "cancelVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "closeVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "openVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "revokePositionTransfer(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setInstitutionName(address,string)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setInstitutionNameOverride(address,string)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLatePenaltyRate(address,uint256)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "completePauseVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "partialPauseVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "unpauseVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setCloseFactor(uint256)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "sweepProtocolShareToReserve(address)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLiquidatorWhitelist(address,bool)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setProtocolLiquidationShare(uint256)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setSettlerWhitelist(address,bool)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, +]; diff --git a/vips/vip-665/data/remote.ts b/vips/vip-665/data/remote.ts new file mode 100644 index 000000000..bdac571c6 --- /dev/null +++ b/vips/vip-665/data/remote.ts @@ -0,0 +1,184 @@ +// Critical-timelock action plan — remote chains (7), reconciled against live ACM state. +// Every remote action is a revoke from Critical (the Guardian keeps whatever it already holds); there are +// no swaps/grants on remotes. +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; + +export const ZERO = "0x0000000000000000000000000000000000000000"; + +export type RemoteChain = + | "ethereum" + | "arbitrumone" + | "basemainnet" + | "zksyncmainnet" + | "opmainnet" + | "unichainmainnet" + | "opbnbmainnet"; + +export const REMOTE_CHAINS: RemoteChain[] = [ + "ethereum", + "arbitrumone", + "basemainnet", + "zksyncmainnet", + "opmainnet", + "unichainmainnet", + "opbnbmainnet", +]; + +export const LZ_CHAIN_ID: Record = { + ethereum: LzChainId.ethereum, + arbitrumone: LzChainId.arbitrumone, + basemainnet: LzChainId.basemainnet, + zksyncmainnet: LzChainId.zksyncmainnet, + opmainnet: LzChainId.opmainnet, + unichainmainnet: LzChainId.unichainmainnet, + opbnbmainnet: LzChainId.opbnbmainnet, +}; + +// ACM for op / unichain / opBNB is not in networkAddresses — hardcoded (verified on-chain). +export const REMOTE_ACM: Record = { + ethereum: NETWORK_ADDRESSES.ethereum.ACCESS_CONTROL_MANAGER, + arbitrumone: NETWORK_ADDRESSES.arbitrumone.ACCESS_CONTROL_MANAGER, + basemainnet: NETWORK_ADDRESSES.basemainnet.ACCESS_CONTROL_MANAGER, + zksyncmainnet: NETWORK_ADDRESSES.zksyncmainnet.ACCESS_CONTROL_MANAGER, + opmainnet: "0xD71b1F33f6B0259683f11174EE4Ddc2bb9cE4eD6", + unichainmainnet: "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0", + opbnbmainnet: "0xA60Deae5344F1152426cA440fb6552eA0e3005D6", +}; + +// Per-chain contract addresses that networkAddresses does not key. +const XVS_BRIDGE_ADMIN: Record = { + ethereum: "0x9C6C95632A8FB3A74f2fB4B7FfC50B003c992b96", + arbitrumone: "0xf5d81C6F7DAA3F97A6265C8441f92eFda22Ad784", + basemainnet: "0x6303FEcee7161bF959d65df4Afb9e1ba5701f78e", + zksyncmainnet: "0x2471043F05Cc41A6051dd6714DC967C7BfC8F902", + opmainnet: "0x3c307DF1Bf3198a2417d9CA86806B307D147Ddf7", + unichainmainnet: "0x2EAaa880f97C9B63d37b39b0b316022d93d43604", + opbnbmainnet: "0x52fcE05aDbf6103d71ed2BA8Be7A317282731831", +}; + +const OMNICHAIN_EXECUTOR_OWNER: Record = { + ethereum: "0x87Ed3Fd3a25d157637b955991fb1B41B566916Ba", + arbitrumone: "0xf72C1Aa0A1227B4bCcB28E1B1015F0616E2db7fD", + basemainnet: "0x8BA591f72a90fb379b9a82087b190d51b226F0a9", + zksyncmainnet: "0xdfaed3E5d9707629Ed5c225b4fB980c064286771", + opmainnet: "0xe6d9Eb3A07a1dc4496fc71417D7A7b9d5666BaA3", + unichainmainnet: "0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd", + opbnbmainnet: "0xf7e4c81Cf4A03d52472a4d00c3d9Ef35aF127E45", +}; + +// SentinelOracle is not published in the @venusprotocol deployment packages — hardcoded proxies, +// verified on-chain. +const SENTINEL_ORACLE: Partial> = { + ethereum: "0x444C53E194B40c272fAd683210e2cB1c16Ab132e", + arbitrumone: "0x3563CAbc541a0432C66A64942ffB4070a9726226", + basemainnet: "0xCdD6D79Fd313C21967CED04C1b8bE70BDc27574D", +}; + +const addressesOf = (chain: RemoteChain) => NETWORK_ADDRESSES[chain] as Record; + +// Resolve a contract key to its address on a chain. On Arbitrum/OP the "CHAINLINK_ORACLE" key is the +// SequencerChainlinkOracle adapter. +export const remoteAddr = (chain: RemoteChain, c: string): string => { + switch (c) { + case "WILDCARD": + return ZERO; + case "ResilientOracle": + return addressesOf(chain).RESILIENT_ORACLE; + case "ChainlinkOracle": + return addressesOf(chain).CHAINLINK_ORACLE; + case "RedStoneOracle": + return addressesOf(chain).REDSTONE_ORACLE; + case "SequencerChainlinkOracle": + return addressesOf(chain).CHAINLINK_ORACLE; + case "SentinelOracle": + return SENTINEL_ORACLE[chain]!; + case "XVSBridgeAdmin": + return XVS_BRIDGE_ADMIN[chain]; + case "OmnichainExecutorOwner": + return OMNICHAIN_EXECUTOR_OWNER[chain]; + default: + throw new Error(`unknown remote contract key ${c}`); + } +}; + +const ALL_REMOTES = REMOTE_CHAINS; + +// Every row is a revoke from Critical. contract = contract key (resolved per-chain); chains = where it +// applies; guardian = Guardian currently holds it (must still hold post-VIP). +export const REMOTE_ROWS: { signature: string; contract: string; chains: RemoteChain[]; guardian: boolean }[] = [ + // ── Common to all 7 remotes ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle", chains: ALL_REMOTES, guardian: true }, + { + signature: "setCollateralFactor(address,uint256,uint256)", + contract: "WILDCARD", + chains: ALL_REMOTES, + guardian: true, + }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner", chains: ALL_REMOTES, guardian: true }, + { + signature: "setMaxDailyReceiveLimit(uint256)", + contract: "OmnichainExecutorOwner", + chains: ALL_REMOTES, + guardian: true, + }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin", chains: ALL_REMOTES, guardian: false }, + + // ── Chain-specific ── + { + signature: "setDirectPrice(address,uint256)", + contract: "ChainlinkOracle", + chains: ["ethereum", "basemainnet", "zksyncmainnet"], + guardian: true, + }, + { + signature: "setTokenConfig(TokenConfig)", + contract: "ChainlinkOracle", + chains: ["ethereum", "basemainnet", "zksyncmainnet"], + guardian: true, + }, + { + signature: "setDirectPrice(address,uint256)", + contract: "RedStoneOracle", + chains: ["ethereum", "arbitrumone", "basemainnet", "zksyncmainnet", "opmainnet", "unichainmainnet"], + guardian: true, + }, + { + signature: "setTokenConfig(TokenConfig)", + contract: "RedStoneOracle", + chains: ["ethereum", "arbitrumone", "basemainnet", "zksyncmainnet", "opmainnet", "unichainmainnet"], + guardian: true, + }, + { + signature: "setDirectPrice(address,uint256)", + contract: "SequencerChainlinkOracle", + chains: ["arbitrumone", "opmainnet"], + guardian: true, + }, + { + signature: "setTokenConfig(TokenConfig)", + contract: "SequencerChainlinkOracle", + chains: ["arbitrumone", "opmainnet"], + guardian: true, + }, + { + signature: "setDirectPrice(address,uint256)", + contract: "SentinelOracle", + chains: ["ethereum", "arbitrumone", "basemainnet"], + guardian: true, + }, + { + signature: "setTokenOracleConfig(address,address)", + contract: "SentinelOracle", + chains: ["ethereum", "arbitrumone", "basemainnet"], + guardian: true, + }, +]; + +// Rows applicable to one chain, with resolved target address. +export const remoteRowsFor = (chain: RemoteChain) => + REMOTE_ROWS.filter(r => r.chains.includes(chain)).map(r => ({ + signature: r.signature, + target: remoteAddr(chain, r.contract), + guardian: r.guardian, + })); diff --git a/vips/vip-665/data/staleness.ts b/vips/vip-665/data/staleness.ts new file mode 100644 index 000000000..70e97d7e0 --- /dev/null +++ b/vips/vip-665/data/staleness.ts @@ -0,0 +1,49 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +const { bscmainnet } = NETWORK_ADDRESSES; +export const ZERO = "0x0000000000000000000000000000000000000000"; + +const NORMAL = bscmainnet.NORMAL_TIMELOCK; +const FASTTRACK = bscmainnet.FAST_TRACK_TIMELOCK; +const CRITICAL = bscmainnet.CRITICAL_TIMELOCK; +const G1 = bscmainnet.CRITICAL_GUARDIAN; +const G2 = bscmainnet.GUARDIAN; +const G3 = "0x3a3284dC0FaFfb0b5F0d074c4C704D14326C98cF"; + +// Retired contracts (absent from every deployment file) still holding grants. +const RISK_FUND_V2 = "0xdF31a28D68A2AB381D42b380649Ead7ae2A76E42"; +const UNITROLLER = "0xfD36E2c2a6789Db23113685031d7F16329158384"; +const RETIRED_RISK_CONFIG = "0xBa2a43279a228cf9cD94d072777d8d98e7e0a229"; +const RETIRED_RISK_STEWARD = "0xE7252dccd79F2A555E314B9cdd440745b697D562"; +const RETIRED_TWAP_ORACLE = "0xea2f042e1A4f057EF8A5220e57733AD747ea8867"; + +// target = contract the permission is scoped to (ZERO = wildcard); signature = function signature; +// revokeFrom = grantees to drop it from. +export const STALE_ROWS: { target: string; signature: string; revokeFrom: string[] }[] = [ + // Removed setter — the current RiskFundV2 implementation no longer has this function. + { + target: RISK_FUND_V2, + signature: "sweepTokenFromPool(address,address,address,uint256)", + revokeFrom: [NORMAL, FASTTRACK, CRITICAL], + }, + // Legacy 2-arg setter; Guardian 1 already holds the current 3/4-arg setters. + { target: UNITROLLER, signature: "_setCollateralFactor(address,uint256)", revokeFrom: [G1] }, + // Retired risk-config contract — dangling target grants. Holders confirmed on-chain: + // pause/unpause held by Normal+FastTrack+Critical+G2; setRiskParameterConfig only by Normal; + // toggleConfigActive by Normal+FastTrack+Critical (not G2). + { target: RETIRED_RISK_CONFIG, signature: "pause()", revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G2] }, + { target: RETIRED_RISK_CONFIG, signature: "unpause()", revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G2] }, + { target: RETIRED_RISK_CONFIG, signature: "setRiskParameterConfig(string,address,uint256)", revokeFrom: [NORMAL] }, + { target: RETIRED_RISK_CONFIG, signature: "toggleConfigActive(string)", revokeFrom: [NORMAL, FASTTRACK, CRITICAL] }, + // Retired risk steward — dangling target grant. + { target: RETIRED_RISK_STEWARD, signature: "setMaxDeltaBps(uint256)", revokeFrom: [NORMAL, FASTTRACK, CRITICAL] }, + // NOTE: this retired steward was also a candidate GRANTEE of the wildcard setMarketBorrowCaps/ + // setMarketSupplyCaps powers, but it holds neither on-chain, so those two revokes would be no-ops + // and are omitted. + // Retired oracle — dangling target grant. + { + target: RETIRED_TWAP_ORACLE, + signature: "setTokenConfig(TokenConfig)", + revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G3], + }, +]; diff --git a/vips/vip-665/scripts/seedAggregators.ts b/vips/vip-665/scripts/seedAggregators.ts new file mode 100644 index 000000000..9667b09f0 --- /dev/null +++ b/vips/vip-665/scripts/seedAggregators.ts @@ -0,0 +1,40 @@ +/** + * Seeds the VIP-665 grant / revoke batches onto a chain's ACMCommandsAggregator. + * + * Run once per chain, by a funded account, BEFORE the VIP is proposed. addGrant/RevokePermissions are + * permissionless, so any signer works. The printed indices must be wired into GRANT_INDEX / REVOKE_INDEX in + * vips/vip-665/utils/commands.ts. + * + * npx hardhat run vips/vip-665/scripts/seedAggregators.ts --network + * # for zksync add: --config hardhat.config.zksync.ts + */ +import { ethers, network } from "hardhat"; + +import { AGGREGATOR, Chain, grantPermissions, revokePermissions } from "../utils/commands"; +import { seedAggregator } from "../utils/seed"; + +async function main() { + const chain = network.name as Chain; + if (!(chain in AGGREGATOR)) throw new Error(`VIP-665 has no aggregator for network "${chain}"`); + + const [signer] = await ethers.getSigners(); + const grants = grantPermissions(chain); + const revokes = revokePermissions(chain); + + console.log(`Chain ${chain} — aggregator ${AGGREGATOR[chain]}`); + console.log(` seeding ${grants.length} grant(s) and ${revokes.length} revoke(s) from ${await signer.getAddress()}`); + + const { grantIndex, revokeIndex } = await seedAggregator(signer, AGGREGATOR[chain], grants, revokes); + + if (grantIndex !== undefined) console.log(` grant batch landed at index ${grantIndex} → set GRANT_INDEX.${chain}`); + if (revokeIndex !== undefined) + console.log(` revoke batch landed at index ${revokeIndex} → set REVOKE_INDEX.${chain}`); +} + +main().then( + () => process.exit(0), + err => { + console.error(err); + process.exit(1); + }, +); diff --git a/vips/vip-665/utils/commands.ts b/vips/vip-665/utils/commands.ts new file mode 100644 index 000000000..6910abdad --- /dev/null +++ b/vips/vip-665/utils/commands.ts @@ -0,0 +1,94 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, BNB_ROWS } from "../data/bnb"; +import { REMOTE_ACM, REMOTE_CHAINS, RemoteChain, remoteRowsFor } from "../data/remote"; +import { STALE_ROWS } from "../data/staleness"; + +export type Chain = "bscmainnet" | RemoteChain; +export const CHAINS: Chain[] = ["bscmainnet", ...REMOTE_CHAINS]; + +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +// ACMCommandsAggregator per chain (deployed on every mainnet; addresses from the governance-contracts +// deployments). Each instance is bound at construction to its own chain's ACM. +export const AGGREGATOR: Record = { + bscmainnet: "0x8b443Ea6726E56DF4C4F62f80F0556bB9B2a7c64", + ethereum: "0xb78772bed6995551b64e54Cdb8e09800d86C73ee", + arbitrumone: "0x74AFeA28456a683b8fF907699Ff77138edef00f3", + basemainnet: "0xB2770DBD5146f7ee0766Dc9E3931433bb697Aa06", + zksyncmainnet: "0x88B1452e512c8fcf83889DdCfe54dF37D561Db82", + opmainnet: "0xbbEBaF646e7a3E4064a899e68565B1b439eFdf70", + unichainmainnet: "0x904D11b00bdB2740d16176cc00DE139d0d626115", + opbnbmainnet: "0x6dB5e303289fea2E83F7d442470210045592AD93", +}; + +// Index each chain's aggregator stores this VIP's grant / revoke batch at (= the corresponding batch array +// length at seed time). Re-confirm and re-seed with scripts/seedAggregators.ts immediately before +// proposing. GRANT_INDEX is only meaningful on BNB Chain (remotes have no grants). +export const GRANT_INDEX: Record = { + bscmainnet: 4, + ethereum: 3, + arbitrumone: 2, + basemainnet: 2, + zksyncmainnet: 2, + opmainnet: 2, + unichainmainnet: 4, + opbnbmainnet: 2, +}; +export const REVOKE_INDEX: Record = { + bscmainnet: 0, + ethereum: 2, + arbitrumone: 2, + basemainnet: 1, + zksyncmainnet: 1, + opmainnet: 1, + unichainmainnet: 2, + opbnbmainnet: 2, +}; + +export const acmOf = (chain: Chain): string => (chain === "bscmainnet" ? BNB_ACM : REMOTE_ACM[chain]); +export const criticalOf = (chain: Chain): string => + chain === "bscmainnet" ? BNB_CRITICAL : NETWORK_ADDRESSES[chain].CRITICAL_TIMELOCK; + +// A single ACM permission the aggregator grants or revokes. Field names match the on-chain +// ACMCommandsAggregator.Permission struct (contractAddress, functionSig, account). +export interface Permission { + contractAddress: string; + functionSig: string; + account: string; +} + +// Permissions the aggregator grants on a chain. Only BNB Chain has grants (swap → move a function to a +// Guardian, grant → add a Guardian alongside Critical); remotes have none. +export const grantPermissions = (chain: Chain): Permission[] => { + if (chain !== "bscmainnet") return []; + return BNB_ROWS.filter(r => r.action === "swap" || r.action === "grant").map(r => ({ + contractAddress: r.target, + functionSig: r.signature, + account: BNB_GUARDIANS[r.grantTo ?? "guardian1"], + })); +}; + +// Permissions the aggregator revokes on a chain: revoke/swap/stale rows from Critical on BNB (plus the +// staleness / legacy cleanup), or every remote row from that chain's Critical. +export const revokePermissions = (chain: Chain): Permission[] => { + if (chain === "bscmainnet") { + const revokes: Permission[] = BNB_ROWS.filter( + r => r.action === "revoke" || r.action === "swap" || r.action === "stale", + ).map(r => ({ contractAddress: r.target, functionSig: r.signature, account: BNB_CRITICAL })); + // Staleness / legacy cleanup: revoke each dangling grant from every current holder. + for (const s of STALE_ROWS) + for (const who of s.revokeFrom) + revokes.push({ contractAddress: s.target, functionSig: s.signature, account: who }); + return revokes; + } + const critical = criticalOf(chain); + return remoteRowsFor(chain).map(r => ({ contractAddress: r.target, functionSig: r.signature, account: critical })); +}; + +// Grant / revoke counts in a chain's batches — drives expectEvents on the ACM's role events. Each +// giveCallPermission grants one role and each revokeCallPermission revokes one. +export const roleChangeCounts = (chain: Chain): { granted: number; revoked: number } => ({ + granted: grantPermissions(chain).length, + revoked: revokePermissions(chain).length, +}); diff --git a/vips/vip-665/utils/seed.ts b/vips/vip-665/utils/seed.ts new file mode 100644 index 000000000..8d3cda114 --- /dev/null +++ b/vips/vip-665/utils/seed.ts @@ -0,0 +1,33 @@ +import { Contract, Signer } from "ethers"; + +import ACM_COMMANDS_AGGREGATOR_ABI from "../../../simulations/vip-665/abi/ACMCommandsAggregator.json"; +import { Permission } from "./commands"; + +// Append the VIP's grant and revoke batches to a chain's ACMCommandsAggregator and return the indices they +// landed at (read from the emitted *PermissionsAdded events). addGrant/RevokePermissions are permissionless, +// so any funded signer works — the fork simulations pass an impersonated signer, scripts/seedAggregators.ts +// passes the configured deployer. +export const seedAggregator = async ( + signer: Signer, + aggregator: string, + grants: Permission[], + revokes: Permission[], +): Promise<{ grantIndex?: number; revokeIndex?: number }> => { + const agg = new Contract(aggregator, ACM_COMMANDS_AGGREGATOR_ABI, signer); + const result: { grantIndex?: number; revokeIndex?: number } = {}; + + if (grants.length > 0) { + const receipt = await (await agg.addGrantPermissions(grants)).wait(); + result.grantIndex = receipt.events + ?.find((e: { event?: string }) => e.event === "GrantPermissionsAdded") + ?.args?.index.toNumber(); + } + if (revokes.length > 0) { + const receipt = await (await agg.addRevokePermissions(revokes)).wait(); + result.revokeIndex = receipt.events + ?.find((e: { event?: string }) => e.event === "RevokePermissionsAdded") + ?.args?.index.toNumber(); + } + + return result; +}; From 833567b2c1d6d154fb80f9785eadf4185a53e16a Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Tue, 14 Jul 2026 17:35:36 +0530 Subject: [PATCH 02/11] feat: normalize remote syncCash() permission to wildcard --- simulations/vip-665/utils/remoteSim.ts | 32 ++++++- vips/vip-665/bscmainnet.ts | 6 +- vips/vip-665/data/staleness.ts | 3 - vips/vip-665/data/syncCash.ts | 115 +++++++++++++++++++++++++ vips/vip-665/utils/commands.ts | 24 +++--- 5 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 vips/vip-665/data/syncCash.ts diff --git a/simulations/vip-665/utils/remoteSim.ts b/simulations/vip-665/utils/remoteSim.ts index 069b0a4a9..0bd1bbc2c 100644 --- a/simulations/vip-665/utils/remoteSim.ts +++ b/simulations/vip-665/utils/remoteSim.ts @@ -9,6 +9,7 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; import vip665 from "../../../vips/vip-665/bscmainnet"; import { ZERO } from "../../../vips/vip-665/data/bnb"; import { REMOTE_ACM, remoteRowsFor } from "../../../vips/vip-665/data/remote"; +import { SYNC_CASH_MARKETS, SYNC_CASH_SIG } from "../../../vips/vip-665/data/syncCash"; import { AGGREGATOR, Chain, @@ -23,14 +24,17 @@ type RemoteChain = Exclude; const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["address", "string"], [at, fn]); -// RoleGranted / RoleRevoked are emitted by every ACM version. Remotes have no grants, so the only -// RoleGranted is the wrapper grantRole(DEFAULT_ADMIN_ROLE) and RoleRevoked = revokes + the wrapper -// revokeRole. +// RoleGranted / RoleRevoked are emitted by every ACM version. On remotes the grants are the wrapper +// grantRole(DEFAULT_ADMIN_ROLE) plus the single wildcard syncCash() grant; RoleRevoked = the Critical +// revokes + the per-market syncCash() revokes + the wrapper revokeRole. Event counts derive from +// roleChangeCounts, so they track the batch contents automatically. // Shared body for the 7 remote-chain simulations. Run each with its matching --fork. export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { const critical = NETWORK_ADDRESSES[chain].CRITICAL_TIMELOCK; const guardian = NETWORK_ADDRESSES[chain].GUARDIAN; + const normal = NETWORK_ADDRESSES[chain].NORMAL_TIMELOCK; + const syncCashMarkets = SYNC_CASH_MARKETS[chain]; forking(forkBlock, async () => { before(async () => { @@ -60,6 +64,14 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { `pre guardian ${r.signature}@${r.target}`, ).to.equal(r.guardian); }); + + it("syncCash: NormalTimelock holds every per-market grant and no wildcard grant yet", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + expect(syncCashMarkets.length, `syncCash markets for ${chain}`).to.be.greaterThan(0); + expect(await acm.hasRole(role(ZERO, SYNC_CASH_SIG), normal), "pre wildcard syncCash").to.be.false; + for (const m of syncCashMarkets) + expect(await acm.hasRole(role(m, SYNC_CASH_SIG), normal), `pre normal syncCash@${m}`).to.be.true; + }); }); const counts = roleChangeCounts(chain); @@ -98,6 +110,20 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { expect(await acm.isAllowedToCall(critical, r.signature, { from: r.target }), `crit !allowed ${r.signature}`) .to.be.false; }); + + it("syncCash: NormalTimelock gained the wildcard grant and lost every per-market grant", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + expect(await acm.hasRole(role(ZERO, SYNC_CASH_SIG), normal), "post wildcard syncCash").to.be.true; + for (const m of syncCashMarkets) + expect(await acm.hasRole(role(m, SYNC_CASH_SIG), normal), `post normal syncCash@${m}`).to.be.false; + }); + + it("syncCash behavioral: NormalTimelock is still allowed to call syncCash on every market via wildcard", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const m of syncCashMarkets) + expect(await acm.isAllowedToCall(normal, SYNC_CASH_SIG, { from: m }), `normal allowed syncCash@${m}`).to.be + .true; + }); }); }); }; diff --git a/vips/vip-665/bscmainnet.ts b/vips/vip-665/bscmainnet.ts index 10c17aecf..0237865ab 100644 --- a/vips/vip-665/bscmainnet.ts +++ b/vips/vip-665/bscmainnet.ts @@ -45,13 +45,13 @@ const meta = { title: "VIP-665 [Multi-Chain] Reduce CriticalTimelock privileges", description: `#### Summary -This proposal hardens governance by removing high-severity powers from the CriticalTimelock on every mainnet, and — for a small set of BNB Chain functions where a Guardian multisig does not already hold them — moving them to the Guardian. It also cleans up dangling permissions left on removed setters and retired contracts. +This proposal hardens governance by removing high-severity powers from the CriticalTimelock on every mainnet, and — for a small set of BNB Chain functions where a Guardian multisig does not already hold them — moving them to the Guardian. It also cleans up dangling permissions left on removed setters and retired contracts, and normalizes the \`syncCash()\` permission on every remote chain to the wildcard convention used by all other vToken setters. #### Description A proposal routed through the Critical route executes in roughly 7 hours on BNB Chain and 8 hours on remote chains once voting, queue and timelock delays are counted. To shrink that fast-path attack surface, this VIP takes the high-severity powers off the CriticalTimelock across BNB Chain, Ethereum, Arbitrum One, Base, zkSync Era, OP Mainnet, Unichain and opBNB. The full per-contract, per-chain list of permissions changed is in the accompanying community post and the pull request. -Actions per chain: revoke the listed permissions from the CriticalTimelock; on BNB Chain, grant a few functions to Guardian 1 (swap) and grant one to Guardian 1 while keeping Critical (add); and revoke dangling grants on removed setters and retired contracts from every current holder. +Actions per chain: revoke the listed permissions from the CriticalTimelock; on BNB Chain, grant a few functions to Guardian 1 (swap) and grant one to Guardian 1 while keeping Critical (add), and revoke dangling grants on removed setters and retired contracts from every current holder; on each remote chain, grant \`syncCash()\` on the wildcard target (address(0)) to the NormalTimelock and revoke the per-market \`syncCash()\` grants it currently holds. #### Execution model @@ -61,7 +61,7 @@ To keep the whole change in one proposal within the BNB Chain per-transaction ga - **Scoped privilege**: the aggregator's DEFAULT_ADMIN_ROLE grant is scoped to this proposal — granted, used once, and revoked in the same transaction sequence, per chain. - **VIP execution simulation**: validated in a fork environment that every listed permission moved as intended (revoke / swap / grant), that "No change" permissions are untouched, and that the expected ACM events fire. -- **Cross-chain payload size**: each LayerZero message carries only 3 commands, well under the Relayer cap. +- **Cross-chain payload size**: each LayerZero message carries only 4 commands (grant the aggregator the ACM role, execute the grant batch, execute the revoke batch, revoke the role), well under the Relayer cap. #### Voting options diff --git a/vips/vip-665/data/staleness.ts b/vips/vip-665/data/staleness.ts index 70e97d7e0..27379876d 100644 --- a/vips/vip-665/data/staleness.ts +++ b/vips/vip-665/data/staleness.ts @@ -37,9 +37,6 @@ export const STALE_ROWS: { target: string; signature: string; revokeFrom: string { target: RETIRED_RISK_CONFIG, signature: "toggleConfigActive(string)", revokeFrom: [NORMAL, FASTTRACK, CRITICAL] }, // Retired risk steward — dangling target grant. { target: RETIRED_RISK_STEWARD, signature: "setMaxDeltaBps(uint256)", revokeFrom: [NORMAL, FASTTRACK, CRITICAL] }, - // NOTE: this retired steward was also a candidate GRANTEE of the wildcard setMarketBorrowCaps/ - // setMarketSupplyCaps powers, but it holds neither on-chain, so those two revokes would be no-ops - // and are omitted. // Retired oracle — dangling target grant. { target: RETIRED_TWAP_ORACLE, diff --git a/vips/vip-665/data/syncCash.ts b/vips/vip-665/data/syncCash.ts new file mode 100644 index 000000000..88ca4197d --- /dev/null +++ b/vips/vip-665/data/syncCash.ts @@ -0,0 +1,115 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import type { Permission } from "../utils/commands"; +import { RemoteChain } from "./remote"; + +export const ZERO = "0x0000000000000000000000000000000000000000"; +export const SYNC_CASH_SIG = "syncCash()"; + +const normalOf = (chain: RemoteChain): string => (NETWORK_ADDRESSES[chain] as Record).NORMAL_TIMELOCK; + +// Markets whose syncCash() role is currently granted to the NormalTimelock, per chain (verified on-chain). +export const SYNC_CASH_MARKETS: Record = { + ethereum: [ + "0x0792b9c60C728C1D2Fd6665b3D7A08762a9b28e0", + "0x0Ec5488e4F8f319213a14cab188E01fB8517Faa8", + "0x0c6B19287999f1e31a5c0a44393b24B62D2C0468", + "0x13eB80FDBe5C5f4a7039728E258A6f05fb3B912b", + "0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe", + "0x17C07e0c232f2f80DfDbd7a95b942D893A4C5ACb", + "0x256AdDBe0a387c98f487e44b85c29eb983413c5e", + "0x25C20e6e110A1cE3FEbaCC8b7E48368c7b2F0C91", + "0x2d499800239C4CD3012473Cb1EAE33562F0A6933", + "0x30aD10Bd5Be62CAb37863C2BfcC6E8fb4fD85BDa", + "0x325cEB02fe1C2fF816A83a5770eA0E88e2faEcF2", + "0x475d0C68a8CD275c15D1F01F4f291804E445F677", + "0x4a240F0ee138697726C8a3E43eFE6Ac3593432CB", + "0x4fAfbDc4F2a9876Bd1764827b26fb8dc4FD1dB95", + "0x520d67226Bc904aC122dcE66ed2f8f61AA1ED764", + "0x5e35C312862d53FD566737892aDCf010cb4928F7", + "0x62D9E2010Cff87Bae05B91d5E04605ef864ABc3B", + "0x672208C10aaAA2F9A6719F449C4C8227bc0BC202", + "0x76697f8eaeA4bE01C678376aAb97498Ee8f80D5C", + "0x7c8ff7d2A1372433726f879BD945fFb250B94c65", + "0x8716554364f20BCA783cb2BAA744d39361fd1D8d", + "0x8C3e3821259B82fFb32B2450A95d2dcbf161C24E", + "0xA854D35664c658280fFf27B6eDC6C4195c3229B3", + "0xCca202a95E8096315E3F19E46e19E1b326634889", + "0xDB6C345f864883a8F4cae87852Ac342589E76D1B", + "0xE0ee5dDeBFe0abe0a4Af50299D68b74Cec31668e", + "0xE36Ae842DbbD7aE372ebA02C8239cd431cC063d6", + "0xEF26C64bC06A8dE4CA5D31f119835f9A1d9433b9", + "0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E", + "0xa0EE2bAA024cC3AA1BC9395522D07B7970Ca75b3", + "0xa836ce315b7A6Bb19397Ee996551659B1D92298e", + "0xa8e7f9473635a5CB79646f14356a9Fc394CA111A", + "0xb4933AF59868986316Ed37fa865C829Eba2df0C7", + "0xba3916302cBA4aBcB51a01e706fC6051AaF272A0", + "0xc42E4bfb996ED35235bda505430cBE404Eb49F77", + "0xc82780Db1257C788F262FBbDA960B3706Dfdcaf2", + "0xd8AdD9B41D4E1cd64Edad8722AB0bA8D35536657", + "0xf87c0a64dc3a8622D6c63265FA29137788163879", + ], + arbitrumone: [ + "0x246a35E79a3a0618535A469aDaF5091cAA9f7E88", + "0x39D6d13Ea59548637104E40e729E4aABE27FE106", + "0x4f3a73f318C5EA67A86eaaCE24309F29f89900dF", + "0x68a34332983f4Bf866768DD6D6E638b02eF5e1f0", + "0x7D8609f8da70fF9027E9bc5229Af4F6727662707", + "0x9bb8cEc9C0d46F53b4f2173BB2A0221F66c353cC", + "0x9df6B5132135f14719696bBAe3C54BAb272fDb16", + "0xAeB0FEd69354f34831fe1D16475D9A83ddaCaDA6", + "0xB9F9117d4200dC296F9AcD1e8bE1937df834a2fD", + "0xaDa57840B372D4c28623E87FC175dE8490792811", + ], + basemainnet: [ + "0x133d3BCD77158D125B75A17Cb517fFD4B4BE64C5", + "0x3cb752d175740043Ec463673094e06ACDa2F9a2e", + "0x75201D81B3B0b9D17b179118837Be37f64fc4930", + "0x7bBd1005bB24Ec84705b04e1f2DfcCad533b6D72", + "0xEB8A79bD44cF4500943bf94a2b4434c95C008599", + ], + zksyncmainnet: [ + "0x03CAd66259f7F34EE075f8B62D133563D249eDa4", + "0x183dE3C349fCf546aAe925E1c7F364EA6FB4033c", + "0x1Fa916C27c7C2c4602124A14C77Dbb40a5FF1BE8", + "0x1aF23bD57c62A99C59aD48236553D0Dd11e49D2D", + "0x697a70779C1A03Ba2BD28b7627a902BFf831b616", + "0x69cDA960E3b20DFD480866fFfd377Ebe40bd0A46", + "0x84064c058F2EFea4AB648bB6Bd7e40f83fFDe39a", + "0xAF8fD83cFCbe963211FAaf1847F0F217F80B4719", + "0xCEb7Da150d16aCE58F090754feF2775C23C8b631", + ], + opmainnet: [ + "0x1C9406ee95B7af55F005996947b19F91B6D55b15", + "0x37ac9731B0B02df54975cd0c7240e0977a051721", + "0x66d5AE25731Ce99D46770745385e662C8e0B4025", + "0x6b846E3418455804C1920fA4CC7a31A51C659A2D", + "0x9EfdCfC2373f81D3DF24647B1c46e15268884c46", + ], + unichainmainnet: [ + "0x0170398083eb0D0387709523baFCA6426146C218", + "0x67716D6Bf76170Af816F5735e14c4d44D0B05eD2", + "0x68e2A6F7257FAc2F5a557b9E83E1fE6D5B408CE5", + "0xB953f92B9f759d97d2F2Dec10A8A3cf75fcE3A95", + "0xDa7Ce7Ba016d266645712e2e4Ebc6cC75eA8E4CD", + "0xbEC19Bef402C697a7be315d3e59E5F65b89Fa1BB", + "0xc219BC179C7cDb37eACB03f993f9fDc2495e3374", + ], + opbnbmainnet: [ + "0x13B492B8A03d072Bab5C54AC91Dba5b830a50917", + "0x509e81eF638D489936FA85BC58F52Df01190d26C", + "0x53d11cB8A0e5320Cd7229C3acc80d1A0707F2672", + "0xED827b80Bd838192EA95002C01B5c6dA8354219a", + "0xb7a01Ba126830692238521a1aA7E7A7509410b8e", + ], +}; + +// The single wildcard grant: syncCash() on address(0) → NormalTimelock. +export const syncCashGrants = (chain: RemoteChain): Permission[] => [ + { contractAddress: ZERO, functionSig: SYNC_CASH_SIG, account: normalOf(chain) }, +]; + +// The per-market revokes: syncCash() → NormalTimelock, one per market. +export const syncCashRevokes = (chain: RemoteChain): Permission[] => + SYNC_CASH_MARKETS[chain].map(m => ({ contractAddress: m, functionSig: SYNC_CASH_SIG, account: normalOf(chain) })); diff --git a/vips/vip-665/utils/commands.ts b/vips/vip-665/utils/commands.ts index 6910abdad..65dce8e85 100644 --- a/vips/vip-665/utils/commands.ts +++ b/vips/vip-665/utils/commands.ts @@ -3,14 +3,14 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, BNB_ROWS } from "../data/bnb"; import { REMOTE_ACM, REMOTE_CHAINS, RemoteChain, remoteRowsFor } from "../data/remote"; import { STALE_ROWS } from "../data/staleness"; +import { syncCashGrants, syncCashRevokes } from "../data/syncCash"; export type Chain = "bscmainnet" | RemoteChain; export const CHAINS: Chain[] = ["bscmainnet", ...REMOTE_CHAINS]; export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; -// ACMCommandsAggregator per chain (deployed on every mainnet; addresses from the governance-contracts -// deployments). Each instance is bound at construction to its own chain's ACM. +// ACMCommandsAggregator per chain export const AGGREGATOR: Record = { bscmainnet: "0x8b443Ea6726E56DF4C4F62f80F0556bB9B2a7c64", ethereum: "0xb78772bed6995551b64e54Cdb8e09800d86C73ee", @@ -22,9 +22,6 @@ export const AGGREGATOR: Record = { opbnbmainnet: "0x6dB5e303289fea2E83F7d442470210045592AD93", }; -// Index each chain's aggregator stores this VIP's grant / revoke batch at (= the corresponding batch array -// length at seed time). Re-confirm and re-seed with scripts/seedAggregators.ts immediately before -// proposing. GRANT_INDEX is only meaningful on BNB Chain (remotes have no grants). export const GRANT_INDEX: Record = { bscmainnet: 4, ethereum: 3, @@ -58,10 +55,11 @@ export interface Permission { account: string; } -// Permissions the aggregator grants on a chain. Only BNB Chain has grants (swap → move a function to a -// Guardian, grant → add a Guardian alongside Critical); remotes have none. +// Permissions the aggregator grants on a chain. On BNB: swap → move a function to a Guardian, grant → add a +// Guardian alongside Critical. On remotes: the single wildcard syncCash() grant to NormalTimelock (the +// syncCash hygiene cleanup); remotes have no Guardian swaps/grants. export const grantPermissions = (chain: Chain): Permission[] => { - if (chain !== "bscmainnet") return []; + if (chain !== "bscmainnet") return syncCashGrants(chain); return BNB_ROWS.filter(r => r.action === "swap" || r.action === "grant").map(r => ({ contractAddress: r.target, functionSig: r.signature, @@ -70,7 +68,8 @@ export const grantPermissions = (chain: Chain): Permission[] => { }; // Permissions the aggregator revokes on a chain: revoke/swap/stale rows from Critical on BNB (plus the -// staleness / legacy cleanup), or every remote row from that chain's Critical. +// staleness / legacy cleanup); on remotes every remote row from that chain's Critical, plus the per-market +// syncCash() grants from NormalTimelock (replaced by the wildcard grant above). export const revokePermissions = (chain: Chain): Permission[] => { if (chain === "bscmainnet") { const revokes: Permission[] = BNB_ROWS.filter( @@ -83,7 +82,12 @@ export const revokePermissions = (chain: Chain): Permission[] => { return revokes; } const critical = criticalOf(chain); - return remoteRowsFor(chain).map(r => ({ contractAddress: r.target, functionSig: r.signature, account: critical })); + const criticalRevokes = remoteRowsFor(chain).map(r => ({ + contractAddress: r.target, + functionSig: r.signature, + account: critical, + })); + return [...criticalRevokes, ...syncCashRevokes(chain)]; }; // Grant / revoke counts in a chain's batches — drives expectEvents on the ACM's role events. Each From d6574d9541123cb4dfff7bad6c5062654577a80b Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Tue, 14 Jul 2026 18:04:32 +0530 Subject: [PATCH 03/11] refactor: hardcode sim role-event counts and rename loop vars --- simulations/vip-665/bscmainnet.ts | 184 +++++++++++++++---------- simulations/vip-665/utils/remoteSim.ts | 76 +++++----- vips/vip-665/data/remote.ts | 11 ++ vips/vip-665/data/syncCash.ts | 19 ++- vips/vip-665/utils/commands.ts | 7 - 5 files changed, 171 insertions(+), 126 deletions(-) diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts index 9d0e9cd74..922b91082 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-665/bscmainnet.ts @@ -8,8 +8,9 @@ import { forking, testVip } from "src/vip-framework"; import vip665 from "../../vips/vip-665/bscmainnet"; import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, BNB_ROWS, ZERO } from "../../vips/vip-665/data/bnb"; +import { EXPECTED_ROLE_EVENTS } from "../../vips/vip-665/data/remote"; import { STALE_ROWS } from "../../vips/vip-665/data/staleness"; -import { AGGREGATOR, grantPermissions, revokePermissions, roleChangeCounts } from "../../vips/vip-665/utils/commands"; +import { AGGREGATOR, grantPermissions, revokePermissions } from "../../vips/vip-665/utils/commands"; import { seedAggregator } from "../../vips/vip-665/utils/seed"; import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; @@ -27,18 +28,18 @@ const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["addres // One row bucket per action so every category (no-change / revoke / swap / grant / stale) is asserted // explicitly. Each bucket is guarded to be non-empty so a data regression that empties a category fails // loudly instead of passing vacuously. -const NO_CHANGE = BNB_ROWS.filter(r => r.action === "none"); -const REVOKE = BNB_ROWS.filter(r => r.action === "revoke"); -const SWAP = BNB_ROWS.filter(r => r.action === "swap"); -const GRANT = BNB_ROWS.filter(r => r.action === "grant"); -const STALE = BNB_ROWS.filter(r => r.action === "stale"); +const NO_CHANGE = BNB_ROWS.filter(row => row.action === "none"); +const REVOKE = BNB_ROWS.filter(row => row.action === "revoke"); +const SWAP = BNB_ROWS.filter(row => row.action === "swap"); +const GRANT = BNB_ROWS.filter(row => row.action === "grant"); +const STALE = BNB_ROWS.filter(row => row.action === "stale"); forking(FORK_BLOCK, async () => { const acm = () => new Contract(BNB_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - const holds = (who: string, r: { target: string; signature: string }) => - acm().hasRole(role(r.target, r.signature), who); - const guardianAddr = (r: { grantTo?: "guardian1" | "guardian2" | "guardian3" }) => - BNB_GUARDIANS[r.grantTo ?? "guardian1"]; + const holds = (who: string, row: { target: string; signature: string }) => + acm().hasRole(role(row.target, row.signature), who); + const guardianAddr = (row: { grantTo?: "guardian1" | "guardian2" | "guardian3" }) => + BNB_GUARDIANS[row.grantTo ?? "guardian1"]; before(async () => { const signer = await initMainnetUser(bscmainnet.NORMAL_TIMELOCK, ethers.utils.parseEther("2")); @@ -51,74 +52,89 @@ forking(FORK_BLOCK, async () => { }); describe("VIP-665 pre-execution permissions (bscmainnet)", () => { - it("the action plan covers every category (no-change / revoke / swap / grant / stale)", () => { - expect(NO_CHANGE.length, "no-change rows").to.be.greaterThan(0); - expect(REVOKE.length, "revoke rows").to.be.greaterThan(0); - expect(SWAP.length, "swap rows").to.be.greaterThan(0); - expect(GRANT.length, "grant rows").to.be.greaterThan(0); - expect(STALE.length, "stale (BNB) rows").to.be.greaterThan(0); - expect(STALE_ROWS.length, "stale (dangling cleanup) rows").to.be.greaterThan(0); + it("the action plan covers every category with the expected row counts", () => { + expect(NO_CHANGE.length, "no-change rows").to.equal(185); + expect(REVOKE.length, "revoke rows").to.equal(26); + expect(SWAP.length, "swap rows").to.equal(4); + expect(GRANT.length, "grant rows").to.equal(1); + expect(STALE.length, "stale (BNB) rows").to.equal(1); + expect(STALE_ROWS.length, "stale (dangling cleanup) rows").to.equal(8); }); it("no-change: Critical holds each one and Guardian flags match the plan", async () => { - for (const r of NO_CHANGE) { - expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.equal(r.critical); - expect(await holds(BNB_GUARDIANS.guardian1, r), `pre g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); - expect(await holds(BNB_GUARDIANS.guardian2, r), `pre g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); - expect(await holds(BNB_GUARDIANS.guardian3, r), `pre g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + for (const row of NO_CHANGE) { + expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.equal(row.critical); + expect(await holds(BNB_GUARDIANS.guardian1, row), `pre g1 ${row.signature}@${row.target}`).to.equal( + row.guardian1, + ); + expect(await holds(BNB_GUARDIANS.guardian2, row), `pre g2 ${row.signature}@${row.target}`).to.equal( + row.guardian2, + ); + expect(await holds(BNB_GUARDIANS.guardian3, row), `pre g3 ${row.signature}@${row.target}`).to.equal( + row.guardian3, + ); } }); it("revoke: Critical currently holds every permission to be revoked", async () => { - for (const r of REVOKE) { - expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.be.true; - expect(await holds(BNB_GUARDIANS.guardian1, r), `pre g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); - expect(await holds(BNB_GUARDIANS.guardian2, r), `pre g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); - expect(await holds(BNB_GUARDIANS.guardian3, r), `pre g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + for (const row of REVOKE) { + expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.be.true; + expect(await holds(BNB_GUARDIANS.guardian1, row), `pre g1 ${row.signature}@${row.target}`).to.equal( + row.guardian1, + ); + expect(await holds(BNB_GUARDIANS.guardian2, row), `pre g2 ${row.signature}@${row.target}`).to.equal( + row.guardian2, + ); + expect(await holds(BNB_GUARDIANS.guardian3, row), `pre g3 ${row.signature}@${row.target}`).to.equal( + row.guardian3, + ); } }); it("swap: Critical holds each one and the target Guardian does not yet", async () => { - for (const r of SWAP) { - expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.be.true; - expect(await holds(guardianAddr(r), r), `pre guardian ${r.signature}@${r.target}`).to.be.false; + for (const row of SWAP) { + expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.be.true; + expect(await holds(guardianAddr(row), row), `pre guardian ${row.signature}@${row.target}`).to.be.false; } }); it("grant: Critical holds each one and the target Guardian does not yet", async () => { - for (const r of GRANT) { - expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.be.true; - expect(await holds(guardianAddr(r), r), `pre guardian ${r.signature}@${r.target}`).to.be.false; + for (const row of GRANT) { + expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.be.true; + expect(await holds(guardianAddr(row), row), `pre guardian ${row.signature}@${row.target}`).to.be.false; } }); it("stale (BNB rows): Critical currently holds each dangling permission", async () => { - for (const r of STALE) { - expect(await holds(BNB_CRITICAL, r), `pre critical ${r.signature}@${r.target}`).to.be.true; - expect(await holds(BNB_GUARDIANS.guardian1, r), `pre g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); - expect(await holds(BNB_GUARDIANS.guardian2, r), `pre g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); - expect(await holds(BNB_GUARDIANS.guardian3, r), `pre g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + for (const row of STALE) { + expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.be.true; + expect(await holds(BNB_GUARDIANS.guardian1, row), `pre g1 ${row.signature}@${row.target}`).to.equal( + row.guardian1, + ); + expect(await holds(BNB_GUARDIANS.guardian2, row), `pre g2 ${row.signature}@${row.target}`).to.equal( + row.guardian2, + ); + expect(await holds(BNB_GUARDIANS.guardian3, row), `pre g3 ${row.signature}@${row.target}`).to.equal( + row.guardian3, + ); } }); it("stale (dangling cleanup): every listed grantee currently holds the dangling permission", async () => { - for (const s of STALE_ROWS) - for (const who of s.revokeFrom) - expect(await holds(who, s), `pre stale ${s.signature}@${s.target} ${who}`).to.be.true; + for (const staleRow of STALE_ROWS) + for (const who of staleRow.revokeFrom) + expect(await holds(who, staleRow), `pre stale ${staleRow.signature}@${staleRow.target} ${who}`).to.be.true; }); }); - const counts = roleChangeCounts("bscmainnet"); - // The BNB ACM (legacy) emits only the OZ Role events, not PermissionGranted/Revoked. Each giveCallPermission - // grants a role and each revokeCallPermission revokes one; the aggregator wrapper adds exactly one more of - // each (grant/revoke of DEFAULT_ADMIN_ROLE to the aggregator). So counts = batch counts + 1. + const events = EXPECTED_ROLE_EVENTS.bscmainnet; testVip("VIP-665 Reduce CriticalTimelock privileges — BNB Chain", await vip665(), { callbackAfterExecution: async (txResponse: TransactionResponse) => { await expectEvents( txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["RoleGranted", "RoleRevoked"], - [counts.granted + 1, counts.revoked + 1], + [events.granted, events.revoked], ); await expectEvents( txResponse, @@ -131,63 +147,81 @@ forking(FORK_BLOCK, async () => { describe("VIP-665 post-execution permissions (bscmainnet)", () => { it("no-change: holders are untouched (Critical and every Guardian flag unchanged)", async () => { - for (const r of NO_CHANGE) { - expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.equal(r.critical); - expect(await holds(BNB_GUARDIANS.guardian1, r), `post g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); - expect(await holds(BNB_GUARDIANS.guardian2, r), `post g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); - expect(await holds(BNB_GUARDIANS.guardian3, r), `post g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + for (const row of NO_CHANGE) { + expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.equal(row.critical); + expect(await holds(BNB_GUARDIANS.guardian1, row), `post g1 ${row.signature}@${row.target}`).to.equal( + row.guardian1, + ); + expect(await holds(BNB_GUARDIANS.guardian2, row), `post g2 ${row.signature}@${row.target}`).to.equal( + row.guardian2, + ); + expect(await holds(BNB_GUARDIANS.guardian3, row), `post g3 ${row.signature}@${row.target}`).to.equal( + row.guardian3, + ); } }); it("revoke: Critical lost each one; Guardian flags unchanged", async () => { - for (const r of REVOKE) { - expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.be.false; - expect(await holds(BNB_GUARDIANS.guardian1, r), `post g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); - expect(await holds(BNB_GUARDIANS.guardian2, r), `post g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); - expect(await holds(BNB_GUARDIANS.guardian3, r), `post g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + for (const row of REVOKE) { + expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; + expect(await holds(BNB_GUARDIANS.guardian1, row), `post g1 ${row.signature}@${row.target}`).to.equal( + row.guardian1, + ); + expect(await holds(BNB_GUARDIANS.guardian2, row), `post g2 ${row.signature}@${row.target}`).to.equal( + row.guardian2, + ); + expect(await holds(BNB_GUARDIANS.guardian3, row), `post g3 ${row.signature}@${row.target}`).to.equal( + row.guardian3, + ); } }); it("swap: Critical lost each one and the target Guardian gained it", async () => { - for (const r of SWAP) { - expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.be.false; - expect(await holds(guardianAddr(r), r), `post guardian ${r.signature}@${r.target}`).to.be.true; + for (const row of SWAP) { + expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; + expect(await holds(guardianAddr(row), row), `post guardian ${row.signature}@${row.target}`).to.be.true; } }); it("grant: the target Guardian gained each one while Critical kept it", async () => { - for (const r of GRANT) { - expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.be.true; - expect(await holds(guardianAddr(r), r), `post guardian ${r.signature}@${r.target}`).to.be.true; + for (const row of GRANT) { + expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.true; + expect(await holds(guardianAddr(row), row), `post guardian ${row.signature}@${row.target}`).to.be.true; } }); it("stale (BNB rows): Critical lost each dangling permission; Guardian flags unchanged", async () => { - for (const r of STALE) { - expect(await holds(BNB_CRITICAL, r), `post critical ${r.signature}@${r.target}`).to.be.false; - expect(await holds(BNB_GUARDIANS.guardian1, r), `post g1 ${r.signature}@${r.target}`).to.equal(r.guardian1); - expect(await holds(BNB_GUARDIANS.guardian2, r), `post g2 ${r.signature}@${r.target}`).to.equal(r.guardian2); - expect(await holds(BNB_GUARDIANS.guardian3, r), `post g3 ${r.signature}@${r.target}`).to.equal(r.guardian3); + for (const row of STALE) { + expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; + expect(await holds(BNB_GUARDIANS.guardian1, row), `post g1 ${row.signature}@${row.target}`).to.equal( + row.guardian1, + ); + expect(await holds(BNB_GUARDIANS.guardian2, row), `post g2 ${row.signature}@${row.target}`).to.equal( + row.guardian2, + ); + expect(await holds(BNB_GUARDIANS.guardian3, row), `post g3 ${row.signature}@${row.target}`).to.equal( + row.guardian3, + ); } }); it("stale (dangling cleanup): every listed grantee lost the dangling permission", async () => { - for (const s of STALE_ROWS) - for (const who of s.revokeFrom) - expect(await holds(who, s), `post stale ${s.signature}@${s.target} ${who}`).to.be.false; + for (const staleRow of STALE_ROWS) + for (const who of staleRow.revokeFrom) + expect(await holds(who, staleRow), `post stale ${staleRow.signature}@${staleRow.target} ${who}`).to.be.false; }); }); describe("Post-VIP behavioral: swapped permissions follow the ACM authorization checks", () => { it("every swapped function is allowed for the target Guardian and denied for Critical", async () => { - for (const r of SWAP.filter(x => x.target !== ZERO)) { + for (const row of SWAP.filter(swapRow => swapRow.target !== ZERO)) { expect( - await acm().isAllowedToCall(BNB_CRITICAL, r.signature, { from: r.target }), - `crit !allowed ${r.signature}`, + await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), + `crit !allowed ${row.signature}`, ).to.be.false; expect( - await acm().isAllowedToCall(guardianAddr(r), r.signature, { from: r.target }), - `guardian allowed ${r.signature}`, + await acm().isAllowedToCall(guardianAddr(row), row.signature, { from: row.target }), + `guardian allowed ${row.signature}`, ).to.be.true; } }); diff --git a/simulations/vip-665/utils/remoteSim.ts b/simulations/vip-665/utils/remoteSim.ts index 0bd1bbc2c..ae8b889e9 100644 --- a/simulations/vip-665/utils/remoteSim.ts +++ b/simulations/vip-665/utils/remoteSim.ts @@ -8,15 +8,9 @@ import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; import vip665 from "../../../vips/vip-665/bscmainnet"; import { ZERO } from "../../../vips/vip-665/data/bnb"; -import { REMOTE_ACM, remoteRowsFor } from "../../../vips/vip-665/data/remote"; +import { EXPECTED_ROLE_EVENTS, REMOTE_ACM, remoteRowsFor } from "../../../vips/vip-665/data/remote"; import { SYNC_CASH_MARKETS, SYNC_CASH_SIG } from "../../../vips/vip-665/data/syncCash"; -import { - AGGREGATOR, - Chain, - grantPermissions, - revokePermissions, - roleChangeCounts, -} from "../../../vips/vip-665/utils/commands"; +import { AGGREGATOR, Chain, grantPermissions, revokePermissions } from "../../../vips/vip-665/utils/commands"; import { seedAggregator } from "../../../vips/vip-665/utils/seed"; import ACCESS_CONTROL_MANAGER_ABI from "../abi/AccessControlManager.json"; @@ -26,8 +20,8 @@ const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["addres // RoleGranted / RoleRevoked are emitted by every ACM version. On remotes the grants are the wrapper // grantRole(DEFAULT_ADMIN_ROLE) plus the single wildcard syncCash() grant; RoleRevoked = the Critical -// revokes + the per-market syncCash() revokes + the wrapper revokeRole. Event counts derive from -// roleChangeCounts, so they track the batch contents automatically. +// revokes + the per-market syncCash() revokes + the wrapper revokeRole. Expected counts come from the +// hardcoded EXPECTED_ROLE_EVENTS oracle in data/remote.ts. // Shared body for the 7 remote-chain simulations. Run each with its matching --fork. export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { @@ -51,37 +45,39 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { it("revoke: Critical currently holds every permission to be revoked", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const r of rows) - expect(await acm.hasRole(role(r.target, r.signature), critical), `pre critical ${r.signature}@${r.target}`).to - .be.true; + for (const row of rows) + expect( + await acm.hasRole(role(row.target, row.signature), critical), + `pre critical ${row.signature}@${row.target}`, + ).to.be.true; }); it("no-change: the Guardian flag matches the plan for every row", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const r of rows) + for (const row of rows) expect( - await acm.hasRole(role(r.target, r.signature), guardian), - `pre guardian ${r.signature}@${r.target}`, - ).to.equal(r.guardian); + await acm.hasRole(role(row.target, row.signature), guardian), + `pre guardian ${row.signature}@${row.target}`, + ).to.equal(row.guardian); }); it("syncCash: NormalTimelock holds every per-market grant and no wildcard grant yet", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); expect(syncCashMarkets.length, `syncCash markets for ${chain}`).to.be.greaterThan(0); expect(await acm.hasRole(role(ZERO, SYNC_CASH_SIG), normal), "pre wildcard syncCash").to.be.false; - for (const m of syncCashMarkets) - expect(await acm.hasRole(role(m, SYNC_CASH_SIG), normal), `pre normal syncCash@${m}`).to.be.true; + for (const market of syncCashMarkets) + expect(await acm.hasRole(role(market, SYNC_CASH_SIG), normal), `pre normal syncCash@${market}`).to.be.true; }); }); - const counts = roleChangeCounts(chain); + const events = EXPECTED_ROLE_EVENTS[chain]; testForkedNetworkVipCommands(`VIP-665 ${chain}`, await vip665(), { callbackAfterExecution: async (txResponse: TransactionResponse) => { await expectEvents( txResponse, [ACCESS_CONTROL_MANAGER_ABI], ["RoleGranted", "RoleRevoked"], - [counts.granted + 1, counts.revoked + 1], + [events.granted, events.revoked], ); }, }); @@ -89,40 +85,46 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { describe(`VIP-665 post-execution permissions (${chain})`, () => { it("revoke: Critical lost every revoked permission", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const r of rows) - expect(await acm.hasRole(role(r.target, r.signature), critical), `post critical ${r.signature}@${r.target}`) - .to.be.false; + for (const row of rows) + expect( + await acm.hasRole(role(row.target, row.signature), critical), + `post critical ${row.signature}@${row.target}`, + ).to.be.false; }); it("no-change: the Guardian flag is unchanged for every row", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const r of rows) + for (const row of rows) expect( - await acm.hasRole(role(r.target, r.signature), guardian), - `post guardian ${r.signature}@${r.target}`, - ).to.equal(r.guardian); + await acm.hasRole(role(row.target, row.signature), guardian), + `post guardian ${row.signature}@${row.target}`, + ).to.equal(row.guardian); }); it("behavioral: Critical is no longer allowed to call any revoked function", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const r of rows) - if (r.target !== ZERO) - expect(await acm.isAllowedToCall(critical, r.signature, { from: r.target }), `crit !allowed ${r.signature}`) - .to.be.false; + for (const row of rows) + if (row.target !== ZERO) + expect( + await acm.isAllowedToCall(critical, row.signature, { from: row.target }), + `crit !allowed ${row.signature}`, + ).to.be.false; }); it("syncCash: NormalTimelock gained the wildcard grant and lost every per-market grant", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); expect(await acm.hasRole(role(ZERO, SYNC_CASH_SIG), normal), "post wildcard syncCash").to.be.true; - for (const m of syncCashMarkets) - expect(await acm.hasRole(role(m, SYNC_CASH_SIG), normal), `post normal syncCash@${m}`).to.be.false; + for (const market of syncCashMarkets) + expect(await acm.hasRole(role(market, SYNC_CASH_SIG), normal), `post normal syncCash@${market}`).to.be.false; }); it("syncCash behavioral: NormalTimelock is still allowed to call syncCash on every market via wildcard", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const m of syncCashMarkets) - expect(await acm.isAllowedToCall(normal, SYNC_CASH_SIG, { from: m }), `normal allowed syncCash@${m}`).to.be - .true; + for (const market of syncCashMarkets) + expect( + await acm.isAllowedToCall(normal, SYNC_CASH_SIG, { from: market }), + `normal allowed syncCash@${market}`, + ).to.be.true; }); }); }); diff --git a/vips/vip-665/data/remote.ts b/vips/vip-665/data/remote.ts index bdac571c6..4f6fefa9c 100644 --- a/vips/vip-665/data/remote.ts +++ b/vips/vip-665/data/remote.ts @@ -182,3 +182,14 @@ export const remoteRowsFor = (chain: RemoteChain) => target: remoteAddr(chain, r.contract), guardian: r.guardian, })); + +export const EXPECTED_ROLE_EVENTS: Record<"bscmainnet" | RemoteChain, { granted: number; revoked: number }> = { + bscmainnet: { granted: 6, revoked: 55 }, + ethereum: { granted: 2, revoked: 50 }, + arbitrumone: { granted: 2, revoked: 22 }, + basemainnet: { granted: 2, revoked: 17 }, + zksyncmainnet: { granted: 2, revoked: 19 }, + opmainnet: { granted: 2, revoked: 15 }, + unichainmainnet: { granted: 2, revoked: 15 }, + opbnbmainnet: { granted: 2, revoked: 11 }, +}; diff --git a/vips/vip-665/data/syncCash.ts b/vips/vip-665/data/syncCash.ts index 88ca4197d..71de1e7ef 100644 --- a/vips/vip-665/data/syncCash.ts +++ b/vips/vip-665/data/syncCash.ts @@ -6,8 +6,6 @@ import { RemoteChain } from "./remote"; export const ZERO = "0x0000000000000000000000000000000000000000"; export const SYNC_CASH_SIG = "syncCash()"; -const normalOf = (chain: RemoteChain): string => (NETWORK_ADDRESSES[chain] as Record).NORMAL_TIMELOCK; - // Markets whose syncCash() role is currently granted to the NormalTimelock, per chain (verified on-chain). export const SYNC_CASH_MARKETS: Record = { ethereum: [ @@ -106,10 +104,17 @@ export const SYNC_CASH_MARKETS: Record = { }; // The single wildcard grant: syncCash() on address(0) → NormalTimelock. -export const syncCashGrants = (chain: RemoteChain): Permission[] => [ - { contractAddress: ZERO, functionSig: SYNC_CASH_SIG, account: normalOf(chain) }, -]; +export const syncCashGrants = (chain: RemoteChain): Permission[] => { + const normalTimelock = (NETWORK_ADDRESSES[chain] as Record).NORMAL_TIMELOCK; + return [{ contractAddress: ZERO, functionSig: SYNC_CASH_SIG, account: normalTimelock }]; +}; // The per-market revokes: syncCash() → NormalTimelock, one per market. -export const syncCashRevokes = (chain: RemoteChain): Permission[] => - SYNC_CASH_MARKETS[chain].map(m => ({ contractAddress: m, functionSig: SYNC_CASH_SIG, account: normalOf(chain) })); +export const syncCashRevokes = (chain: RemoteChain): Permission[] => { + const normalTimelock = (NETWORK_ADDRESSES[chain] as Record).NORMAL_TIMELOCK; + return SYNC_CASH_MARKETS[chain].map(market => ({ + contractAddress: market, + functionSig: SYNC_CASH_SIG, + account: normalTimelock, + })); +}; diff --git a/vips/vip-665/utils/commands.ts b/vips/vip-665/utils/commands.ts index 65dce8e85..5b7ad9bb2 100644 --- a/vips/vip-665/utils/commands.ts +++ b/vips/vip-665/utils/commands.ts @@ -89,10 +89,3 @@ export const revokePermissions = (chain: Chain): Permission[] => { })); return [...criticalRevokes, ...syncCashRevokes(chain)]; }; - -// Grant / revoke counts in a chain's batches — drives expectEvents on the ACM's role events. Each -// giveCallPermission grants one role and each revokeCallPermission revokes one. -export const roleChangeCounts = (chain: Chain): { granted: number; revoked: number } => ({ - granted: grantPermissions(chain).length, - revoked: revokePermissions(chain).length, -}); From 43bc8df8cdbb5f918bb78dc6f5f5efed31ef4483 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Tue, 14 Jul 2026 18:42:00 +0530 Subject: [PATCH 04/11] docs: group bnb.ts permission rows by package and contract --- vips/vip-665/data/bnb.ts | 58 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/vips/vip-665/data/bnb.ts b/vips/vip-665/data/bnb.ts index e4fe10270..cd0a7309f 100644 --- a/vips/vip-665/data/bnb.ts +++ b/vips/vip-665/data/bnb.ts @@ -80,6 +80,8 @@ export const BNB_ROWS: { action: Action; grantTo?: "guardian1" | "guardian2" | "guardian3"; }[] = [ + // ==================== venus-protocol ==================== + // ---- Liquidator ---- { signature: "addToAllowlist(address,address)", target: CONTRACTS.Liquidator, @@ -143,6 +145,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- PegStability_USDT ---- { signature: "setVAIMintCap(uint256)", target: CONTRACTS.PegStability_USDT, @@ -188,6 +191,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- Prime ---- { signature: "addMarket(address,address,uint256,uint256)", target: CONTRACTS.Prime, @@ -278,6 +282,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- PrimeLiquidityProvider ---- { signature: "setMaxLoopsLimit(uint256)", target: CONTRACTS.PrimeLiquidityProvider, @@ -323,6 +328,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- PrimeV2 ---- { signature: "pause()", target: CONTRACTS.PrimeV2, @@ -341,6 +347,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- Unitroller (core pool Comptroller) ---- { signature: "addPoolMarkets(uint96[],address[])", target: CONTRACTS.Unitroller, @@ -523,6 +530,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- VaiUnitroller ---- { signature: "setBaseRate(uint256)", target: CONTRACTS.VaiUnitroller, @@ -559,6 +567,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- VAIVaultProxy ---- { signature: "pause()", target: CONTRACTS.VAIVaultProxy, @@ -577,6 +586,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- VBNBAdmin ---- { signature: "setInterestRateModel(address)", target: CONTRACTS.VBNBAdmin, @@ -586,6 +596,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- VRTVaultProxy ---- { signature: "pause()", target: CONTRACTS.VRTVaultProxy, @@ -604,6 +615,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- XVSVaultProxy ---- { signature: "setRewardAmountPerBlockOrSecond(address,uint256)", target: CONTRACTS.XVSVaultProxy, @@ -631,6 +643,8 @@ export const BNB_ROWS: { guardian3: false, action: "revoke", }, + // ==================== oracle ==================== + // ---- BinanceOracle ---- { signature: "setMaxStalePeriod(string,uint256)", target: CONTRACTS.BinanceOracle, @@ -649,6 +663,7 @@ export const BNB_ROWS: { guardian3: true, action: "none", }, + // ---- ChainlinkOracle ---- { signature: "setDirectPrice(address,uint256)", target: CONTRACTS.ChainlinkOracle, @@ -676,6 +691,7 @@ export const BNB_ROWS: { guardian3: true, action: "revoke", }, + // ---- DeviationBoundedOracle ---- { signature: "setThresholds(address,uint256,uint256)", target: CONTRACTS.DeviationBoundedOracle, @@ -767,6 +783,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- PythOracle ---- { signature: "setTokenConfig(TokenConfig)", target: CONTRACTS.PythOracle, @@ -776,6 +793,7 @@ export const BNB_ROWS: { guardian3: true, action: "revoke", }, + // ---- RedStoneOracle ---- { signature: "setDirectPrice(address,uint256)", target: CONTRACTS.RedStoneOracle, @@ -794,6 +812,7 @@ export const BNB_ROWS: { guardian3: true, action: "revoke", }, + // ---- ResilientOracle ---- { signature: "setTokenConfig(TokenConfig)", target: CONTRACTS.ResilientOracle, @@ -821,6 +840,7 @@ export const BNB_ROWS: { guardian3: true, action: "none", }, + // ---- USDTChainlinkOracle ---- { signature: "setDirectPrice(address,uint256)", target: CONTRACTS.USDTChainlinkOracle, @@ -839,6 +859,8 @@ export const BNB_ROWS: { guardian3: true, action: "revoke", }, + // ==================== protocol-reserve ==================== + // ---- BTCBPrimeConverter ---- { signature: "setConversionConfig(address,address,ConversionConfig)", target: CONTRACTS.BTCBPrimeConverter, @@ -875,6 +897,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- ConverterNetwork ---- { signature: "addTokenConverter(address)", target: CONTRACTS.ConverterNetwork, @@ -893,6 +916,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- ETHPrimeConverter ---- { signature: "setConversionConfig(address,address,ConversionConfig)", target: CONTRACTS.ETHPrimeConverter, @@ -929,6 +953,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- ProtocolShareReserve ---- { signature: "addOrUpdateDistributionConfigs(DistributionConfig[])", target: CONTRACTS.ProtocolShareReserve, @@ -947,6 +972,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- RiskFundConverter ---- { signature: "setConversionConfig(address,address,ConversionConfig)", target: CONTRACTS.RiskFundConverter, @@ -992,6 +1018,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- RiskFundV2 ---- { signature: "setMinAmountToConvert(uint256)", target: CONTRACTS.RiskFundV2, @@ -1001,6 +1028,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- USDCPrimeConverter ---- { signature: "setConversionConfig(address,address,ConversionConfig)", target: CONTRACTS.USDCPrimeConverter, @@ -1037,6 +1065,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- USDTPrimeConverter ---- { signature: "setConversionConfig(address,address,ConversionConfig)", target: CONTRACTS.USDTPrimeConverter, @@ -1073,6 +1102,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- WBNBBurnConverter ---- { signature: "setConversionConfig(address,address,ConversionConfig)", target: CONTRACTS.WBNBBurnConverter, @@ -1109,6 +1139,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- XVSVaultConverter ---- { signature: "setConversionConfig(address,address,ConversionConfig)", target: CONTRACTS.XVSVaultConverter, @@ -1145,6 +1176,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- XVSVaultTreasury ---- { signature: "fundXVSVault(uint256)", target: CONTRACTS.XVSVaultTreasury, @@ -1154,6 +1186,8 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ==================== isolated-pools ==================== + // ---- Comptroller_DeFi ---- { signature: "setForcedLiquidation(address,bool)", target: CONTRACTS.Comptroller_DeFi, @@ -1163,6 +1197,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- Comptroller_GameFi ---- { signature: "setForcedLiquidation(address,bool)", target: CONTRACTS.Comptroller_GameFi, @@ -1172,6 +1207,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- Comptroller_LiquidStakedBNB ---- { signature: "setForcedLiquidation(address,bool)", target: CONTRACTS.Comptroller_LiquidStakedBNB, @@ -1181,6 +1217,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- Comptroller_Stablecoins ---- { signature: "setForcedLiquidation(address,bool)", target: CONTRACTS.Comptroller_Stablecoins, @@ -1190,6 +1227,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- Comptroller_Tron ---- { signature: "setForcedLiquidation(address,bool)", target: CONTRACTS.Comptroller_Tron, @@ -1199,6 +1237,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- Shortfall ---- { signature: "updateIncentiveBps(uint256)", target: CONTRACTS.Shortfall, @@ -1253,6 +1292,8 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ==================== venus-periphery ==================== + // ---- DeviationSentinel ---- { signature: "setTokenConfig(address,(uint8,bool))", target: CONTRACTS.DeviationSentinel, @@ -1289,6 +1330,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- EBrake ---- { signature: "decreaseCF(address,uint256)", target: CONTRACTS.EBrake, @@ -1424,6 +1466,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- Executor ---- { signature: "setMarketConfig(address,(uint256,uint256,bool))", target: CONTRACTS.Executor, @@ -1433,6 +1476,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- PancakeSwapOracle ---- { signature: "setPoolConfig(address,address)", target: CONTRACTS.PancakeSwapOracle, @@ -1442,6 +1486,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- PendlePTVaultAdapter ---- { signature: "pause()", target: CONTRACTS.PendlePTVaultAdapter, @@ -1460,6 +1505,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- RelativePositionManager ---- { signature: "executePositionAccountCall(address,address[],bytes[])", target: CONTRACTS.RelativePositionManager, @@ -1532,6 +1578,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- SentinelOracle ---- { signature: "setDirectPrice(address,uint256)", target: CONTRACTS.SentinelOracle, @@ -1550,6 +1597,7 @@ export const BNB_ROWS: { guardian3: false, action: "revoke", }, + // ---- UniswapOracle ---- { signature: "setPoolConfig(address,address)", target: CONTRACTS.UniswapOracle, @@ -1559,6 +1607,8 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ==================== governance-contracts ==================== + // ---- AuxiliaryCommandsAggregator ---- { signature: "addAuthorizedBatchers(address[])", target: CONTRACTS.AuxiliaryCommandsAggregator, @@ -1586,6 +1636,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- OmnichainProposalSender ---- { signature: "execute(uint16,bytes,bytes,address)", target: CONTRACTS.OmnichainProposalSender, @@ -1658,6 +1709,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- RiskOracle ---- { signature: "removeAuthorizedSender(address)", target: CONTRACTS.RiskOracle, @@ -1676,6 +1728,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- RiskStewardReceiver ---- { signature: "setWhitelistedExecutor(address,bool)", target: CONTRACTS.RiskStewardReceiver, @@ -1703,6 +1756,8 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ==================== token-bridge ==================== + // ---- XVSBridgeAdmin ---- { signature: "setConfig(uint16,uint16,uint256,bytes)", target: CONTRACTS.XVSBridgeAdmin, @@ -1848,6 +1903,8 @@ export const BNB_ROWS: { guardian3: false, action: "revoke", }, + // ==================== fixed-rate-vaults ==================== + // ---- InstitutionalVaultControllerProxy ---- { signature: "createVault(VaultConfig,InstitutionalConfig,RiskConfig,string,string,string)", target: CONTRACTS.InstitutionalVaultControllerProxy, @@ -1993,6 +2050,7 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // ---- LiquidationAdapterProxy ---- { signature: "setCloseFactor(uint256)", target: CONTRACTS.LiquidationAdapterProxy, From 8c15c1a9ed3d3e1f8c286390e2d97c2cc2fd71e6 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 15 Jul 2026 00:44:22 +0530 Subject: [PATCH 05/11] refactor: refactor data files --- simulations/vip-665/bscmainnet.ts | 116 +++- simulations/vip-665/utils/remoteSim.ts | 32 +- vips/vip-665/bscmainnet.ts | 18 +- vips/vip-665/data/{bnb.ts => actionPlan.ts} | 226 +++++--- vips/vip-665/data/addresses.ts | 276 ++++++++++ vips/vip-665/data/cleanup.ts | 576 ++++++++++++++++++++ vips/vip-665/data/remote.ts | 195 ------- vips/vip-665/data/staleness.ts | 46 -- vips/vip-665/data/syncCash.ts | 120 ---- vips/vip-665/utils/commands.ts | 99 +++- 10 files changed, 1222 insertions(+), 482 deletions(-) rename vips/vip-665/data/{bnb.ts => actionPlan.ts} (89%) create mode 100644 vips/vip-665/data/addresses.ts create mode 100644 vips/vip-665/data/cleanup.ts delete mode 100644 vips/vip-665/data/remote.ts delete mode 100644 vips/vip-665/data/staleness.ts delete mode 100644 vips/vip-665/data/syncCash.ts diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts index 922b91082..6339ec90e 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-665/bscmainnet.ts @@ -6,11 +6,17 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents, initMainnetUser } from "src/utils"; import { forking, testVip } from "src/vip-framework"; -import vip665 from "../../vips/vip-665/bscmainnet"; -import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, BNB_ROWS, ZERO } from "../../vips/vip-665/data/bnb"; -import { EXPECTED_ROLE_EVENTS } from "../../vips/vip-665/data/remote"; -import { STALE_ROWS } from "../../vips/vip-665/data/staleness"; -import { AGGREGATOR, grantPermissions, revokePermissions } from "../../vips/vip-665/utils/commands"; +import vip665, { EXPECTED_ROLE_EVENTS } from "../../vips/vip-665/bscmainnet"; +import { BNB_ROWS } from "../../vips/vip-665/data/actionPlan"; +import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, ZERO } from "../../vips/vip-665/data/addresses"; +import { REDUNDANT_REVOKES, STALE_ROWS } from "../../vips/vip-665/data/cleanup"; +import { + AGGREGATOR, + BNB_LEGACY_WILDCARD_REVOKES, + grantPermissions, + legacyWildcardRole, + revokePermissions, +} from "../../vips/vip-665/utils/commands"; import { seedAggregator } from "../../vips/vip-665/utils/seed"; import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; @@ -33,6 +39,8 @@ const REVOKE = BNB_ROWS.filter(row => row.action === "revoke"); const SWAP = BNB_ROWS.filter(row => row.action === "swap"); const GRANT = BNB_ROWS.filter(row => row.action === "grant"); const STALE = BNB_ROWS.filter(row => row.action === "stale"); +// Redundant (wildcard-shadowed) target-specific grants revoked as behavior-preserving cleanup. +const REDUNDANT = REDUNDANT_REVOKES.bscmainnet; forking(FORK_BLOCK, async () => { const acm = () => new Contract(BNB_ACM, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); @@ -59,6 +67,26 @@ forking(FORK_BLOCK, async () => { expect(GRANT.length, "grant rows").to.equal(1); expect(STALE.length, "stale (BNB) rows").to.equal(1); expect(STALE_ROWS.length, "stale (dangling cleanup) rows").to.equal(8); + expect(BNB_LEGACY_WILDCARD_REVOKES.length, "legacy wildcard revokes").to.equal(3); + expect(REDUNDANT.length, "redundant revokes").to.equal(25); + }); + + it("legacy wildcard: each grantee currently holds the 32-byte wildcard role", async () => { + for (const r of BNB_LEGACY_WILDCARD_REVOKES) { + expect( + await acm().hasRole(legacyWildcardRole(r.signature), r.account), + `pre legacy wildcard ${r.signature} ${r.account}`, + ).to.be.true; + } + }); + + it("redundant: each target-specific grant is currently held by its account", async () => { + for (const r of REDUNDANT) { + expect( + await acm().hasRole(role(r.contract, r.signature), r.account), + `pre redundant ${r.note} (${r.signature})`, + ).to.be.true; + } }); it("no-change: Critical holds each one and Guardian flags match the plan", async () => { @@ -146,34 +174,36 @@ forking(FORK_BLOCK, async () => { }); describe("VIP-665 post-execution permissions (bscmainnet)", () => { - it("no-change: holders are untouched (Critical and every Guardian flag unchanged)", async () => { + // No-change = the capability is untouched. Every holder the plan lists can still call the function — either + // through its own grant, or (for grants the redundant cleanup drops) through the surviving wildcard. + it("no-change: Critical and every listed Guardian can still call the function", async () => { for (const row of NO_CHANGE) { - expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.equal(row.critical); - expect(await holds(BNB_GUARDIANS.guardian1, row), `post g1 ${row.signature}@${row.target}`).to.equal( - row.guardian1, - ); - expect(await holds(BNB_GUARDIANS.guardian2, row), `post g2 ${row.signature}@${row.target}`).to.equal( - row.guardian2, - ); - expect(await holds(BNB_GUARDIANS.guardian3, row), `post g3 ${row.signature}@${row.target}`).to.equal( - row.guardian3, - ); + if (row.critical) + expect( + await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), + `no-change critical ${row.signature}@${row.target}`, + ).to.be.true; + if (row.guardian1) + expect( + await acm().isAllowedToCall(BNB_GUARDIANS.guardian1, row.signature, { from: row.target }), + `no-change g1 ${row.signature}@${row.target}`, + ).to.be.true; + if (row.guardian2) + expect( + await acm().isAllowedToCall(BNB_GUARDIANS.guardian2, row.signature, { from: row.target }), + `no-change g2 ${row.signature}@${row.target}`, + ).to.be.true; + if (row.guardian3) + expect( + await acm().isAllowedToCall(BNB_GUARDIANS.guardian3, row.signature, { from: row.target }), + `no-change g3 ${row.signature}@${row.target}`, + ).to.be.true; } }); - it("revoke: Critical lost each one; Guardian flags unchanged", async () => { - for (const row of REVOKE) { + it("revoke: the CriticalTimelock lost each target-specific grant", async () => { + for (const row of REVOKE) expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; - expect(await holds(BNB_GUARDIANS.guardian1, row), `post g1 ${row.signature}@${row.target}`).to.equal( - row.guardian1, - ); - expect(await holds(BNB_GUARDIANS.guardian2, row), `post g2 ${row.signature}@${row.target}`).to.equal( - row.guardian2, - ); - expect(await holds(BNB_GUARDIANS.guardian3, row), `post g3 ${row.signature}@${row.target}`).to.equal( - row.guardian3, - ); - } }); it("swap: Critical lost each one and the target Guardian gained it", async () => { @@ -210,6 +240,36 @@ forking(FORK_BLOCK, async () => { for (const who of staleRow.revokeFrom) expect(await holds(who, staleRow), `post stale ${staleRow.signature}@${staleRow.target} ${who}`).to.be.false; }); + + it("legacy wildcard: each grantee lost the 32-byte wildcard role", async () => { + for (const r of BNB_LEGACY_WILDCARD_REVOKES) { + expect( + await acm().hasRole(legacyWildcardRole(r.signature), r.account), + `post legacy wildcard ${r.signature} ${r.account}`, + ).to.be.false; + } + }); + + it("redundant: each target-specific grant was revoked", async () => { + for (const r of REDUNDANT) { + expect( + await acm().hasRole(role(r.contract, r.signature), r.account), + `post redundant ${r.note} (${r.signature})`, + ).to.be.false; + } + }); + + it("redundant behavioral: each account can still call its function via the surviving wildcard", async () => { + for (const r of REDUNDANT) { + // setCollateralFactor from Critical is the single case whose wildcard is also revoked, so its power is + // fully removed (asserted in the revoke test). Every other redundant revoke is behavior-preserving. + if (r.signature === "setCollateralFactor(address,uint256,uint256)" && r.account === BNB_CRITICAL) continue; + expect( + await acm().isAllowedToCall(r.account, r.signature, { from: r.contract }), + `still callable ${r.note} (${r.signature})`, + ).to.be.true; + } + }); }); describe("Post-VIP behavioral: swapped permissions follow the ACM authorization checks", () => { diff --git a/simulations/vip-665/utils/remoteSim.ts b/simulations/vip-665/utils/remoteSim.ts index ae8b889e9..a0a451c1b 100644 --- a/simulations/vip-665/utils/remoteSim.ts +++ b/simulations/vip-665/utils/remoteSim.ts @@ -6,10 +6,10 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents, initMainnetUser } from "src/utils"; import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import vip665 from "../../../vips/vip-665/bscmainnet"; -import { ZERO } from "../../../vips/vip-665/data/bnb"; -import { EXPECTED_ROLE_EVENTS, REMOTE_ACM, remoteRowsFor } from "../../../vips/vip-665/data/remote"; -import { SYNC_CASH_MARKETS, SYNC_CASH_SIG } from "../../../vips/vip-665/data/syncCash"; +import vip665, { EXPECTED_ROLE_EVENTS } from "../../../vips/vip-665/bscmainnet"; +import { remoteRowsFor } from "../../../vips/vip-665/data/actionPlan"; +import { REMOTE_ACM, SYNC_CASH_MARKETS, ZERO } from "../../../vips/vip-665/data/addresses"; +import { REDUNDANT_REVOKES, SYNC_CASH_SIG } from "../../../vips/vip-665/data/cleanup"; import { AGGREGATOR, Chain, grantPermissions, revokePermissions } from "../../../vips/vip-665/utils/commands"; import { seedAggregator } from "../../../vips/vip-665/utils/seed"; import ACCESS_CONTROL_MANAGER_ABI from "../abi/AccessControlManager.json"; @@ -21,7 +21,7 @@ const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["addres // RoleGranted / RoleRevoked are emitted by every ACM version. On remotes the grants are the wrapper // grantRole(DEFAULT_ADMIN_ROLE) plus the single wildcard syncCash() grant; RoleRevoked = the Critical // revokes + the per-market syncCash() revokes + the wrapper revokeRole. Expected counts come from the -// hardcoded EXPECTED_ROLE_EVENTS oracle in data/remote.ts. +// hardcoded EXPECTED_ROLE_EVENTS oracle. // Shared body for the 7 remote-chain simulations. Run each with its matching --fork. export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { @@ -37,12 +37,19 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { }); const rows = remoteRowsFor(chain); + const redundant = REDUNDANT_REVOKES[chain]; describe(`VIP-665 pre-execution permissions (${chain})`, () => { it("the plan has at least one revoke row for this chain", () => { expect(rows.length, `revoke rows for ${chain}`).to.be.greaterThan(0); }); + it("redundant: each target-specific grant is currently held by its account", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const r of redundant) + expect(await acm.hasRole(role(r.contract, r.signature), r.account), `pre redundant ${r.note}`).to.be.true; + }); + it("revoke: Critical currently holds every permission to be revoked", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); for (const row of rows) @@ -101,6 +108,21 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { ).to.equal(row.guardian); }); + it("redundant: each target-specific grant was revoked", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const r of redundant) + expect(await acm.hasRole(role(r.contract, r.signature), r.account), `post redundant ${r.note}`).to.be.false; + }); + + it("redundant behavioral: each account can still call the function via the surviving wildcard", async () => { + const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + for (const r of redundant) + expect( + await acm.isAllowedToCall(r.account, r.signature, { from: r.contract }), + `post callable ${r.note} (${r.signature})`, + ).to.be.true; + }); + it("behavioral: Critical is no longer allowed to call any revoked function", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); for (const row of rows) diff --git a/vips/vip-665/bscmainnet.ts b/vips/vip-665/bscmainnet.ts index 0237865ab..7337542a1 100644 --- a/vips/vip-665/bscmainnet.ts +++ b/vips/vip-665/bscmainnet.ts @@ -1,7 +1,7 @@ import { Command, ProposalType } from "src/types"; import { makeProposal } from "src/utils"; -import { LZ_CHAIN_ID, RemoteChain } from "./data/remote"; +import { LZ_CHAIN_ID, RemoteChain } from "./data/actionPlan"; import { AGGREGATOR, Chain, @@ -10,9 +10,24 @@ import { REVOKE_INDEX, acmOf, grantPermissions, + legacyWildcardCommands, revokePermissions, } from "./utils/commands"; +// Expected RoleGranted / RoleRevoked counts per chain, asserted by the simulations after execution. +// granted = aggregator grants + wrapper grantRole(DEFAULT_ADMIN). revoked = aggregator revokes + wrapper +// revokeRole(DEFAULT_ADMIN) + redundant cleanup + (BNB only) the 3 direct legacy-wildcard revokeRole calls. +export const EXPECTED_ROLE_EVENTS: Record<"bscmainnet" | RemoteChain, { granted: number; revoked: number }> = { + bscmainnet: { granted: 6, revoked: 82 }, + ethereum: { granted: 2, revoked: 62 }, + arbitrumone: { granted: 2, revoked: 34 }, + basemainnet: { granted: 2, revoked: 29 }, + zksyncmainnet: { granted: 2, revoked: 23 }, + opmainnet: { granted: 2, revoked: 19 }, + unichainmainnet: { granted: 2, revoked: 19 }, + opbnbmainnet: { granted: 2, revoked: 13 }, +}; + // The commands the VIP emits per chain: grant the aggregator DEFAULT_ADMIN_ROLE, execute the grant and/or // revoke batch, revoke the role. Local on BNB; wrapped with dstChainId (LayerZero) on remotes. const aggregatorCommands = (chain: Chain): Command[] => { @@ -77,6 +92,7 @@ export const vip665 = () => makeProposal( [ ...aggregatorCommands("bscmainnet"), + ...legacyWildcardCommands(), ...aggregatorCommands("ethereum"), ...aggregatorCommands("arbitrumone"), ...aggregatorCommands("basemainnet"), diff --git a/vips/vip-665/data/bnb.ts b/vips/vip-665/data/actionPlan.ts similarity index 89% rename from vips/vip-665/data/bnb.ts rename to vips/vip-665/data/actionPlan.ts index cd0a7309f..c8d186b95 100644 --- a/vips/vip-665/data/bnb.ts +++ b/vips/vip-665/data/actionPlan.ts @@ -1,71 +1,20 @@ +// VIP-665 — reduce CriticalTimelock privileges across BNB Chain and the 7 remote mainnets. +// BNB rows carry the current holder flags and the final action; remote rows are all Critical revokes. import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; -const { bscmainnet } = NETWORK_ADDRESSES; -export const ZERO = "0x0000000000000000000000000000000000000000"; - -export const BNB_ACM = bscmainnet.ACCESS_CONTROL_MANAGER; -export const BNB_CRITICAL = bscmainnet.CRITICAL_TIMELOCK; -// Guardian 1 = CRITICAL_GUARDIAN (swap/grant target), 2 = GUARDIAN (pause), 3 = oracles. -export const BNB_GUARDIANS = { - guardian1: bscmainnet.CRITICAL_GUARDIAN, - guardian2: bscmainnet.GUARDIAN, - guardian3: "0x3a3284dC0FaFfb0b5F0d074c4C704D14326C98cF", -}; - -// Contract addresses the action plan is scoped to (verified on-chain). -const CONTRACTS = { - Liquidator: "0x0870793286aaDA55D39CE7f82fb2766e8004cF43", - PegStability_USDT: "0xC138aa4E424D1A8539e8F38Af5a754a2B7c3Cc36", - Prime: "0xBbCD063efE506c3D42a0Fa2dB5C08430288C71FC", - PrimeLiquidityProvider: "0x23c4F844ffDdC6161174eB32c770D4D8C07833F2", - PrimeV2: "0x059EabA8676b03e4e8f009eFb7F587C28450F50f", - Unitroller: "0xfD36E2c2a6789Db23113685031d7F16329158384", - VaiUnitroller: "0x004065D34C6b18cE4370ced1CeBDE94865DbFAFE", - VAIVaultProxy: "0x0667Eed0a0aAb930af74a3dfeDD263A73994f216", - VBNBAdmin: "0x9A7890534d9d91d473F28cB97962d176e2B65f1d", - VRTVaultProxy: "0x98bF4786D72AAEF6c714425126Dd92f149e3F334", - XVSVaultProxy: "0x051100480289e704d20e9DB4804837068f3f9204", - BinanceOracle: "0x594810b741d136f1960141C0d8Fb4a91bE78A820", - ChainlinkOracle: "0x1B2103441A0A108daD8848D8F5d790e4D402921F", - DeviationBoundedOracle: "0xc79Cb7efEBd121DC4B39eA141C214606595D665A", - PythOracle: "0xb893E38162f55fb80B18Aa44da76FaDf8E9B2262", - RedStoneOracle: "0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a", - ResilientOracle: "0x6592b5DE802159F3E74B2486b091D11a8256ab8A", - USDTChainlinkOracle: "0x22Dc2BAEa32E95AB07C2F5B8F63336CbF61aB6b8", - BTCBPrimeConverter: "0xE8CeAa79f082768f99266dFd208d665d2Dd18f53", - ConverterNetwork: "0xF7Caad5CeB0209165f2dFE71c92aDe14d0F15995", - ETHPrimeConverter: "0xca430B8A97Ea918fF634162acb0b731445B8195E", - ProtocolShareReserve: "0xCa01D5A9A248a830E9D93231e791B1afFed7c446", - RiskFundConverter: "0xA5622D276CcbB8d9BBE3D1ffd1BB11a0032E53F0", - RiskFundV2: "0xdF31a28D68A2AB381D42b380649Ead7ae2A76E42", - USDCPrimeConverter: "0xa758c9C215B6c4198F0a0e3FA46395Fa15Db691b", - USDTPrimeConverter: "0xD9f101AA67F3D72662609a2703387242452078C3", - WBNBBurnConverter: "0x9eF79830e626C8ccA7e46DCEd1F90e51E7cFCeBE", - XVSVaultConverter: "0xd5b9AE835F4C59272032B3B954417179573331E0", - XVSVaultTreasury: "0x269ff7818DB317f60E386D2be0B259e1a324a40a", - Comptroller_DeFi: "0x3344417c9360b963ca93A4e8305361AEde340Ab9", - Comptroller_GameFi: "0x1b43ea8622e76627B81665B1eCeBB4867566B963", - Comptroller_LiquidStakedBNB: "0xd933909A4a2b7A4638903028f44D1d38ce27c352", - Comptroller_Stablecoins: "0x94c1495cD4c557f1560Cbd68EAB0d197e6291571", - Comptroller_Tron: "0x23b4404E4E5eC5FF5a6FFb70B7d14E3FabF237B0", - Shortfall: "0xf37530A8a810Fcb501AA0Ecd0B0699388F0F2209", - DeviationSentinel: "0x6599C15cc8407046CD91E5c0F8B7f765fF914870", - EBrake: "0x35eBaBB99c7Fb7ba0C90bCc26e5d55Cdf89C23Ec", - Executor: "0xDd541A1b065F9587b01815a390a4d4559D7b630F", - PancakeSwapOracle: "0x44B72078240A3509979faF450085Fa818401D32E", - PendlePTVaultAdapter: "0x60Db419d8ea13C5827072Cf693D13cA1Ec6E0B4a", - RelativePositionManager: "0x1525D804DFff218DcC8B9359940F423209356C42", - SentinelOracle: "0x58eae0Cf4215590E19860b66b146C5d539cb6f14", - UniswapOracle: "0x8FD05458faf220B2324c4BFbb29DBC4B3CF6f23f", - AuxiliaryCommandsAggregator: "0x528A428748dfE73DFcc844176B401475D1831057", - OmnichainProposalSender: "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6", - RiskOracle: "0x0E3E51958b0Daa8C57c949675975CBEDd7b5a1a1", - RiskStewardReceiver: "0x47856bFa74B71d24a5545c7506862B8FddE52baB", - XVSBridgeAdmin: "0x70d644877b7b73800E9073BCFCE981eAaB6Dbc21", - InstitutionalVaultControllerProxy: "0x6D9e91cB766259af42619c14c994E694E57e6E85", - LiquidationAdapterProxy: "0x17A6222fB8b4b6D852cA54f5bc376a6A2c6224Bd", -}; +import { + BNB_CRITICAL, + BNB_CONTRACTS as CONTRACTS, + OMNICHAIN_EXECUTOR_OWNER, + SENTINEL_ORACLE, + XVS_BRIDGE_ADMIN, + ZERO, +} from "./addresses"; +// =================================================================================================== +// BNB Chain +// =================================================================================================== export type Action = "none" | "revoke" | "swap" | "grant" | "stale"; // signature = ACM-registered function signature; target = contract it is scoped to; // critical/guardian1/guardian2/guardian3 = current holders; action = final action; @@ -2097,3 +2046,150 @@ export const BNB_ROWS: { action: "none", }, ]; + +// setCollateralFactor on the isolated-pools wildcard target is revoked from the CriticalTimelock via a +// direct ACM.revokeRole on the legacy BNB ACM (the aggregator cannot clear wildcard grants there — see +// legacyWildcardRole in utils/commands.ts). +export const BNB_ACTION_LEGACY_WILDCARD_REVOKES: { signature: string; account: string }[] = [ + { signature: "setCollateralFactor(address,uint256,uint256)", account: BNB_CRITICAL }, +]; + +// =================================================================================================== +// Remote chains +// =================================================================================================== +export type RemoteChain = + | "ethereum" + | "arbitrumone" + | "basemainnet" + | "zksyncmainnet" + | "opmainnet" + | "unichainmainnet" + | "opbnbmainnet"; + +export const REMOTE_CHAINS: RemoteChain[] = [ + "ethereum", + "arbitrumone", + "basemainnet", + "zksyncmainnet", + "opmainnet", + "unichainmainnet", + "opbnbmainnet", +]; + +export const LZ_CHAIN_ID: Record = { + ethereum: LzChainId.ethereum, + arbitrumone: LzChainId.arbitrumone, + basemainnet: LzChainId.basemainnet, + zksyncmainnet: LzChainId.zksyncmainnet, + opmainnet: LzChainId.opmainnet, + unichainmainnet: LzChainId.unichainmainnet, + opbnbmainnet: LzChainId.opbnbmainnet, +}; + +const addressesOf = (chain: RemoteChain) => NETWORK_ADDRESSES[chain] as Record; + +// Resolve a contract key to its address on a chain. On Arbitrum/OP the "CHAINLINK_ORACLE" key is the +// SequencerChainlinkOracle adapter. +export const remoteAddr = (chain: RemoteChain, c: string): string => { + switch (c) { + case "WILDCARD": + return ZERO; + case "ResilientOracle": + return addressesOf(chain).RESILIENT_ORACLE; + case "ChainlinkOracle": + return addressesOf(chain).CHAINLINK_ORACLE; + case "RedStoneOracle": + return addressesOf(chain).REDSTONE_ORACLE; + case "SequencerChainlinkOracle": + return addressesOf(chain).CHAINLINK_ORACLE; + case "SentinelOracle": + return SENTINEL_ORACLE[chain]!; + case "XVSBridgeAdmin": + return XVS_BRIDGE_ADMIN[chain]; + case "OmnichainExecutorOwner": + return OMNICHAIN_EXECUTOR_OWNER[chain]; + default: + throw new Error(`unknown remote contract key ${c}`); + } +}; + +const ALL_REMOTES = REMOTE_CHAINS; + +// Every row is a revoke from Critical. contract = contract key (resolved per-chain); chains = where it +// applies; guardian = Guardian currently holds it (must still hold post-VIP). +export const REMOTE_ROWS: { signature: string; contract: string; chains: RemoteChain[]; guardian: boolean }[] = [ + // ── Common to all 7 remotes ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle", chains: ALL_REMOTES, guardian: true }, + { + signature: "setCollateralFactor(address,uint256,uint256)", + contract: "WILDCARD", + chains: ALL_REMOTES, + guardian: true, + }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner", chains: ALL_REMOTES, guardian: true }, + { + signature: "setMaxDailyReceiveLimit(uint256)", + contract: "OmnichainExecutorOwner", + chains: ALL_REMOTES, + guardian: true, + }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin", chains: ALL_REMOTES, guardian: false }, + + // ── Chain-specific ── + { + signature: "setDirectPrice(address,uint256)", + contract: "ChainlinkOracle", + chains: ["ethereum", "basemainnet", "zksyncmainnet"], + guardian: true, + }, + { + signature: "setTokenConfig(TokenConfig)", + contract: "ChainlinkOracle", + chains: ["ethereum", "basemainnet", "zksyncmainnet"], + guardian: true, + }, + { + signature: "setDirectPrice(address,uint256)", + contract: "RedStoneOracle", + chains: ["ethereum", "arbitrumone", "basemainnet", "zksyncmainnet", "opmainnet", "unichainmainnet"], + guardian: true, + }, + { + signature: "setTokenConfig(TokenConfig)", + contract: "RedStoneOracle", + chains: ["ethereum", "arbitrumone", "basemainnet", "zksyncmainnet", "opmainnet", "unichainmainnet"], + guardian: true, + }, + { + signature: "setDirectPrice(address,uint256)", + contract: "SequencerChainlinkOracle", + chains: ["arbitrumone", "opmainnet"], + guardian: true, + }, + { + signature: "setTokenConfig(TokenConfig)", + contract: "SequencerChainlinkOracle", + chains: ["arbitrumone", "opmainnet"], + guardian: true, + }, + { + signature: "setDirectPrice(address,uint256)", + contract: "SentinelOracle", + chains: ["ethereum", "arbitrumone", "basemainnet"], + guardian: true, + }, + { + signature: "setTokenOracleConfig(address,address)", + contract: "SentinelOracle", + chains: ["ethereum", "arbitrumone", "basemainnet"], + guardian: true, + }, +]; + +// Rows applicable to one chain, with resolved target address. +export const remoteRowsFor = (chain: RemoteChain) => + REMOTE_ROWS.filter(r => r.chains.includes(chain)).map(r => ({ + signature: r.signature, + target: remoteAddr(chain, r.contract), + guardian: r.guardian, + })); diff --git a/vips/vip-665/data/addresses.ts b/vips/vip-665/data/addresses.ts new file mode 100644 index 000000000..7408f913c --- /dev/null +++ b/vips/vip-665/data/addresses.ts @@ -0,0 +1,276 @@ +// All raw on-chain addresses used by VIP-665, grouped by chain and purpose. actionPlan.ts, cleanup.ts, +// the VIP and the simulations reference these named constants so the plan files stay free of literals. +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import type { RemoteChain } from "./actionPlan"; +import type { RedundantChain } from "./cleanup"; + +const { bscmainnet } = NETWORK_ADDRESSES; + +export const ZERO = "0x0000000000000000000000000000000000000000"; + +// =================================================================================================== +// bscmainnet +// =================================================================================================== +export const BNB_ACM = bscmainnet.ACCESS_CONTROL_MANAGER; +export const BNB_CRITICAL = bscmainnet.CRITICAL_TIMELOCK; +// Guardian 1 = CRITICAL_GUARDIAN (swap/grant target), 2 = GUARDIAN (pause), 3 = oracles. +export const BNB_GUARDIANS = { + guardian1: bscmainnet.CRITICAL_GUARDIAN, + guardian2: bscmainnet.GUARDIAN, + guardian3: "0x3a3284dC0FaFfb0b5F0d074c4C704D14326C98cF", +}; + +// Contracts the action plan is scoped to. +export const BNB_CONTRACTS = { + Liquidator: "0x0870793286aaDA55D39CE7f82fb2766e8004cF43", + PegStability_USDT: "0xC138aa4E424D1A8539e8F38Af5a754a2B7c3Cc36", + Prime: "0xBbCD063efE506c3D42a0Fa2dB5C08430288C71FC", + PrimeLiquidityProvider: "0x23c4F844ffDdC6161174eB32c770D4D8C07833F2", + PrimeV2: "0x059EabA8676b03e4e8f009eFb7F587C28450F50f", + Unitroller: "0xfD36E2c2a6789Db23113685031d7F16329158384", + VaiUnitroller: "0x004065D34C6b18cE4370ced1CeBDE94865DbFAFE", + VAIVaultProxy: "0x0667Eed0a0aAb930af74a3dfeDD263A73994f216", + VBNBAdmin: "0x9A7890534d9d91d473F28cB97962d176e2B65f1d", + VRTVaultProxy: "0x98bF4786D72AAEF6c714425126Dd92f149e3F334", + XVSVaultProxy: "0x051100480289e704d20e9DB4804837068f3f9204", + BinanceOracle: "0x594810b741d136f1960141C0d8Fb4a91bE78A820", + ChainlinkOracle: "0x1B2103441A0A108daD8848D8F5d790e4D402921F", + DeviationBoundedOracle: "0xc79Cb7efEBd121DC4B39eA141C214606595D665A", + PythOracle: "0xb893E38162f55fb80B18Aa44da76FaDf8E9B2262", + RedStoneOracle: "0x8455EFA4D7Ff63b8BFD96AdD889483Ea7d39B70a", + ResilientOracle: "0x6592b5DE802159F3E74B2486b091D11a8256ab8A", + USDTChainlinkOracle: "0x22Dc2BAEa32E95AB07C2F5B8F63336CbF61aB6b8", + BTCBPrimeConverter: "0xE8CeAa79f082768f99266dFd208d665d2Dd18f53", + ConverterNetwork: "0xF7Caad5CeB0209165f2dFE71c92aDe14d0F15995", + ETHPrimeConverter: "0xca430B8A97Ea918fF634162acb0b731445B8195E", + ProtocolShareReserve: "0xCa01D5A9A248a830E9D93231e791B1afFed7c446", + RiskFundConverter: "0xA5622D276CcbB8d9BBE3D1ffd1BB11a0032E53F0", + RiskFundV2: "0xdF31a28D68A2AB381D42b380649Ead7ae2A76E42", + USDCPrimeConverter: "0xa758c9C215B6c4198F0a0e3FA46395Fa15Db691b", + USDTPrimeConverter: "0xD9f101AA67F3D72662609a2703387242452078C3", + WBNBBurnConverter: "0x9eF79830e626C8ccA7e46DCEd1F90e51E7cFCeBE", + XVSVaultConverter: "0xd5b9AE835F4C59272032B3B954417179573331E0", + XVSVaultTreasury: "0x269ff7818DB317f60E386D2be0B259e1a324a40a", + Comptroller_DeFi: "0x3344417c9360b963ca93A4e8305361AEde340Ab9", + Comptroller_GameFi: "0x1b43ea8622e76627B81665B1eCeBB4867566B963", + Comptroller_LiquidStakedBNB: "0xd933909A4a2b7A4638903028f44D1d38ce27c352", + Comptroller_Stablecoins: "0x94c1495cD4c557f1560Cbd68EAB0d197e6291571", + Comptroller_Tron: "0x23b4404E4E5eC5FF5a6FFb70B7d14E3FabF237B0", + Shortfall: "0xf37530A8a810Fcb501AA0Ecd0B0699388F0F2209", + DeviationSentinel: "0x6599C15cc8407046CD91E5c0F8B7f765fF914870", + EBrake: "0x35eBaBB99c7Fb7ba0C90bCc26e5d55Cdf89C23Ec", + Executor: "0xDd541A1b065F9587b01815a390a4d4559D7b630F", + PancakeSwapOracle: "0x44B72078240A3509979faF450085Fa818401D32E", + PendlePTVaultAdapter: "0x60Db419d8ea13C5827072Cf693D13cA1Ec6E0B4a", + RelativePositionManager: "0x1525D804DFff218DcC8B9359940F423209356C42", + SentinelOracle: "0x58eae0Cf4215590E19860b66b146C5d539cb6f14", + UniswapOracle: "0x8FD05458faf220B2324c4BFbb29DBC4B3CF6f23f", + AuxiliaryCommandsAggregator: "0x528A428748dfE73DFcc844176B401475D1831057", + OmnichainProposalSender: "0x36a69dE601381be7b0DcAc5D5dD058825505F8f6", + RiskOracle: "0x0E3E51958b0Daa8C57c949675975CBEDd7b5a1a1", + RiskStewardReceiver: "0x47856bFa74B71d24a5545c7506862B8FddE52baB", + XVSBridgeAdmin: "0x70d644877b7b73800E9073BCFCE981eAaB6Dbc21", + InstitutionalVaultControllerProxy: "0x6D9e91cB766259af42619c14c994E694E57e6E85", + LiquidationAdapterProxy: "0x17A6222fB8b4b6D852cA54f5bc376a6A2c6224Bd", +}; + +// Retired / legacy contracts (absent from every deployment file) still holding grants. +export const RETIRED = { + RiskFundV2: "0xdF31a28D68A2AB381D42b380649Ead7ae2A76E42", + Unitroller: "0xfD36E2c2a6789Db23113685031d7F16329158384", + RiskConfig: "0xBa2a43279a228cf9cD94d072777d8d98e7e0a229", + RiskSteward: "0xE7252dccd79F2A555E314B9cdd440745b697D562", + TwapOracle: "0xea2f042e1A4f057EF8A5220e57733AD747ea8867", +}; + +// =================================================================================================== +// Remote chains +// =================================================================================================== +// ACM for op / unichain / opBNB is not in networkAddresses — hardcoded (verified on-chain). +export const REMOTE_ACM: Record = { + ethereum: NETWORK_ADDRESSES.ethereum.ACCESS_CONTROL_MANAGER, + arbitrumone: NETWORK_ADDRESSES.arbitrumone.ACCESS_CONTROL_MANAGER, + basemainnet: NETWORK_ADDRESSES.basemainnet.ACCESS_CONTROL_MANAGER, + zksyncmainnet: NETWORK_ADDRESSES.zksyncmainnet.ACCESS_CONTROL_MANAGER, + opmainnet: "0xD71b1F33f6B0259683f11174EE4Ddc2bb9cE4eD6", + unichainmainnet: "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0", + opbnbmainnet: "0xA60Deae5344F1152426cA440fb6552eA0e3005D6", +}; + +// Per-chain contract addresses that networkAddresses does not key. +export const XVS_BRIDGE_ADMIN: Record = { + ethereum: "0x9C6C95632A8FB3A74f2fB4B7FfC50B003c992b96", + arbitrumone: "0xf5d81C6F7DAA3F97A6265C8441f92eFda22Ad784", + basemainnet: "0x6303FEcee7161bF959d65df4Afb9e1ba5701f78e", + zksyncmainnet: "0x2471043F05Cc41A6051dd6714DC967C7BfC8F902", + opmainnet: "0x3c307DF1Bf3198a2417d9CA86806B307D147Ddf7", + unichainmainnet: "0x2EAaa880f97C9B63d37b39b0b316022d93d43604", + opbnbmainnet: "0x52fcE05aDbf6103d71ed2BA8Be7A317282731831", +}; + +export const OMNICHAIN_EXECUTOR_OWNER: Record = { + ethereum: "0x87Ed3Fd3a25d157637b955991fb1B41B566916Ba", + arbitrumone: "0xf72C1Aa0A1227B4bCcB28E1B1015F0616E2db7fD", + basemainnet: "0x8BA591f72a90fb379b9a82087b190d51b226F0a9", + zksyncmainnet: "0xdfaed3E5d9707629Ed5c225b4fB980c064286771", + opmainnet: "0xe6d9Eb3A07a1dc4496fc71417D7A7b9d5666BaA3", + unichainmainnet: "0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd", + opbnbmainnet: "0xf7e4c81Cf4A03d52472a4d00c3d9Ef35aF127E45", +}; + +// SentinelOracle is not published in the @venusprotocol deployment packages — hardcoded proxies, +// verified on-chain. +export const SENTINEL_ORACLE: Partial> = { + ethereum: "0x444C53E194B40c272fAd683210e2cB1c16Ab132e", + arbitrumone: "0x3563CAbc541a0432C66A64942ffB4070a9726226", + basemainnet: "0xCdD6D79Fd313C21967CED04C1b8bE70BDc27574D", +}; + +// Markets whose syncCash() role is currently granted per-market to the NormalTimelock, per chain. +export const SYNC_CASH_MARKETS: Record = { + ethereum: [ + "0x0792b9c60C728C1D2Fd6665b3D7A08762a9b28e0", + "0x0Ec5488e4F8f319213a14cab188E01fB8517Faa8", + "0x0c6B19287999f1e31a5c0a44393b24B62D2C0468", + "0x13eB80FDBe5C5f4a7039728E258A6f05fb3B912b", + "0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe", + "0x17C07e0c232f2f80DfDbd7a95b942D893A4C5ACb", + "0x256AdDBe0a387c98f487e44b85c29eb983413c5e", + "0x25C20e6e110A1cE3FEbaCC8b7E48368c7b2F0C91", + "0x2d499800239C4CD3012473Cb1EAE33562F0A6933", + "0x30aD10Bd5Be62CAb37863C2BfcC6E8fb4fD85BDa", + "0x325cEB02fe1C2fF816A83a5770eA0E88e2faEcF2", + "0x475d0C68a8CD275c15D1F01F4f291804E445F677", + "0x4a240F0ee138697726C8a3E43eFE6Ac3593432CB", + "0x4fAfbDc4F2a9876Bd1764827b26fb8dc4FD1dB95", + "0x520d67226Bc904aC122dcE66ed2f8f61AA1ED764", + "0x5e35C312862d53FD566737892aDCf010cb4928F7", + "0x62D9E2010Cff87Bae05B91d5E04605ef864ABc3B", + "0x672208C10aaAA2F9A6719F449C4C8227bc0BC202", + "0x76697f8eaeA4bE01C678376aAb97498Ee8f80D5C", + "0x7c8ff7d2A1372433726f879BD945fFb250B94c65", + "0x8716554364f20BCA783cb2BAA744d39361fd1D8d", + "0x8C3e3821259B82fFb32B2450A95d2dcbf161C24E", + "0xA854D35664c658280fFf27B6eDC6C4195c3229B3", + "0xCca202a95E8096315E3F19E46e19E1b326634889", + "0xDB6C345f864883a8F4cae87852Ac342589E76D1B", + "0xE0ee5dDeBFe0abe0a4Af50299D68b74Cec31668e", + "0xE36Ae842DbbD7aE372ebA02C8239cd431cC063d6", + "0xEF26C64bC06A8dE4CA5D31f119835f9A1d9433b9", + "0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E", + "0xa0EE2bAA024cC3AA1BC9395522D07B7970Ca75b3", + "0xa836ce315b7A6Bb19397Ee996551659B1D92298e", + "0xa8e7f9473635a5CB79646f14356a9Fc394CA111A", + "0xb4933AF59868986316Ed37fa865C829Eba2df0C7", + "0xba3916302cBA4aBcB51a01e706fC6051AaF272A0", + "0xc42E4bfb996ED35235bda505430cBE404Eb49F77", + "0xc82780Db1257C788F262FBbDA960B3706Dfdcaf2", + "0xd8AdD9B41D4E1cd64Edad8722AB0bA8D35536657", + "0xf87c0a64dc3a8622D6c63265FA29137788163879", + ], + arbitrumone: [ + "0x246a35E79a3a0618535A469aDaF5091cAA9f7E88", + "0x39D6d13Ea59548637104E40e729E4aABE27FE106", + "0x4f3a73f318C5EA67A86eaaCE24309F29f89900dF", + "0x68a34332983f4Bf866768DD6D6E638b02eF5e1f0", + "0x7D8609f8da70fF9027E9bc5229Af4F6727662707", + "0x9bb8cEc9C0d46F53b4f2173BB2A0221F66c353cC", + "0x9df6B5132135f14719696bBAe3C54BAb272fDb16", + "0xAeB0FEd69354f34831fe1D16475D9A83ddaCaDA6", + "0xB9F9117d4200dC296F9AcD1e8bE1937df834a2fD", + "0xaDa57840B372D4c28623E87FC175dE8490792811", + ], + basemainnet: [ + "0x133d3BCD77158D125B75A17Cb517fFD4B4BE64C5", + "0x3cb752d175740043Ec463673094e06ACDa2F9a2e", + "0x75201D81B3B0b9D17b179118837Be37f64fc4930", + "0x7bBd1005bB24Ec84705b04e1f2DfcCad533b6D72", + "0xEB8A79bD44cF4500943bf94a2b4434c95C008599", + ], + zksyncmainnet: [ + "0x03CAd66259f7F34EE075f8B62D133563D249eDa4", + "0x183dE3C349fCf546aAe925E1c7F364EA6FB4033c", + "0x1Fa916C27c7C2c4602124A14C77Dbb40a5FF1BE8", + "0x1aF23bD57c62A99C59aD48236553D0Dd11e49D2D", + "0x697a70779C1A03Ba2BD28b7627a902BFf831b616", + "0x69cDA960E3b20DFD480866fFfd377Ebe40bd0A46", + "0x84064c058F2EFea4AB648bB6Bd7e40f83fFDe39a", + "0xAF8fD83cFCbe963211FAaf1847F0F217F80B4719", + "0xCEb7Da150d16aCE58F090754feF2775C23C8b631", + ], + opmainnet: [ + "0x1C9406ee95B7af55F005996947b19F91B6D55b15", + "0x37ac9731B0B02df54975cd0c7240e0977a051721", + "0x66d5AE25731Ce99D46770745385e662C8e0B4025", + "0x6b846E3418455804C1920fA4CC7a31A51C659A2D", + "0x9EfdCfC2373f81D3DF24647B1c46e15268884c46", + ], + unichainmainnet: [ + "0x0170398083eb0D0387709523baFCA6426146C218", + "0x67716D6Bf76170Af816F5735e14c4d44D0B05eD2", + "0x68e2A6F7257FAc2F5a557b9E83E1fE6D5B408CE5", + "0xB953f92B9f759d97d2F2Dec10A8A3cf75fcE3A95", + "0xDa7Ce7Ba016d266645712e2e4Ebc6cC75eA8E4CD", + "0xbEC19Bef402C697a7be315d3e59E5F65b89Fa1BB", + "0xc219BC179C7cDb37eACB03f993f9fDc2495e3374", + ], + opbnbmainnet: [ + "0x13B492B8A03d072Bab5C54AC91Dba5b830a50917", + "0x509e81eF638D489936FA85BC58F52Df01190d26C", + "0x53d11cB8A0e5320Cd7229C3acc80d1A0707F2672", + "0xED827b80Bd838192EA95002C01B5c6dA8354219a", + "0xb7a01Ba126830692238521a1aA7E7A7509410b8e", + ], +}; + +// Contracts the redundant-grant cleanup is scoped to, per chain. +export const REDUNDANT_CONTRACTS: Record> = { + bscmainnet: { + EBrake: "0x35eBaBB99c7Fb7ba0C90bCc26e5d55Cdf89C23Ec", + Prime: "0xBbCD063efE506c3D42a0Fa2dB5C08430288C71FC", + PrimeLeaderboard: "0x55e2ccF68B7A276dc28AfA107997b8B1Be932c0b", + PrimeLiquidityProvider: "0x23c4F844ffDdC6161174eB32c770D4D8C07833F2", + PrimeV2: "0x059EabA8676b03e4e8f009eFb7F587C28450F50f", + Unitroller: "0xfD36E2c2a6789Db23113685031d7F16329158384", + VBNBAdmin: "0x9A7890534d9d91d473F28cB97962d176e2B65f1d", + VenusERC4626Factory: "0xC2f7924809830886EB04c6b40725Fd68F1891fA2", + vUNI: "0x27FF564707786720C71A2e5c1490A63266683612", + }, + ethereum: { + EBrake: "0xCD09042c5DFFed762998Df9a058ec5944e39949B", + Prime: "0x14C4525f47A7f7C984474979c57a2Dccb8EACB39", + PrimeLiquidityProvider: "0x8ba6aFfd0e7Bcd0028D1639225C84DdCf53D8872", + VenusERC4626Factory: "0x39cb747453Be3416E659dAeA169540b6F000c885", + }, + arbitrumone: { + EBrake: "0xFc4CE7Ca9BB5119705Cfb84d6e4476e8a4032b26", + Prime: "0xFE69720424C954A2da05648a0FAC84f9bf11Ef49", + PrimeLiquidityProvider: "0x86bf21dB200f29F21253080942Be8af61046Ec29", + VenusERC4626Factory: "0xC1422B928cb6FC9BA52880892078578a93aa5Cc7", + }, + basemainnet: { + EBrake: "0x062C68Af7B9Fb059DCB7FA4B6b92E633350fb7c2", + Prime: "0xD2e84244f1e9Fca03Ff024af35b8f9612D5d7a30", + PrimeLiquidityProvider: "0xcB293EB385dEFF2CdeDa4E7060974BB90ee0B208", + VenusERC4626Factory: "0x1A430825B31DdA074751D6731Ce7Dca38D012D13", + }, + opmainnet: { + Prime: "0xE76d2173546Be97Fa6E18358027BdE9742a649f7", + PrimeLiquidityProvider: "0x6412f6cd58D0182aE150b90B5A99e285b91C1a12", + VenusERC4626Factory: "0xc801B471F00Dc22B9a7d7b839CBE87E46d70946F", + }, + unichainmainnet: { + Prime: "0x600aFf613d40D87C8Fe90Cb2e78e8e6667c0C872", + PrimeLiquidityProvider: "0x045a45603E1b073F444fe3Be7d5C7e0a5035afB7", + VenusERC4626Factory: "0x102fEb723C25c67dbdfDccCa3B1c1a6e1a662D2f", + }, + zksyncmainnet: { + Prime: "0xdFe62Dcba3Ce0A827439390d7d45Af8baE599978", + PrimeLiquidityProvider: "0x0EDE6d7fB474614C5D3d5a16581628bb96CB5dff", + VenusERC4626Factory: "0xDC59Dd76Dd7A64d743C764a9aa8C96Ff2Ea8BAc3", + }, + opbnbmainnet: { + VenusERC4626Factory: "0x89A5Ce0A6db7e66E53F148B50D879b700dEB81C8", + }, +}; diff --git a/vips/vip-665/data/cleanup.ts b/vips/vip-665/data/cleanup.ts new file mode 100644 index 000000000..953f205ab --- /dev/null +++ b/vips/vip-665/data/cleanup.ts @@ -0,0 +1,576 @@ +// VIP-665 — ACM maintenance cleanup on all mainnets: +// 1. syncCash() normalized to the wildcard (address(0)) convention used by every other vToken setter. +// 2. Stale/dangling grants on removed setters and retired contracts. +// 3. Redundant target-specific grants shadowed by an identical wildcard grant (behavior-preserving). +import { NETWORK_ADDRESSES } from "src/networkAddresses"; + +import type { Permission } from "../utils/commands"; +import { RemoteChain } from "./actionPlan"; +import { BNB_GUARDIANS, REDUNDANT_CONTRACTS as CONTRACTS, RETIRED, SYNC_CASH_MARKETS, ZERO } from "./addresses"; + +const { bscmainnet } = NETWORK_ADDRESSES; + +// =================================================================================================== +// 1. syncCash() wildcard normalization (remote chains) +// =================================================================================================== +export const SYNC_CASH_SIG = "syncCash()"; + +// The single wildcard grant: syncCash() on address(0) → NormalTimelock. +export const syncCashGrants = (chain: RemoteChain): Permission[] => { + const normalTimelock = (NETWORK_ADDRESSES[chain] as Record).NORMAL_TIMELOCK; + return [{ contractAddress: ZERO, functionSig: SYNC_CASH_SIG, account: normalTimelock }]; +}; + +// The per-market revokes: syncCash() → NormalTimelock, one per market. +export const syncCashRevokes = (chain: RemoteChain): Permission[] => { + const normalTimelock = (NETWORK_ADDRESSES[chain] as Record).NORMAL_TIMELOCK; + return SYNC_CASH_MARKETS[chain].map(market => ({ + contractAddress: market, + functionSig: SYNC_CASH_SIG, + account: normalTimelock, + })); +}; + +// =================================================================================================== +// 2. Stale / dangling grants (bscmainnet) +// =================================================================================================== +const NORMAL = bscmainnet.NORMAL_TIMELOCK; +const FASTTRACK = bscmainnet.FAST_TRACK_TIMELOCK; +const CRITICAL = bscmainnet.CRITICAL_TIMELOCK; +const G1 = BNB_GUARDIANS.guardian1; +const G2 = BNB_GUARDIANS.guardian2; +const G3 = BNB_GUARDIANS.guardian3; +const RISK_FUND_V2 = RETIRED.RiskFundV2; +const UNITROLLER = RETIRED.Unitroller; +const RETIRED_RISK_CONFIG = RETIRED.RiskConfig; +const RETIRED_RISK_STEWARD = RETIRED.RiskSteward; +const RETIRED_TWAP_ORACLE = RETIRED.TwapOracle; + +// target = contract the permission is scoped to (ZERO = wildcard); signature = function signature; +// revokeFrom = grantees to drop it from. +export const STALE_ROWS: { target: string; signature: string; revokeFrom: string[] }[] = [ + // Removed setter — the current RiskFundV2 implementation no longer has this function. + { + target: RISK_FUND_V2, + signature: "sweepTokenFromPool(address,address,address,uint256)", + revokeFrom: [NORMAL, FASTTRACK, CRITICAL], + }, + // Legacy 2-arg setter; Guardian 1 already holds the current 3/4-arg setters. + { target: UNITROLLER, signature: "_setCollateralFactor(address,uint256)", revokeFrom: [G1] }, + // Retired risk-config contract — dangling target grants. Holders confirmed on-chain: + // pause/unpause held by Normal+FastTrack+Critical+G2; setRiskParameterConfig only by Normal; + // toggleConfigActive by Normal+FastTrack+Critical (not G2). + { target: RETIRED_RISK_CONFIG, signature: "pause()", revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G2] }, + { target: RETIRED_RISK_CONFIG, signature: "unpause()", revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G2] }, + { target: RETIRED_RISK_CONFIG, signature: "setRiskParameterConfig(string,address,uint256)", revokeFrom: [NORMAL] }, + { target: RETIRED_RISK_CONFIG, signature: "toggleConfigActive(string)", revokeFrom: [NORMAL, FASTTRACK, CRITICAL] }, + // Retired risk steward — dangling target grant. + { target: RETIRED_RISK_STEWARD, signature: "setMaxDeltaBps(uint256)", revokeFrom: [NORMAL, FASTTRACK, CRITICAL] }, + // Retired oracle — dangling target grant. + { + target: RETIRED_TWAP_ORACLE, + signature: "setTokenConfig(TokenConfig)", + revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G3], + }, +]; + +// Retired risk steward still holds live wildcard cap powers as a grantee. On the legacy BNB ACM these +// wildcard grants must be cleared with a direct ACM.revokeRole (see legacyWildcardRole in utils/commands.ts). +export const CLEANUP_LEGACY_WILDCARD_REVOKES: { signature: string; account: string }[] = [ + { signature: "setMarketBorrowCaps(address[],uint256[])", account: RETIRED_RISK_STEWARD }, + { signature: "setMarketSupplyCaps(address[],uint256[])", account: RETIRED_RISK_STEWARD }, +]; + +// =================================================================================================== +// 3. Redundant target-specific grants shadowed by an identical wildcard grant +// =================================================================================================== +export type RedundantChain = + | "bscmainnet" + | "ethereum" + | "arbitrumone" + | "basemainnet" + | "opmainnet" + | "unichainmainnet" + | "zksyncmainnet" + | "opbnbmainnet"; + +// Timelocks / guardians per chain, keyed by networkAddresses (cast for uniform string access). +const na = NETWORK_ADDRESSES as unknown as Record>; + +// A single target-specific grant to revoke. note = "" for review readability. +export interface RedundantRevoke { + contract: string; + signature: string; + account: string; + note: string; +} + +// The 75 redundant target-specific grants, per chain. +export const REDUNDANT_REVOKES: Record = { + bscmainnet: [ + { + contract: CONTRACTS.bscmainnet.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "EBrake — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.bscmainnet.FAST_TRACK_TIMELOCK, + note: "EBrake — FastTrackTimelock", + }, + { + contract: CONTRACTS.bscmainnet.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.bscmainnet.CRITICAL_TIMELOCK, + note: "EBrake — CriticalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "EBrake — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.bscmainnet.FAST_TRACK_TIMELOCK, + note: "EBrake — FastTrackTimelock", + }, + { + contract: CONTRACTS.bscmainnet.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.bscmainnet.CRITICAL_TIMELOCK, + note: "EBrake — CriticalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.Prime, + signature: "setMaxLoopsLimit(uint256)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "Prime — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.PrimeLeaderboard, + signature: "setMaxLoopsLimit(uint256)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "PrimeLeaderboard — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.PrimeLiquidityProvider, + signature: "setMaxLoopsLimit(uint256)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "PrimeLiquidityProvider — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.PrimeV2, + signature: "setMaxLoopsLimit(uint256)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "PrimeV2 — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.Unitroller, + signature: "setCollateralFactor(address,uint256,uint256)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "Unitroller — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.Unitroller, + signature: "setCollateralFactor(address,uint256,uint256)", + account: na.bscmainnet.FAST_TRACK_TIMELOCK, + note: "Unitroller — FastTrackTimelock", + }, + { + contract: CONTRACTS.bscmainnet.Unitroller, + signature: "setCollateralFactor(address,uint256,uint256)", + account: na.bscmainnet.CRITICAL_TIMELOCK, + note: "Unitroller — CriticalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.Unitroller, + signature: "setCollateralFactor(address,uint256,uint256)", + account: na.bscmainnet.CRITICAL_GUARDIAN, + note: "Unitroller — Guardian 1", + }, + { + contract: CONTRACTS.bscmainnet.Unitroller, + signature: "unlistMarket(address)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "Unitroller — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.Unitroller, + signature: "unlistMarket(address)", + account: na.bscmainnet.FAST_TRACK_TIMELOCK, + note: "Unitroller — FastTrackTimelock", + }, + { + contract: CONTRACTS.bscmainnet.Unitroller, + signature: "unlistMarket(address)", + account: na.bscmainnet.CRITICAL_TIMELOCK, + note: "Unitroller — CriticalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.Unitroller, + signature: "unlistMarket(address)", + account: na.bscmainnet.GUARDIAN, + note: "Unitroller — Guardian 2", + }, + { + contract: CONTRACTS.bscmainnet.VBNBAdmin, + signature: "setInterestRateModel(address)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "VBNBAdmin — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.VBNBAdmin, + signature: "setInterestRateModel(address)", + account: na.bscmainnet.FAST_TRACK_TIMELOCK, + note: "VBNBAdmin — FastTrackTimelock", + }, + { + contract: CONTRACTS.bscmainnet.VBNBAdmin, + signature: "setInterestRateModel(address)", + account: na.bscmainnet.CRITICAL_TIMELOCK, + note: "VBNBAdmin — CriticalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.VenusERC4626Factory, + signature: "setMaxLoopsLimit(uint256)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.VenusERC4626Factory, + signature: "setRewardRecipient(address)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.vUNI, + signature: "_setReserveFactor(uint256)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "vUNI — NormalTimelock", + }, + { + contract: CONTRACTS.bscmainnet.vUNI, + signature: "setReduceReservesBlockDelta(uint256)", + account: na.bscmainnet.NORMAL_TIMELOCK, + note: "vUNI — NormalTimelock", + }, + ], + ethereum: [ + { + contract: CONTRACTS.ethereum.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.ethereum.GUARDIAN, + note: "EBrake — Guardian", + }, + { + contract: CONTRACTS.ethereum.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.ethereum.NORMAL_TIMELOCK, + note: "EBrake — NormalTimelock", + }, + { + contract: CONTRACTS.ethereum.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.ethereum.FAST_TRACK_TIMELOCK, + note: "EBrake — FastTrackTimelock", + }, + { + contract: CONTRACTS.ethereum.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.ethereum.CRITICAL_TIMELOCK, + note: "EBrake — CriticalTimelock", + }, + { + contract: CONTRACTS.ethereum.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.ethereum.GUARDIAN, + note: "EBrake — Guardian", + }, + { + contract: CONTRACTS.ethereum.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.ethereum.NORMAL_TIMELOCK, + note: "EBrake — NormalTimelock", + }, + { + contract: CONTRACTS.ethereum.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.ethereum.FAST_TRACK_TIMELOCK, + note: "EBrake — FastTrackTimelock", + }, + { + contract: CONTRACTS.ethereum.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.ethereum.CRITICAL_TIMELOCK, + note: "EBrake — CriticalTimelock", + }, + { + contract: CONTRACTS.ethereum.Prime, + signature: "setMaxLoopsLimit(uint256)", + account: na.ethereum.NORMAL_TIMELOCK, + note: "Prime — NormalTimelock", + }, + { + contract: CONTRACTS.ethereum.PrimeLiquidityProvider, + signature: "setMaxLoopsLimit(uint256)", + account: na.ethereum.NORMAL_TIMELOCK, + note: "PrimeLiquidityProvider — NormalTimelock", + }, + { + contract: CONTRACTS.ethereum.VenusERC4626Factory, + signature: "setMaxLoopsLimit(uint256)", + account: na.ethereum.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.ethereum.VenusERC4626Factory, + signature: "setRewardRecipient(address)", + account: na.ethereum.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + ], + arbitrumone: [ + { + contract: CONTRACTS.arbitrumone.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.arbitrumone.GUARDIAN, + note: "EBrake — Guardian", + }, + { + contract: CONTRACTS.arbitrumone.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.arbitrumone.NORMAL_TIMELOCK, + note: "EBrake — NormalTimelock", + }, + { + contract: CONTRACTS.arbitrumone.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.arbitrumone.FAST_TRACK_TIMELOCK, + note: "EBrake — FastTrackTimelock", + }, + { + contract: CONTRACTS.arbitrumone.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.arbitrumone.CRITICAL_TIMELOCK, + note: "EBrake — CriticalTimelock", + }, + { + contract: CONTRACTS.arbitrumone.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.arbitrumone.GUARDIAN, + note: "EBrake — Guardian", + }, + { + contract: CONTRACTS.arbitrumone.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.arbitrumone.NORMAL_TIMELOCK, + note: "EBrake — NormalTimelock", + }, + { + contract: CONTRACTS.arbitrumone.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.arbitrumone.FAST_TRACK_TIMELOCK, + note: "EBrake — FastTrackTimelock", + }, + { + contract: CONTRACTS.arbitrumone.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.arbitrumone.CRITICAL_TIMELOCK, + note: "EBrake — CriticalTimelock", + }, + { + contract: CONTRACTS.arbitrumone.Prime, + signature: "setMaxLoopsLimit(uint256)", + account: na.arbitrumone.NORMAL_TIMELOCK, + note: "Prime — NormalTimelock", + }, + { + contract: CONTRACTS.arbitrumone.PrimeLiquidityProvider, + signature: "setMaxLoopsLimit(uint256)", + account: na.arbitrumone.NORMAL_TIMELOCK, + note: "PrimeLiquidityProvider — NormalTimelock", + }, + { + contract: CONTRACTS.arbitrumone.VenusERC4626Factory, + signature: "setMaxLoopsLimit(uint256)", + account: na.arbitrumone.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.arbitrumone.VenusERC4626Factory, + signature: "setRewardRecipient(address)", + account: na.arbitrumone.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + ], + basemainnet: [ + { + contract: CONTRACTS.basemainnet.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.basemainnet.GUARDIAN, + note: "EBrake — Guardian", + }, + { + contract: CONTRACTS.basemainnet.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.basemainnet.NORMAL_TIMELOCK, + note: "EBrake — NormalTimelock", + }, + { + contract: CONTRACTS.basemainnet.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.basemainnet.FAST_TRACK_TIMELOCK, + note: "EBrake — FastTrackTimelock", + }, + { + contract: CONTRACTS.basemainnet.EBrake, + signature: "setMarketBorrowCaps(address[],uint256[])", + account: na.basemainnet.CRITICAL_TIMELOCK, + note: "EBrake — CriticalTimelock", + }, + { + contract: CONTRACTS.basemainnet.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.basemainnet.GUARDIAN, + note: "EBrake — Guardian", + }, + { + contract: CONTRACTS.basemainnet.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.basemainnet.NORMAL_TIMELOCK, + note: "EBrake — NormalTimelock", + }, + { + contract: CONTRACTS.basemainnet.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.basemainnet.FAST_TRACK_TIMELOCK, + note: "EBrake — FastTrackTimelock", + }, + { + contract: CONTRACTS.basemainnet.EBrake, + signature: "setMarketSupplyCaps(address[],uint256[])", + account: na.basemainnet.CRITICAL_TIMELOCK, + note: "EBrake — CriticalTimelock", + }, + { + contract: CONTRACTS.basemainnet.Prime, + signature: "setMaxLoopsLimit(uint256)", + account: na.basemainnet.NORMAL_TIMELOCK, + note: "Prime — NormalTimelock", + }, + { + contract: CONTRACTS.basemainnet.PrimeLiquidityProvider, + signature: "setMaxLoopsLimit(uint256)", + account: na.basemainnet.NORMAL_TIMELOCK, + note: "PrimeLiquidityProvider — NormalTimelock", + }, + { + contract: CONTRACTS.basemainnet.VenusERC4626Factory, + signature: "setMaxLoopsLimit(uint256)", + account: na.basemainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.basemainnet.VenusERC4626Factory, + signature: "setRewardRecipient(address)", + account: na.basemainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + ], + opmainnet: [ + { + contract: CONTRACTS.opmainnet.Prime, + signature: "setMaxLoopsLimit(uint256)", + account: na.opmainnet.NORMAL_TIMELOCK, + note: "Prime — NormalTimelock", + }, + { + contract: CONTRACTS.opmainnet.PrimeLiquidityProvider, + signature: "setMaxLoopsLimit(uint256)", + account: na.opmainnet.NORMAL_TIMELOCK, + note: "PrimeLiquidityProvider — NormalTimelock", + }, + { + contract: CONTRACTS.opmainnet.VenusERC4626Factory, + signature: "setMaxLoopsLimit(uint256)", + account: na.opmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.opmainnet.VenusERC4626Factory, + signature: "setRewardRecipient(address)", + account: na.opmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + ], + unichainmainnet: [ + { + contract: CONTRACTS.unichainmainnet.Prime, + signature: "setMaxLoopsLimit(uint256)", + account: na.unichainmainnet.NORMAL_TIMELOCK, + note: "Prime — NormalTimelock", + }, + { + contract: CONTRACTS.unichainmainnet.PrimeLiquidityProvider, + signature: "setMaxLoopsLimit(uint256)", + account: na.unichainmainnet.NORMAL_TIMELOCK, + note: "PrimeLiquidityProvider — NormalTimelock", + }, + { + contract: CONTRACTS.unichainmainnet.VenusERC4626Factory, + signature: "setMaxLoopsLimit(uint256)", + account: na.unichainmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.unichainmainnet.VenusERC4626Factory, + signature: "setRewardRecipient(address)", + account: na.unichainmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + ], + zksyncmainnet: [ + { + contract: CONTRACTS.zksyncmainnet.Prime, + signature: "setMaxLoopsLimit(uint256)", + account: na.zksyncmainnet.NORMAL_TIMELOCK, + note: "Prime — NormalTimelock", + }, + { + contract: CONTRACTS.zksyncmainnet.PrimeLiquidityProvider, + signature: "setMaxLoopsLimit(uint256)", + account: na.zksyncmainnet.NORMAL_TIMELOCK, + note: "PrimeLiquidityProvider — NormalTimelock", + }, + { + contract: CONTRACTS.zksyncmainnet.VenusERC4626Factory, + signature: "setMaxLoopsLimit(uint256)", + account: na.zksyncmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.zksyncmainnet.VenusERC4626Factory, + signature: "setRewardRecipient(address)", + account: na.zksyncmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + ], + opbnbmainnet: [ + { + contract: CONTRACTS.opbnbmainnet.VenusERC4626Factory, + signature: "setMaxLoopsLimit(uint256)", + account: na.opbnbmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + { + contract: CONTRACTS.opbnbmainnet.VenusERC4626Factory, + signature: "setRewardRecipient(address)", + account: na.opbnbmainnet.NORMAL_TIMELOCK, + note: "VenusERC4626Factory — NormalTimelock", + }, + ], +}; diff --git a/vips/vip-665/data/remote.ts b/vips/vip-665/data/remote.ts deleted file mode 100644 index 4f6fefa9c..000000000 --- a/vips/vip-665/data/remote.ts +++ /dev/null @@ -1,195 +0,0 @@ -// Critical-timelock action plan — remote chains (7), reconciled against live ACM state. -// Every remote action is a revoke from Critical (the Guardian keeps whatever it already holds); there are -// no swaps/grants on remotes. -import { NETWORK_ADDRESSES } from "src/networkAddresses"; -import { LzChainId } from "src/types"; - -export const ZERO = "0x0000000000000000000000000000000000000000"; - -export type RemoteChain = - | "ethereum" - | "arbitrumone" - | "basemainnet" - | "zksyncmainnet" - | "opmainnet" - | "unichainmainnet" - | "opbnbmainnet"; - -export const REMOTE_CHAINS: RemoteChain[] = [ - "ethereum", - "arbitrumone", - "basemainnet", - "zksyncmainnet", - "opmainnet", - "unichainmainnet", - "opbnbmainnet", -]; - -export const LZ_CHAIN_ID: Record = { - ethereum: LzChainId.ethereum, - arbitrumone: LzChainId.arbitrumone, - basemainnet: LzChainId.basemainnet, - zksyncmainnet: LzChainId.zksyncmainnet, - opmainnet: LzChainId.opmainnet, - unichainmainnet: LzChainId.unichainmainnet, - opbnbmainnet: LzChainId.opbnbmainnet, -}; - -// ACM for op / unichain / opBNB is not in networkAddresses — hardcoded (verified on-chain). -export const REMOTE_ACM: Record = { - ethereum: NETWORK_ADDRESSES.ethereum.ACCESS_CONTROL_MANAGER, - arbitrumone: NETWORK_ADDRESSES.arbitrumone.ACCESS_CONTROL_MANAGER, - basemainnet: NETWORK_ADDRESSES.basemainnet.ACCESS_CONTROL_MANAGER, - zksyncmainnet: NETWORK_ADDRESSES.zksyncmainnet.ACCESS_CONTROL_MANAGER, - opmainnet: "0xD71b1F33f6B0259683f11174EE4Ddc2bb9cE4eD6", - unichainmainnet: "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0", - opbnbmainnet: "0xA60Deae5344F1152426cA440fb6552eA0e3005D6", -}; - -// Per-chain contract addresses that networkAddresses does not key. -const XVS_BRIDGE_ADMIN: Record = { - ethereum: "0x9C6C95632A8FB3A74f2fB4B7FfC50B003c992b96", - arbitrumone: "0xf5d81C6F7DAA3F97A6265C8441f92eFda22Ad784", - basemainnet: "0x6303FEcee7161bF959d65df4Afb9e1ba5701f78e", - zksyncmainnet: "0x2471043F05Cc41A6051dd6714DC967C7BfC8F902", - opmainnet: "0x3c307DF1Bf3198a2417d9CA86806B307D147Ddf7", - unichainmainnet: "0x2EAaa880f97C9B63d37b39b0b316022d93d43604", - opbnbmainnet: "0x52fcE05aDbf6103d71ed2BA8Be7A317282731831", -}; - -const OMNICHAIN_EXECUTOR_OWNER: Record = { - ethereum: "0x87Ed3Fd3a25d157637b955991fb1B41B566916Ba", - arbitrumone: "0xf72C1Aa0A1227B4bCcB28E1B1015F0616E2db7fD", - basemainnet: "0x8BA591f72a90fb379b9a82087b190d51b226F0a9", - zksyncmainnet: "0xdfaed3E5d9707629Ed5c225b4fB980c064286771", - opmainnet: "0xe6d9Eb3A07a1dc4496fc71417D7A7b9d5666BaA3", - unichainmainnet: "0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd", - opbnbmainnet: "0xf7e4c81Cf4A03d52472a4d00c3d9Ef35aF127E45", -}; - -// SentinelOracle is not published in the @venusprotocol deployment packages — hardcoded proxies, -// verified on-chain. -const SENTINEL_ORACLE: Partial> = { - ethereum: "0x444C53E194B40c272fAd683210e2cB1c16Ab132e", - arbitrumone: "0x3563CAbc541a0432C66A64942ffB4070a9726226", - basemainnet: "0xCdD6D79Fd313C21967CED04C1b8bE70BDc27574D", -}; - -const addressesOf = (chain: RemoteChain) => NETWORK_ADDRESSES[chain] as Record; - -// Resolve a contract key to its address on a chain. On Arbitrum/OP the "CHAINLINK_ORACLE" key is the -// SequencerChainlinkOracle adapter. -export const remoteAddr = (chain: RemoteChain, c: string): string => { - switch (c) { - case "WILDCARD": - return ZERO; - case "ResilientOracle": - return addressesOf(chain).RESILIENT_ORACLE; - case "ChainlinkOracle": - return addressesOf(chain).CHAINLINK_ORACLE; - case "RedStoneOracle": - return addressesOf(chain).REDSTONE_ORACLE; - case "SequencerChainlinkOracle": - return addressesOf(chain).CHAINLINK_ORACLE; - case "SentinelOracle": - return SENTINEL_ORACLE[chain]!; - case "XVSBridgeAdmin": - return XVS_BRIDGE_ADMIN[chain]; - case "OmnichainExecutorOwner": - return OMNICHAIN_EXECUTOR_OWNER[chain]; - default: - throw new Error(`unknown remote contract key ${c}`); - } -}; - -const ALL_REMOTES = REMOTE_CHAINS; - -// Every row is a revoke from Critical. contract = contract key (resolved per-chain); chains = where it -// applies; guardian = Guardian currently holds it (must still hold post-VIP). -export const REMOTE_ROWS: { signature: string; contract: string; chains: RemoteChain[]; guardian: boolean }[] = [ - // ── Common to all 7 remotes ── - { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle", chains: ALL_REMOTES, guardian: true }, - { - signature: "setCollateralFactor(address,uint256,uint256)", - contract: "WILDCARD", - chains: ALL_REMOTES, - guardian: true, - }, - { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner", chains: ALL_REMOTES, guardian: true }, - { - signature: "setMaxDailyReceiveLimit(uint256)", - contract: "OmnichainExecutorOwner", - chains: ALL_REMOTES, - guardian: true, - }, - { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin", chains: ALL_REMOTES, guardian: false }, - - // ── Chain-specific ── - { - signature: "setDirectPrice(address,uint256)", - contract: "ChainlinkOracle", - chains: ["ethereum", "basemainnet", "zksyncmainnet"], - guardian: true, - }, - { - signature: "setTokenConfig(TokenConfig)", - contract: "ChainlinkOracle", - chains: ["ethereum", "basemainnet", "zksyncmainnet"], - guardian: true, - }, - { - signature: "setDirectPrice(address,uint256)", - contract: "RedStoneOracle", - chains: ["ethereum", "arbitrumone", "basemainnet", "zksyncmainnet", "opmainnet", "unichainmainnet"], - guardian: true, - }, - { - signature: "setTokenConfig(TokenConfig)", - contract: "RedStoneOracle", - chains: ["ethereum", "arbitrumone", "basemainnet", "zksyncmainnet", "opmainnet", "unichainmainnet"], - guardian: true, - }, - { - signature: "setDirectPrice(address,uint256)", - contract: "SequencerChainlinkOracle", - chains: ["arbitrumone", "opmainnet"], - guardian: true, - }, - { - signature: "setTokenConfig(TokenConfig)", - contract: "SequencerChainlinkOracle", - chains: ["arbitrumone", "opmainnet"], - guardian: true, - }, - { - signature: "setDirectPrice(address,uint256)", - contract: "SentinelOracle", - chains: ["ethereum", "arbitrumone", "basemainnet"], - guardian: true, - }, - { - signature: "setTokenOracleConfig(address,address)", - contract: "SentinelOracle", - chains: ["ethereum", "arbitrumone", "basemainnet"], - guardian: true, - }, -]; - -// Rows applicable to one chain, with resolved target address. -export const remoteRowsFor = (chain: RemoteChain) => - REMOTE_ROWS.filter(r => r.chains.includes(chain)).map(r => ({ - signature: r.signature, - target: remoteAddr(chain, r.contract), - guardian: r.guardian, - })); - -export const EXPECTED_ROLE_EVENTS: Record<"bscmainnet" | RemoteChain, { granted: number; revoked: number }> = { - bscmainnet: { granted: 6, revoked: 55 }, - ethereum: { granted: 2, revoked: 50 }, - arbitrumone: { granted: 2, revoked: 22 }, - basemainnet: { granted: 2, revoked: 17 }, - zksyncmainnet: { granted: 2, revoked: 19 }, - opmainnet: { granted: 2, revoked: 15 }, - unichainmainnet: { granted: 2, revoked: 15 }, - opbnbmainnet: { granted: 2, revoked: 11 }, -}; diff --git a/vips/vip-665/data/staleness.ts b/vips/vip-665/data/staleness.ts deleted file mode 100644 index 27379876d..000000000 --- a/vips/vip-665/data/staleness.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NETWORK_ADDRESSES } from "src/networkAddresses"; - -const { bscmainnet } = NETWORK_ADDRESSES; -export const ZERO = "0x0000000000000000000000000000000000000000"; - -const NORMAL = bscmainnet.NORMAL_TIMELOCK; -const FASTTRACK = bscmainnet.FAST_TRACK_TIMELOCK; -const CRITICAL = bscmainnet.CRITICAL_TIMELOCK; -const G1 = bscmainnet.CRITICAL_GUARDIAN; -const G2 = bscmainnet.GUARDIAN; -const G3 = "0x3a3284dC0FaFfb0b5F0d074c4C704D14326C98cF"; - -// Retired contracts (absent from every deployment file) still holding grants. -const RISK_FUND_V2 = "0xdF31a28D68A2AB381D42b380649Ead7ae2A76E42"; -const UNITROLLER = "0xfD36E2c2a6789Db23113685031d7F16329158384"; -const RETIRED_RISK_CONFIG = "0xBa2a43279a228cf9cD94d072777d8d98e7e0a229"; -const RETIRED_RISK_STEWARD = "0xE7252dccd79F2A555E314B9cdd440745b697D562"; -const RETIRED_TWAP_ORACLE = "0xea2f042e1A4f057EF8A5220e57733AD747ea8867"; - -// target = contract the permission is scoped to (ZERO = wildcard); signature = function signature; -// revokeFrom = grantees to drop it from. -export const STALE_ROWS: { target: string; signature: string; revokeFrom: string[] }[] = [ - // Removed setter — the current RiskFundV2 implementation no longer has this function. - { - target: RISK_FUND_V2, - signature: "sweepTokenFromPool(address,address,address,uint256)", - revokeFrom: [NORMAL, FASTTRACK, CRITICAL], - }, - // Legacy 2-arg setter; Guardian 1 already holds the current 3/4-arg setters. - { target: UNITROLLER, signature: "_setCollateralFactor(address,uint256)", revokeFrom: [G1] }, - // Retired risk-config contract — dangling target grants. Holders confirmed on-chain: - // pause/unpause held by Normal+FastTrack+Critical+G2; setRiskParameterConfig only by Normal; - // toggleConfigActive by Normal+FastTrack+Critical (not G2). - { target: RETIRED_RISK_CONFIG, signature: "pause()", revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G2] }, - { target: RETIRED_RISK_CONFIG, signature: "unpause()", revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G2] }, - { target: RETIRED_RISK_CONFIG, signature: "setRiskParameterConfig(string,address,uint256)", revokeFrom: [NORMAL] }, - { target: RETIRED_RISK_CONFIG, signature: "toggleConfigActive(string)", revokeFrom: [NORMAL, FASTTRACK, CRITICAL] }, - // Retired risk steward — dangling target grant. - { target: RETIRED_RISK_STEWARD, signature: "setMaxDeltaBps(uint256)", revokeFrom: [NORMAL, FASTTRACK, CRITICAL] }, - // Retired oracle — dangling target grant. - { - target: RETIRED_TWAP_ORACLE, - signature: "setTokenConfig(TokenConfig)", - revokeFrom: [NORMAL, FASTTRACK, CRITICAL, G3], - }, -]; diff --git a/vips/vip-665/data/syncCash.ts b/vips/vip-665/data/syncCash.ts deleted file mode 100644 index 71de1e7ef..000000000 --- a/vips/vip-665/data/syncCash.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { NETWORK_ADDRESSES } from "src/networkAddresses"; - -import type { Permission } from "../utils/commands"; -import { RemoteChain } from "./remote"; - -export const ZERO = "0x0000000000000000000000000000000000000000"; -export const SYNC_CASH_SIG = "syncCash()"; - -// Markets whose syncCash() role is currently granted to the NormalTimelock, per chain (verified on-chain). -export const SYNC_CASH_MARKETS: Record = { - ethereum: [ - "0x0792b9c60C728C1D2Fd6665b3D7A08762a9b28e0", - "0x0Ec5488e4F8f319213a14cab188E01fB8517Faa8", - "0x0c6B19287999f1e31a5c0a44393b24B62D2C0468", - "0x13eB80FDBe5C5f4a7039728E258A6f05fb3B912b", - "0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe", - "0x17C07e0c232f2f80DfDbd7a95b942D893A4C5ACb", - "0x256AdDBe0a387c98f487e44b85c29eb983413c5e", - "0x25C20e6e110A1cE3FEbaCC8b7E48368c7b2F0C91", - "0x2d499800239C4CD3012473Cb1EAE33562F0A6933", - "0x30aD10Bd5Be62CAb37863C2BfcC6E8fb4fD85BDa", - "0x325cEB02fe1C2fF816A83a5770eA0E88e2faEcF2", - "0x475d0C68a8CD275c15D1F01F4f291804E445F677", - "0x4a240F0ee138697726C8a3E43eFE6Ac3593432CB", - "0x4fAfbDc4F2a9876Bd1764827b26fb8dc4FD1dB95", - "0x520d67226Bc904aC122dcE66ed2f8f61AA1ED764", - "0x5e35C312862d53FD566737892aDCf010cb4928F7", - "0x62D9E2010Cff87Bae05B91d5E04605ef864ABc3B", - "0x672208C10aaAA2F9A6719F449C4C8227bc0BC202", - "0x76697f8eaeA4bE01C678376aAb97498Ee8f80D5C", - "0x7c8ff7d2A1372433726f879BD945fFb250B94c65", - "0x8716554364f20BCA783cb2BAA744d39361fd1D8d", - "0x8C3e3821259B82fFb32B2450A95d2dcbf161C24E", - "0xA854D35664c658280fFf27B6eDC6C4195c3229B3", - "0xCca202a95E8096315E3F19E46e19E1b326634889", - "0xDB6C345f864883a8F4cae87852Ac342589E76D1B", - "0xE0ee5dDeBFe0abe0a4Af50299D68b74Cec31668e", - "0xE36Ae842DbbD7aE372ebA02C8239cd431cC063d6", - "0xEF26C64bC06A8dE4CA5D31f119835f9A1d9433b9", - "0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E", - "0xa0EE2bAA024cC3AA1BC9395522D07B7970Ca75b3", - "0xa836ce315b7A6Bb19397Ee996551659B1D92298e", - "0xa8e7f9473635a5CB79646f14356a9Fc394CA111A", - "0xb4933AF59868986316Ed37fa865C829Eba2df0C7", - "0xba3916302cBA4aBcB51a01e706fC6051AaF272A0", - "0xc42E4bfb996ED35235bda505430cBE404Eb49F77", - "0xc82780Db1257C788F262FBbDA960B3706Dfdcaf2", - "0xd8AdD9B41D4E1cd64Edad8722AB0bA8D35536657", - "0xf87c0a64dc3a8622D6c63265FA29137788163879", - ], - arbitrumone: [ - "0x246a35E79a3a0618535A469aDaF5091cAA9f7E88", - "0x39D6d13Ea59548637104E40e729E4aABE27FE106", - "0x4f3a73f318C5EA67A86eaaCE24309F29f89900dF", - "0x68a34332983f4Bf866768DD6D6E638b02eF5e1f0", - "0x7D8609f8da70fF9027E9bc5229Af4F6727662707", - "0x9bb8cEc9C0d46F53b4f2173BB2A0221F66c353cC", - "0x9df6B5132135f14719696bBAe3C54BAb272fDb16", - "0xAeB0FEd69354f34831fe1D16475D9A83ddaCaDA6", - "0xB9F9117d4200dC296F9AcD1e8bE1937df834a2fD", - "0xaDa57840B372D4c28623E87FC175dE8490792811", - ], - basemainnet: [ - "0x133d3BCD77158D125B75A17Cb517fFD4B4BE64C5", - "0x3cb752d175740043Ec463673094e06ACDa2F9a2e", - "0x75201D81B3B0b9D17b179118837Be37f64fc4930", - "0x7bBd1005bB24Ec84705b04e1f2DfcCad533b6D72", - "0xEB8A79bD44cF4500943bf94a2b4434c95C008599", - ], - zksyncmainnet: [ - "0x03CAd66259f7F34EE075f8B62D133563D249eDa4", - "0x183dE3C349fCf546aAe925E1c7F364EA6FB4033c", - "0x1Fa916C27c7C2c4602124A14C77Dbb40a5FF1BE8", - "0x1aF23bD57c62A99C59aD48236553D0Dd11e49D2D", - "0x697a70779C1A03Ba2BD28b7627a902BFf831b616", - "0x69cDA960E3b20DFD480866fFfd377Ebe40bd0A46", - "0x84064c058F2EFea4AB648bB6Bd7e40f83fFDe39a", - "0xAF8fD83cFCbe963211FAaf1847F0F217F80B4719", - "0xCEb7Da150d16aCE58F090754feF2775C23C8b631", - ], - opmainnet: [ - "0x1C9406ee95B7af55F005996947b19F91B6D55b15", - "0x37ac9731B0B02df54975cd0c7240e0977a051721", - "0x66d5AE25731Ce99D46770745385e662C8e0B4025", - "0x6b846E3418455804C1920fA4CC7a31A51C659A2D", - "0x9EfdCfC2373f81D3DF24647B1c46e15268884c46", - ], - unichainmainnet: [ - "0x0170398083eb0D0387709523baFCA6426146C218", - "0x67716D6Bf76170Af816F5735e14c4d44D0B05eD2", - "0x68e2A6F7257FAc2F5a557b9E83E1fE6D5B408CE5", - "0xB953f92B9f759d97d2F2Dec10A8A3cf75fcE3A95", - "0xDa7Ce7Ba016d266645712e2e4Ebc6cC75eA8E4CD", - "0xbEC19Bef402C697a7be315d3e59E5F65b89Fa1BB", - "0xc219BC179C7cDb37eACB03f993f9fDc2495e3374", - ], - opbnbmainnet: [ - "0x13B492B8A03d072Bab5C54AC91Dba5b830a50917", - "0x509e81eF638D489936FA85BC58F52Df01190d26C", - "0x53d11cB8A0e5320Cd7229C3acc80d1A0707F2672", - "0xED827b80Bd838192EA95002C01B5c6dA8354219a", - "0xb7a01Ba126830692238521a1aA7E7A7509410b8e", - ], -}; - -// The single wildcard grant: syncCash() on address(0) → NormalTimelock. -export const syncCashGrants = (chain: RemoteChain): Permission[] => { - const normalTimelock = (NETWORK_ADDRESSES[chain] as Record).NORMAL_TIMELOCK; - return [{ contractAddress: ZERO, functionSig: SYNC_CASH_SIG, account: normalTimelock }]; -}; - -// The per-market revokes: syncCash() → NormalTimelock, one per market. -export const syncCashRevokes = (chain: RemoteChain): Permission[] => { - const normalTimelock = (NETWORK_ADDRESSES[chain] as Record).NORMAL_TIMELOCK; - return SYNC_CASH_MARKETS[chain].map(market => ({ - contractAddress: market, - functionSig: SYNC_CASH_SIG, - account: normalTimelock, - })); -}; diff --git a/vips/vip-665/utils/commands.ts b/vips/vip-665/utils/commands.ts index 5b7ad9bb2..101ff23b8 100644 --- a/vips/vip-665/utils/commands.ts +++ b/vips/vip-665/utils/commands.ts @@ -1,9 +1,23 @@ +import { ethers } from "ethers"; import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { Command } from "src/types"; -import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, BNB_ROWS } from "../data/bnb"; -import { REMOTE_ACM, REMOTE_CHAINS, RemoteChain, remoteRowsFor } from "../data/remote"; -import { STALE_ROWS } from "../data/staleness"; -import { syncCashGrants, syncCashRevokes } from "../data/syncCash"; +import { + BNB_ACTION_LEGACY_WILDCARD_REVOKES, + BNB_ROWS, + REMOTE_CHAINS, + RemoteChain, + remoteRowsFor, +} from "../data/actionPlan"; +import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, REMOTE_ACM } from "../data/addresses"; +import { + CLEANUP_LEGACY_WILDCARD_REVOKES, + REDUNDANT_REVOKES, + RedundantChain, + STALE_ROWS, + syncCashGrants, + syncCashRevokes, +} from "../data/cleanup"; export type Chain = "bscmainnet" | RemoteChain; export const CHAINS: Chain[] = ["bscmainnet", ...REMOTE_CHAINS]; @@ -56,8 +70,8 @@ export interface Permission { } // Permissions the aggregator grants on a chain. On BNB: swap → move a function to a Guardian, grant → add a -// Guardian alongside Critical. On remotes: the single wildcard syncCash() grant to NormalTimelock (the -// syncCash hygiene cleanup); remotes have no Guardian swaps/grants. +// Guardian alongside Critical. On remotes: the single wildcard syncCash() grant to NormalTimelock; remotes +// have no Guardian swaps/grants. export const grantPermissions = (chain: Chain): Permission[] => { if (chain !== "bscmainnet") return syncCashGrants(chain); return BNB_ROWS.filter(r => r.action === "swap" || r.action === "grant").map(r => ({ @@ -67,25 +81,66 @@ export const grantPermissions = (chain: Chain): Permission[] => { })); }; +// Key identifying a unique ACM revoke (contract + function + grantee), used to de-duplicate the redundant +// cleanup against the base plan (e.g. Unitroller setCollateralFactor from Critical is in both). +const revokeKey = (p: Permission) => `${p.contractAddress.toLowerCase()}|${p.functionSig}|${p.account.toLowerCase()}`; + +// Redundant target-specific grants to revoke on a chain — shadowed by an identical wildcard grant held by the +// same account, so revoking them is behavior-preserving. +const redundantRevokes = (chain: Chain): Permission[] => + REDUNDANT_REVOKES[chain as RedundantChain].map(r => ({ + contractAddress: r.contract, + functionSig: r.signature, + account: r.account, + })); + // Permissions the aggregator revokes on a chain: revoke/swap/stale rows from Critical on BNB (plus the -// staleness / legacy cleanup); on remotes every remote row from that chain's Critical, plus the per-market -// syncCash() grants from NormalTimelock (replaced by the wildcard grant above). +// dangling-grant cleanup); on remotes every remote row from that chain's Critical, plus the per-market +// syncCash() grants from NormalTimelock (replaced by the wildcard grant). Finally the redundant +// (wildcard-shadowed) target-specific grants, de-duplicated against everything above. export const revokePermissions = (chain: Chain): Permission[] => { + let base: Permission[]; if (chain === "bscmainnet") { - const revokes: Permission[] = BNB_ROWS.filter( - r => r.action === "revoke" || r.action === "swap" || r.action === "stale", - ).map(r => ({ contractAddress: r.target, functionSig: r.signature, account: BNB_CRITICAL })); - // Staleness / legacy cleanup: revoke each dangling grant from every current holder. + base = BNB_ROWS.filter(r => r.action === "revoke" || r.action === "swap" || r.action === "stale").map(r => ({ + contractAddress: r.target, + functionSig: r.signature, + account: BNB_CRITICAL, + })); for (const s of STALE_ROWS) - for (const who of s.revokeFrom) - revokes.push({ contractAddress: s.target, functionSig: s.signature, account: who }); - return revokes; + for (const who of s.revokeFrom) base.push({ contractAddress: s.target, functionSig: s.signature, account: who }); + } else { + const critical = criticalOf(chain); + const criticalRevokes = remoteRowsFor(chain).map(r => ({ + contractAddress: r.target, + functionSig: r.signature, + account: critical, + })); + base = [...criticalRevokes, ...syncCashRevokes(chain)]; } - const critical = criticalOf(chain); - const criticalRevokes = remoteRowsFor(chain).map(r => ({ - contractAddress: r.target, - functionSig: r.signature, - account: critical, - })); - return [...criticalRevokes, ...syncCashRevokes(chain)]; + const seen = new Set(base.map(revokeKey)); + const redundant = redundantRevokes(chain).filter(p => !seen.has(revokeKey(p))); + return [...base, ...redundant]; }; + +// BNB legacy-ACM wildcard quirk. The AccessControlManager on bscmainnet derives a wildcard ("any contract") +// role from the 32-byte DEFAULT_ADMIN_ROLE constant, not the 20-byte address(0). revokeCallPermission hashes +// the 20-byte zero, so it targets a different role and can never clear a wildcard grant — and the +// ACMCommandsAggregator only calls give/revokeCallPermission. These grants are cleared with a direct +// ACM.revokeRole(legacyRole, account), which the NormalTimelock (proposal executor and ACM DEFAULT_ADMIN) can call. +export const legacyWildcardRole = (signature: string): string => + ethers.utils.solidityKeccak256(["bytes32", "string"], [ethers.constants.HashZero, signature]); + +// Wildcard grants on the bscmainnet legacy ACM the plan revokes but the aggregator cannot reach: the +// setCollateralFactor revoke from Critical (action plan) and the retired risk steward cap powers (cleanup). +export const BNB_LEGACY_WILDCARD_REVOKES: { signature: string; account: string }[] = [ + ...BNB_ACTION_LEGACY_WILDCARD_REVOKES, + ...CLEANUP_LEGACY_WILDCARD_REVOKES, +]; + +// Direct ACM.revokeRole calls for the legacy wildcard grants, executed by the NormalTimelock. +export const legacyWildcardCommands = (): Command[] => + BNB_LEGACY_WILDCARD_REVOKES.map(r => ({ + target: BNB_ACM, + signature: "revokeRole(bytes32,address)", + params: [legacyWildcardRole(r.signature), r.account], + })); From 9d2cdbf3db30615495e3438d72dacc276c7ca932 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 15 Jul 2026 01:21:43 +0530 Subject: [PATCH 06/11] test: assert critical cannot call revoked funcs; drop unused note field --- simulations/vip-665/bscmainnet.ts | 14 ++++- simulations/vip-665/utils/remoteSim.ts | 12 +++- vips/vip-665/data/cleanup.ts | 78 +------------------------- 3 files changed, 21 insertions(+), 83 deletions(-) diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts index 6339ec90e..5c404b128 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-665/bscmainnet.ts @@ -84,7 +84,7 @@ forking(FORK_BLOCK, async () => { for (const r of REDUNDANT) { expect( await acm().hasRole(role(r.contract, r.signature), r.account), - `pre redundant ${r.note} (${r.signature})`, + `pre redundant ${r.signature}@${r.contract} ${r.account}`, ).to.be.true; } }); @@ -206,6 +206,14 @@ forking(FORK_BLOCK, async () => { expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; }); + it("behavioral: the CriticalTimelock can no longer call any revoked or stale function", async () => { + for (const row of [...REVOKE, ...STALE]) + expect( + await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), + `crit still allowed ${row.signature}@${row.target}`, + ).to.be.false; + }); + it("swap: Critical lost each one and the target Guardian gained it", async () => { for (const row of SWAP) { expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; @@ -254,7 +262,7 @@ forking(FORK_BLOCK, async () => { for (const r of REDUNDANT) { expect( await acm().hasRole(role(r.contract, r.signature), r.account), - `post redundant ${r.note} (${r.signature})`, + `post redundant ${r.signature}@${r.contract} ${r.account}`, ).to.be.false; } }); @@ -266,7 +274,7 @@ forking(FORK_BLOCK, async () => { if (r.signature === "setCollateralFactor(address,uint256,uint256)" && r.account === BNB_CRITICAL) continue; expect( await acm().isAllowedToCall(r.account, r.signature, { from: r.contract }), - `still callable ${r.note} (${r.signature})`, + `still callable ${r.signature}@${r.contract} ${r.account}`, ).to.be.true; } }); diff --git a/simulations/vip-665/utils/remoteSim.ts b/simulations/vip-665/utils/remoteSim.ts index a0a451c1b..0481aba22 100644 --- a/simulations/vip-665/utils/remoteSim.ts +++ b/simulations/vip-665/utils/remoteSim.ts @@ -47,7 +47,10 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { it("redundant: each target-specific grant is currently held by its account", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); for (const r of redundant) - expect(await acm.hasRole(role(r.contract, r.signature), r.account), `pre redundant ${r.note}`).to.be.true; + expect( + await acm.hasRole(role(r.contract, r.signature), r.account), + `pre redundant ${r.signature}@${r.contract} ${r.account}`, + ).to.be.true; }); it("revoke: Critical currently holds every permission to be revoked", async () => { @@ -111,7 +114,10 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { it("redundant: each target-specific grant was revoked", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); for (const r of redundant) - expect(await acm.hasRole(role(r.contract, r.signature), r.account), `post redundant ${r.note}`).to.be.false; + expect( + await acm.hasRole(role(r.contract, r.signature), r.account), + `post redundant ${r.signature}@${r.contract} ${r.account}`, + ).to.be.false; }); it("redundant behavioral: each account can still call the function via the surviving wildcard", async () => { @@ -119,7 +125,7 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { for (const r of redundant) expect( await acm.isAllowedToCall(r.account, r.signature, { from: r.contract }), - `post callable ${r.note} (${r.signature})`, + `post callable ${r.signature}@${r.contract} ${r.account}`, ).to.be.true; }); diff --git a/vips/vip-665/data/cleanup.ts b/vips/vip-665/data/cleanup.ts index 953f205ab..f30d03d2d 100644 --- a/vips/vip-665/data/cleanup.ts +++ b/vips/vip-665/data/cleanup.ts @@ -97,12 +97,11 @@ export type RedundantChain = // Timelocks / guardians per chain, keyed by networkAddresses (cast for uniform string access). const na = NETWORK_ADDRESSES as unknown as Record>; -// A single target-specific grant to revoke. note = "" for review readability. +// A single target-specific grant to revoke. export interface RedundantRevoke { contract: string; signature: string; account: string; - note: string; } // The 75 redundant target-specific grants, per chain. @@ -112,151 +111,126 @@ export const REDUNDANT_REVOKES: Record = { contract: CONTRACTS.bscmainnet.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "EBrake — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.bscmainnet.FAST_TRACK_TIMELOCK, - note: "EBrake — FastTrackTimelock", }, { contract: CONTRACTS.bscmainnet.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.bscmainnet.CRITICAL_TIMELOCK, - note: "EBrake — CriticalTimelock", }, { contract: CONTRACTS.bscmainnet.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "EBrake — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.bscmainnet.FAST_TRACK_TIMELOCK, - note: "EBrake — FastTrackTimelock", }, { contract: CONTRACTS.bscmainnet.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.bscmainnet.CRITICAL_TIMELOCK, - note: "EBrake — CriticalTimelock", }, { contract: CONTRACTS.bscmainnet.Prime, signature: "setMaxLoopsLimit(uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "Prime — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.PrimeLeaderboard, signature: "setMaxLoopsLimit(uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "PrimeLeaderboard — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.PrimeLiquidityProvider, signature: "setMaxLoopsLimit(uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "PrimeLiquidityProvider — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.PrimeV2, signature: "setMaxLoopsLimit(uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "PrimeV2 — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.Unitroller, signature: "setCollateralFactor(address,uint256,uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "Unitroller — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.Unitroller, signature: "setCollateralFactor(address,uint256,uint256)", account: na.bscmainnet.FAST_TRACK_TIMELOCK, - note: "Unitroller — FastTrackTimelock", }, { contract: CONTRACTS.bscmainnet.Unitroller, signature: "setCollateralFactor(address,uint256,uint256)", account: na.bscmainnet.CRITICAL_TIMELOCK, - note: "Unitroller — CriticalTimelock", }, { contract: CONTRACTS.bscmainnet.Unitroller, signature: "setCollateralFactor(address,uint256,uint256)", account: na.bscmainnet.CRITICAL_GUARDIAN, - note: "Unitroller — Guardian 1", }, { contract: CONTRACTS.bscmainnet.Unitroller, signature: "unlistMarket(address)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "Unitroller — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.Unitroller, signature: "unlistMarket(address)", account: na.bscmainnet.FAST_TRACK_TIMELOCK, - note: "Unitroller — FastTrackTimelock", }, { contract: CONTRACTS.bscmainnet.Unitroller, signature: "unlistMarket(address)", account: na.bscmainnet.CRITICAL_TIMELOCK, - note: "Unitroller — CriticalTimelock", }, { contract: CONTRACTS.bscmainnet.Unitroller, signature: "unlistMarket(address)", account: na.bscmainnet.GUARDIAN, - note: "Unitroller — Guardian 2", }, { contract: CONTRACTS.bscmainnet.VBNBAdmin, signature: "setInterestRateModel(address)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "VBNBAdmin — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.VBNBAdmin, signature: "setInterestRateModel(address)", account: na.bscmainnet.FAST_TRACK_TIMELOCK, - note: "VBNBAdmin — FastTrackTimelock", }, { contract: CONTRACTS.bscmainnet.VBNBAdmin, signature: "setInterestRateModel(address)", account: na.bscmainnet.CRITICAL_TIMELOCK, - note: "VBNBAdmin — CriticalTimelock", }, { contract: CONTRACTS.bscmainnet.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.VenusERC4626Factory, signature: "setRewardRecipient(address)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.vUNI, signature: "_setReserveFactor(uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "vUNI — NormalTimelock", }, { contract: CONTRACTS.bscmainnet.vUNI, signature: "setReduceReservesBlockDelta(uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, - note: "vUNI — NormalTimelock", }, ], ethereum: [ @@ -264,73 +238,61 @@ export const REDUNDANT_REVOKES: Record = { contract: CONTRACTS.ethereum.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.ethereum.GUARDIAN, - note: "EBrake — Guardian", }, { contract: CONTRACTS.ethereum.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.ethereum.NORMAL_TIMELOCK, - note: "EBrake — NormalTimelock", }, { contract: CONTRACTS.ethereum.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.ethereum.FAST_TRACK_TIMELOCK, - note: "EBrake — FastTrackTimelock", }, { contract: CONTRACTS.ethereum.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.ethereum.CRITICAL_TIMELOCK, - note: "EBrake — CriticalTimelock", }, { contract: CONTRACTS.ethereum.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.ethereum.GUARDIAN, - note: "EBrake — Guardian", }, { contract: CONTRACTS.ethereum.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.ethereum.NORMAL_TIMELOCK, - note: "EBrake — NormalTimelock", }, { contract: CONTRACTS.ethereum.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.ethereum.FAST_TRACK_TIMELOCK, - note: "EBrake — FastTrackTimelock", }, { contract: CONTRACTS.ethereum.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.ethereum.CRITICAL_TIMELOCK, - note: "EBrake — CriticalTimelock", }, { contract: CONTRACTS.ethereum.Prime, signature: "setMaxLoopsLimit(uint256)", account: na.ethereum.NORMAL_TIMELOCK, - note: "Prime — NormalTimelock", }, { contract: CONTRACTS.ethereum.PrimeLiquidityProvider, signature: "setMaxLoopsLimit(uint256)", account: na.ethereum.NORMAL_TIMELOCK, - note: "PrimeLiquidityProvider — NormalTimelock", }, { contract: CONTRACTS.ethereum.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.ethereum.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.ethereum.VenusERC4626Factory, signature: "setRewardRecipient(address)", account: na.ethereum.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, ], arbitrumone: [ @@ -338,73 +300,61 @@ export const REDUNDANT_REVOKES: Record = { contract: CONTRACTS.arbitrumone.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.arbitrumone.GUARDIAN, - note: "EBrake — Guardian", }, { contract: CONTRACTS.arbitrumone.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.arbitrumone.NORMAL_TIMELOCK, - note: "EBrake — NormalTimelock", }, { contract: CONTRACTS.arbitrumone.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.arbitrumone.FAST_TRACK_TIMELOCK, - note: "EBrake — FastTrackTimelock", }, { contract: CONTRACTS.arbitrumone.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.arbitrumone.CRITICAL_TIMELOCK, - note: "EBrake — CriticalTimelock", }, { contract: CONTRACTS.arbitrumone.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.arbitrumone.GUARDIAN, - note: "EBrake — Guardian", }, { contract: CONTRACTS.arbitrumone.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.arbitrumone.NORMAL_TIMELOCK, - note: "EBrake — NormalTimelock", }, { contract: CONTRACTS.arbitrumone.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.arbitrumone.FAST_TRACK_TIMELOCK, - note: "EBrake — FastTrackTimelock", }, { contract: CONTRACTS.arbitrumone.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.arbitrumone.CRITICAL_TIMELOCK, - note: "EBrake — CriticalTimelock", }, { contract: CONTRACTS.arbitrumone.Prime, signature: "setMaxLoopsLimit(uint256)", account: na.arbitrumone.NORMAL_TIMELOCK, - note: "Prime — NormalTimelock", }, { contract: CONTRACTS.arbitrumone.PrimeLiquidityProvider, signature: "setMaxLoopsLimit(uint256)", account: na.arbitrumone.NORMAL_TIMELOCK, - note: "PrimeLiquidityProvider — NormalTimelock", }, { contract: CONTRACTS.arbitrumone.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.arbitrumone.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.arbitrumone.VenusERC4626Factory, signature: "setRewardRecipient(address)", account: na.arbitrumone.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, ], basemainnet: [ @@ -412,73 +362,61 @@ export const REDUNDANT_REVOKES: Record = { contract: CONTRACTS.basemainnet.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.basemainnet.GUARDIAN, - note: "EBrake — Guardian", }, { contract: CONTRACTS.basemainnet.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.basemainnet.NORMAL_TIMELOCK, - note: "EBrake — NormalTimelock", }, { contract: CONTRACTS.basemainnet.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.basemainnet.FAST_TRACK_TIMELOCK, - note: "EBrake — FastTrackTimelock", }, { contract: CONTRACTS.basemainnet.EBrake, signature: "setMarketBorrowCaps(address[],uint256[])", account: na.basemainnet.CRITICAL_TIMELOCK, - note: "EBrake — CriticalTimelock", }, { contract: CONTRACTS.basemainnet.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.basemainnet.GUARDIAN, - note: "EBrake — Guardian", }, { contract: CONTRACTS.basemainnet.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.basemainnet.NORMAL_TIMELOCK, - note: "EBrake — NormalTimelock", }, { contract: CONTRACTS.basemainnet.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.basemainnet.FAST_TRACK_TIMELOCK, - note: "EBrake — FastTrackTimelock", }, { contract: CONTRACTS.basemainnet.EBrake, signature: "setMarketSupplyCaps(address[],uint256[])", account: na.basemainnet.CRITICAL_TIMELOCK, - note: "EBrake — CriticalTimelock", }, { contract: CONTRACTS.basemainnet.Prime, signature: "setMaxLoopsLimit(uint256)", account: na.basemainnet.NORMAL_TIMELOCK, - note: "Prime — NormalTimelock", }, { contract: CONTRACTS.basemainnet.PrimeLiquidityProvider, signature: "setMaxLoopsLimit(uint256)", account: na.basemainnet.NORMAL_TIMELOCK, - note: "PrimeLiquidityProvider — NormalTimelock", }, { contract: CONTRACTS.basemainnet.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.basemainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.basemainnet.VenusERC4626Factory, signature: "setRewardRecipient(address)", account: na.basemainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, ], opmainnet: [ @@ -486,25 +424,21 @@ export const REDUNDANT_REVOKES: Record = { contract: CONTRACTS.opmainnet.Prime, signature: "setMaxLoopsLimit(uint256)", account: na.opmainnet.NORMAL_TIMELOCK, - note: "Prime — NormalTimelock", }, { contract: CONTRACTS.opmainnet.PrimeLiquidityProvider, signature: "setMaxLoopsLimit(uint256)", account: na.opmainnet.NORMAL_TIMELOCK, - note: "PrimeLiquidityProvider — NormalTimelock", }, { contract: CONTRACTS.opmainnet.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.opmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.opmainnet.VenusERC4626Factory, signature: "setRewardRecipient(address)", account: na.opmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, ], unichainmainnet: [ @@ -512,25 +446,21 @@ export const REDUNDANT_REVOKES: Record = { contract: CONTRACTS.unichainmainnet.Prime, signature: "setMaxLoopsLimit(uint256)", account: na.unichainmainnet.NORMAL_TIMELOCK, - note: "Prime — NormalTimelock", }, { contract: CONTRACTS.unichainmainnet.PrimeLiquidityProvider, signature: "setMaxLoopsLimit(uint256)", account: na.unichainmainnet.NORMAL_TIMELOCK, - note: "PrimeLiquidityProvider — NormalTimelock", }, { contract: CONTRACTS.unichainmainnet.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.unichainmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.unichainmainnet.VenusERC4626Factory, signature: "setRewardRecipient(address)", account: na.unichainmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, ], zksyncmainnet: [ @@ -538,25 +468,21 @@ export const REDUNDANT_REVOKES: Record = { contract: CONTRACTS.zksyncmainnet.Prime, signature: "setMaxLoopsLimit(uint256)", account: na.zksyncmainnet.NORMAL_TIMELOCK, - note: "Prime — NormalTimelock", }, { contract: CONTRACTS.zksyncmainnet.PrimeLiquidityProvider, signature: "setMaxLoopsLimit(uint256)", account: na.zksyncmainnet.NORMAL_TIMELOCK, - note: "PrimeLiquidityProvider — NormalTimelock", }, { contract: CONTRACTS.zksyncmainnet.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.zksyncmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.zksyncmainnet.VenusERC4626Factory, signature: "setRewardRecipient(address)", account: na.zksyncmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, ], opbnbmainnet: [ @@ -564,13 +490,11 @@ export const REDUNDANT_REVOKES: Record = { contract: CONTRACTS.opbnbmainnet.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.opbnbmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, { contract: CONTRACTS.opbnbmainnet.VenusERC4626Factory, signature: "setRewardRecipient(address)", account: na.opbnbmainnet.NORMAL_TIMELOCK, - note: "VenusERC4626Factory — NormalTimelock", }, ], }; From 01e4e69a0dd91111092dfa49e42db38b9b621a81 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 15 Jul 2026 01:46:50 +0530 Subject: [PATCH 07/11] fix: keep CriticalTimelock's setMinAmountToConvert on USDTPrimeConverter (live function) --- simulations/vip-665/bscmainnet.ts | 36 ++----------------------------- vips/vip-665/bscmainnet.ts | 2 +- vips/vip-665/data/actionPlan.ts | 6 ++++-- vips/vip-665/utils/commands.ts | 4 ++-- 4 files changed, 9 insertions(+), 39 deletions(-) diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts index 5c404b128..ed1d3518d 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-665/bscmainnet.ts @@ -31,14 +31,13 @@ const vUSDT = "0xfD5840Cd36d94D7229439859C0112a4185BC0255"; const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["address", "string"], [at, fn]); -// One row bucket per action so every category (no-change / revoke / swap / grant / stale) is asserted +// One row bucket per action so every category (no-change / revoke / swap / grant) is asserted // explicitly. Each bucket is guarded to be non-empty so a data regression that empties a category fails // loudly instead of passing vacuously. const NO_CHANGE = BNB_ROWS.filter(row => row.action === "none"); const REVOKE = BNB_ROWS.filter(row => row.action === "revoke"); const SWAP = BNB_ROWS.filter(row => row.action === "swap"); const GRANT = BNB_ROWS.filter(row => row.action === "grant"); -const STALE = BNB_ROWS.filter(row => row.action === "stale"); // Redundant (wildcard-shadowed) target-specific grants revoked as behavior-preserving cleanup. const REDUNDANT = REDUNDANT_REVOKES.bscmainnet; @@ -61,11 +60,10 @@ forking(FORK_BLOCK, async () => { describe("VIP-665 pre-execution permissions (bscmainnet)", () => { it("the action plan covers every category with the expected row counts", () => { - expect(NO_CHANGE.length, "no-change rows").to.equal(185); + expect(NO_CHANGE.length, "no-change rows").to.equal(186); expect(REVOKE.length, "revoke rows").to.equal(26); expect(SWAP.length, "swap rows").to.equal(4); expect(GRANT.length, "grant rows").to.equal(1); - expect(STALE.length, "stale (BNB) rows").to.equal(1); expect(STALE_ROWS.length, "stale (dangling cleanup) rows").to.equal(8); expect(BNB_LEGACY_WILDCARD_REVOKES.length, "legacy wildcard revokes").to.equal(3); expect(REDUNDANT.length, "redundant revokes").to.equal(25); @@ -133,21 +131,6 @@ forking(FORK_BLOCK, async () => { } }); - it("stale (BNB rows): Critical currently holds each dangling permission", async () => { - for (const row of STALE) { - expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.be.true; - expect(await holds(BNB_GUARDIANS.guardian1, row), `pre g1 ${row.signature}@${row.target}`).to.equal( - row.guardian1, - ); - expect(await holds(BNB_GUARDIANS.guardian2, row), `pre g2 ${row.signature}@${row.target}`).to.equal( - row.guardian2, - ); - expect(await holds(BNB_GUARDIANS.guardian3, row), `pre g3 ${row.signature}@${row.target}`).to.equal( - row.guardian3, - ); - } - }); - it("stale (dangling cleanup): every listed grantee currently holds the dangling permission", async () => { for (const staleRow of STALE_ROWS) for (const who of staleRow.revokeFrom) @@ -228,21 +211,6 @@ forking(FORK_BLOCK, async () => { } }); - it("stale (BNB rows): Critical lost each dangling permission; Guardian flags unchanged", async () => { - for (const row of STALE) { - expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; - expect(await holds(BNB_GUARDIANS.guardian1, row), `post g1 ${row.signature}@${row.target}`).to.equal( - row.guardian1, - ); - expect(await holds(BNB_GUARDIANS.guardian2, row), `post g2 ${row.signature}@${row.target}`).to.equal( - row.guardian2, - ); - expect(await holds(BNB_GUARDIANS.guardian3, row), `post g3 ${row.signature}@${row.target}`).to.equal( - row.guardian3, - ); - } - }); - it("stale (dangling cleanup): every listed grantee lost the dangling permission", async () => { for (const staleRow of STALE_ROWS) for (const who of staleRow.revokeFrom) diff --git a/vips/vip-665/bscmainnet.ts b/vips/vip-665/bscmainnet.ts index 7337542a1..17c727816 100644 --- a/vips/vip-665/bscmainnet.ts +++ b/vips/vip-665/bscmainnet.ts @@ -18,7 +18,7 @@ import { // granted = aggregator grants + wrapper grantRole(DEFAULT_ADMIN). revoked = aggregator revokes + wrapper // revokeRole(DEFAULT_ADMIN) + redundant cleanup + (BNB only) the 3 direct legacy-wildcard revokeRole calls. export const EXPECTED_ROLE_EVENTS: Record<"bscmainnet" | RemoteChain, { granted: number; revoked: number }> = { - bscmainnet: { granted: 6, revoked: 82 }, + bscmainnet: { granted: 6, revoked: 81 }, ethereum: { granted: 2, revoked: 62 }, arbitrumone: { granted: 2, revoked: 34 }, basemainnet: { granted: 2, revoked: 29 }, diff --git a/vips/vip-665/data/actionPlan.ts b/vips/vip-665/data/actionPlan.ts index c8d186b95..ddfcec9a1 100644 --- a/vips/vip-665/data/actionPlan.ts +++ b/vips/vip-665/data/actionPlan.ts @@ -15,7 +15,7 @@ import { // =================================================================================================== // BNB Chain // =================================================================================================== -export type Action = "none" | "revoke" | "swap" | "grant" | "stale"; +export type Action = "none" | "revoke" | "swap" | "grant"; // signature = ACM-registered function signature; target = contract it is scoped to; // critical/guardian1/guardian2/guardian3 = current holders; action = final action; // grantTo = destination guardian for swap/grant actions. @@ -1024,6 +1024,8 @@ export const BNB_ROWS: { guardian3: false, action: "none", }, + // setMinAmountToConvert is not revoked here: the grant looks dangling but the contract/function is live, + // so Critical keeps it (No change). The stale grant, if any, is handled explicitly in a separate cleanup. { signature: "setMinAmountToConvert(uint256)", target: CONTRACTS.USDTPrimeConverter, @@ -1031,7 +1033,7 @@ export const BNB_ROWS: { guardian1: false, guardian2: false, guardian3: false, - action: "stale", + action: "none", }, { signature: "pauseConversion()", diff --git a/vips/vip-665/utils/commands.ts b/vips/vip-665/utils/commands.ts index 101ff23b8..36d97118b 100644 --- a/vips/vip-665/utils/commands.ts +++ b/vips/vip-665/utils/commands.ts @@ -94,14 +94,14 @@ const redundantRevokes = (chain: Chain): Permission[] => account: r.account, })); -// Permissions the aggregator revokes on a chain: revoke/swap/stale rows from Critical on BNB (plus the +// Permissions the aggregator revokes on a chain: revoke/swap rows from Critical on BNB (plus the // dangling-grant cleanup); on remotes every remote row from that chain's Critical, plus the per-market // syncCash() grants from NormalTimelock (replaced by the wildcard grant). Finally the redundant // (wildcard-shadowed) target-specific grants, de-duplicated against everything above. export const revokePermissions = (chain: Chain): Permission[] => { let base: Permission[]; if (chain === "bscmainnet") { - base = BNB_ROWS.filter(r => r.action === "revoke" || r.action === "swap" || r.action === "stale").map(r => ({ + base = BNB_ROWS.filter(r => r.action === "revoke" || r.action === "swap").map(r => ({ contractAddress: r.target, functionSig: r.signature, account: BNB_CRITICAL, From a2350b5c2ac80ff770ec9fbaa013f86cf0030766 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 15 Jul 2026 02:47:27 +0530 Subject: [PATCH 08/11] refactor: rename permission-list builders to buildGrant/buildRevokePermissions --- simulations/vip-665/bscmainnet.ts | 12 ++++++------ simulations/vip-665/utils/remoteSim.ts | 4 ++-- vips/vip-665/bscmainnet.ts | 8 ++++---- vips/vip-665/scripts/seedAggregators.ts | 6 +++--- vips/vip-665/utils/commands.ts | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts index ed1d3518d..07789c49e 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-665/bscmainnet.ts @@ -13,9 +13,9 @@ import { REDUNDANT_REVOKES, STALE_ROWS } from "../../vips/vip-665/data/cleanup"; import { AGGREGATOR, BNB_LEGACY_WILDCARD_REVOKES, - grantPermissions, + buildGrantPermissions, legacyWildcardRole, - revokePermissions, + buildRevokePermissions, } from "../../vips/vip-665/utils/commands"; import { seedAggregator } from "../../vips/vip-665/utils/seed"; import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; @@ -53,8 +53,8 @@ forking(FORK_BLOCK, async () => { await seedAggregator( signer, AGGREGATOR.bscmainnet, - grantPermissions("bscmainnet"), - revokePermissions("bscmainnet"), + buildGrantPermissions("bscmainnet"), + buildRevokePermissions("bscmainnet"), ); }); @@ -189,8 +189,8 @@ forking(FORK_BLOCK, async () => { expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; }); - it("behavioral: the CriticalTimelock can no longer call any revoked or stale function", async () => { - for (const row of [...REVOKE, ...STALE]) + it("behavioral: the CriticalTimelock can no longer call any revoked function", async () => { + for (const row of REVOKE) expect( await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), `crit still allowed ${row.signature}@${row.target}`, diff --git a/simulations/vip-665/utils/remoteSim.ts b/simulations/vip-665/utils/remoteSim.ts index 0481aba22..aad621fb0 100644 --- a/simulations/vip-665/utils/remoteSim.ts +++ b/simulations/vip-665/utils/remoteSim.ts @@ -10,7 +10,7 @@ import vip665, { EXPECTED_ROLE_EVENTS } from "../../../vips/vip-665/bscmainnet"; import { remoteRowsFor } from "../../../vips/vip-665/data/actionPlan"; import { REMOTE_ACM, SYNC_CASH_MARKETS, ZERO } from "../../../vips/vip-665/data/addresses"; import { REDUNDANT_REVOKES, SYNC_CASH_SIG } from "../../../vips/vip-665/data/cleanup"; -import { AGGREGATOR, Chain, grantPermissions, revokePermissions } from "../../../vips/vip-665/utils/commands"; +import { AGGREGATOR, Chain, buildGrantPermissions, buildRevokePermissions } from "../../../vips/vip-665/utils/commands"; import { seedAggregator } from "../../../vips/vip-665/utils/seed"; import ACCESS_CONTROL_MANAGER_ABI from "../abi/AccessControlManager.json"; @@ -33,7 +33,7 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { forking(forkBlock, async () => { before(async () => { const signer = await initMainnetUser(NETWORK_ADDRESSES[chain].NORMAL_TIMELOCK, ethers.utils.parseEther("2")); - await seedAggregator(signer, AGGREGATOR[chain], grantPermissions(chain), revokePermissions(chain)); + await seedAggregator(signer, AGGREGATOR[chain], buildGrantPermissions(chain), buildRevokePermissions(chain)); }); const rows = remoteRowsFor(chain); diff --git a/vips/vip-665/bscmainnet.ts b/vips/vip-665/bscmainnet.ts index 17c727816..f9aeb37df 100644 --- a/vips/vip-665/bscmainnet.ts +++ b/vips/vip-665/bscmainnet.ts @@ -9,9 +9,9 @@ import { GRANT_INDEX, REVOKE_INDEX, acmOf, - grantPermissions, + buildGrantPermissions, legacyWildcardCommands, - revokePermissions, + buildRevokePermissions, } from "./utils/commands"; // Expected RoleGranted / RoleRevoked counts per chain, asserted by the simulations after execution. @@ -37,14 +37,14 @@ const aggregatorCommands = (chain: Chain): Command[] => { const commands: Command[] = [ { target: acm, signature: "grantRole(bytes32,address)", params: [DEFAULT_ADMIN_ROLE, agg], ...route }, ]; - if (grantPermissions(chain).length > 0) + if (buildGrantPermissions(chain).length > 0) commands.push({ target: agg, signature: "executeGrantPermissions(uint256)", params: [GRANT_INDEX[chain]], ...route, }); - if (revokePermissions(chain).length > 0) + if (buildRevokePermissions(chain).length > 0) commands.push({ target: agg, signature: "executeRevokePermissions(uint256)", diff --git a/vips/vip-665/scripts/seedAggregators.ts b/vips/vip-665/scripts/seedAggregators.ts index 9667b09f0..73a7a1231 100644 --- a/vips/vip-665/scripts/seedAggregators.ts +++ b/vips/vip-665/scripts/seedAggregators.ts @@ -10,7 +10,7 @@ */ import { ethers, network } from "hardhat"; -import { AGGREGATOR, Chain, grantPermissions, revokePermissions } from "../utils/commands"; +import { AGGREGATOR, Chain, buildGrantPermissions, buildRevokePermissions } from "../utils/commands"; import { seedAggregator } from "../utils/seed"; async function main() { @@ -18,8 +18,8 @@ async function main() { if (!(chain in AGGREGATOR)) throw new Error(`VIP-665 has no aggregator for network "${chain}"`); const [signer] = await ethers.getSigners(); - const grants = grantPermissions(chain); - const revokes = revokePermissions(chain); + const grants = buildGrantPermissions(chain); + const revokes = buildRevokePermissions(chain); console.log(`Chain ${chain} — aggregator ${AGGREGATOR[chain]}`); console.log(` seeding ${grants.length} grant(s) and ${revokes.length} revoke(s) from ${await signer.getAddress()}`); diff --git a/vips/vip-665/utils/commands.ts b/vips/vip-665/utils/commands.ts index 36d97118b..cc09571c9 100644 --- a/vips/vip-665/utils/commands.ts +++ b/vips/vip-665/utils/commands.ts @@ -72,7 +72,7 @@ export interface Permission { // Permissions the aggregator grants on a chain. On BNB: swap → move a function to a Guardian, grant → add a // Guardian alongside Critical. On remotes: the single wildcard syncCash() grant to NormalTimelock; remotes // have no Guardian swaps/grants. -export const grantPermissions = (chain: Chain): Permission[] => { +export const buildGrantPermissions = (chain: Chain): Permission[] => { if (chain !== "bscmainnet") return syncCashGrants(chain); return BNB_ROWS.filter(r => r.action === "swap" || r.action === "grant").map(r => ({ contractAddress: r.target, @@ -98,7 +98,7 @@ const redundantRevokes = (chain: Chain): Permission[] => // dangling-grant cleanup); on remotes every remote row from that chain's Critical, plus the per-market // syncCash() grants from NormalTimelock (replaced by the wildcard grant). Finally the redundant // (wildcard-shadowed) target-specific grants, de-duplicated against everything above. -export const revokePermissions = (chain: Chain): Permission[] => { +export const buildRevokePermissions = (chain: Chain): Permission[] => { let base: Permission[]; if (chain === "bscmainnet") { base = BNB_ROWS.filter(r => r.action === "revoke" || r.action === "swap").map(r => ({ From bc0a7105c92bd06bc266dbef0724bf26965b65bf Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 15 Jul 2026 02:56:55 +0530 Subject: [PATCH 09/11] refactor: extract no-change permission rows into noChangeRows.ts --- simulations/vip-665/bscmainnet.ts | 74 +- vips/vip-665/data/actionPlan.ts | 1973 ++--------------------------- vips/vip-665/data/noChangeRows.ts | 1682 ++++++++++++++++++++++++ 3 files changed, 1837 insertions(+), 1892 deletions(-) create mode 100644 vips/vip-665/data/noChangeRows.ts diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts index 07789c49e..c134a864a 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-665/bscmainnet.ts @@ -14,8 +14,8 @@ import { AGGREGATOR, BNB_LEGACY_WILDCARD_REVOKES, buildGrantPermissions, - legacyWildcardRole, buildRevokePermissions, + legacyWildcardRole, } from "../../vips/vip-665/utils/commands"; import { seedAggregator } from "../../vips/vip-665/utils/seed"; import ACM_COMMANDS_AGGREGATOR_ABI from "./abi/ACMCommandsAggregator.json"; @@ -87,21 +87,6 @@ forking(FORK_BLOCK, async () => { } }); - it("no-change: Critical holds each one and Guardian flags match the plan", async () => { - for (const row of NO_CHANGE) { - expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.equal(row.critical); - expect(await holds(BNB_GUARDIANS.guardian1, row), `pre g1 ${row.signature}@${row.target}`).to.equal( - row.guardian1, - ); - expect(await holds(BNB_GUARDIANS.guardian2, row), `pre g2 ${row.signature}@${row.target}`).to.equal( - row.guardian2, - ); - expect(await holds(BNB_GUARDIANS.guardian3, row), `pre g3 ${row.signature}@${row.target}`).to.equal( - row.guardian3, - ); - } - }); - it("revoke: Critical currently holds every permission to be revoked", async () => { for (const row of REVOKE) { expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.be.true; @@ -157,33 +142,6 @@ forking(FORK_BLOCK, async () => { }); describe("VIP-665 post-execution permissions (bscmainnet)", () => { - // No-change = the capability is untouched. Every holder the plan lists can still call the function — either - // through its own grant, or (for grants the redundant cleanup drops) through the surviving wildcard. - it("no-change: Critical and every listed Guardian can still call the function", async () => { - for (const row of NO_CHANGE) { - if (row.critical) - expect( - await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), - `no-change critical ${row.signature}@${row.target}`, - ).to.be.true; - if (row.guardian1) - expect( - await acm().isAllowedToCall(BNB_GUARDIANS.guardian1, row.signature, { from: row.target }), - `no-change g1 ${row.signature}@${row.target}`, - ).to.be.true; - if (row.guardian2) - expect( - await acm().isAllowedToCall(BNB_GUARDIANS.guardian2, row.signature, { from: row.target }), - `no-change g2 ${row.signature}@${row.target}`, - ).to.be.true; - if (row.guardian3) - expect( - await acm().isAllowedToCall(BNB_GUARDIANS.guardian3, row.signature, { from: row.target }), - `no-change g3 ${row.signature}@${row.target}`, - ).to.be.true; - } - }); - it("revoke: the CriticalTimelock lost each target-specific grant", async () => { for (const row of REVOKE) expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; @@ -272,4 +230,34 @@ forking(FORK_BLOCK, async () => { await expect(asCritical._setForcedLiquidation(vUSDT, true)).to.be.reverted; }); }); + + // "No change" rows carry no action and were validated at extraction (see data/noChangeRows.ts). This block + // re-confirms post-execution that Critical and every listed Guardian still retain each capability — directly + // or via a surviving wildcard — so the VIP touched nothing it shouldn't have. + describe("VIP-665 no-change permissions retained (bscmainnet)", () => { + it("Critical and every listed Guardian can still call each untouched function", async () => { + for (const row of NO_CHANGE) { + if (row.critical) + expect( + await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), + `no-change critical ${row.signature}@${row.target}`, + ).to.be.true; + if (row.guardian1) + expect( + await acm().isAllowedToCall(BNB_GUARDIANS.guardian1, row.signature, { from: row.target }), + `no-change g1 ${row.signature}@${row.target}`, + ).to.be.true; + if (row.guardian2) + expect( + await acm().isAllowedToCall(BNB_GUARDIANS.guardian2, row.signature, { from: row.target }), + `no-change g2 ${row.signature}@${row.target}`, + ).to.be.true; + if (row.guardian3) + expect( + await acm().isAllowedToCall(BNB_GUARDIANS.guardian3, row.signature, { from: row.target }), + `no-change g3 ${row.signature}@${row.target}`, + ).to.be.true; + } + }); + }); }); diff --git a/vips/vip-665/data/actionPlan.ts b/vips/vip-665/data/actionPlan.ts index ddfcec9a1..769ae749b 100644 --- a/vips/vip-665/data/actionPlan.ts +++ b/vips/vip-665/data/actionPlan.ts @@ -11,6 +11,7 @@ import { XVS_BRIDGE_ADMIN, ZERO, } from "./addresses"; +import { BNB_NO_CHANGE_ROWS } from "./noChangeRows"; // =================================================================================================== // BNB Chain @@ -19,7 +20,7 @@ export type Action = "none" | "revoke" | "swap" | "grant"; // signature = ACM-registered function signature; target = contract it is scoped to; // critical/guardian1/guardian2/guardian3 = current holders; action = final action; // grantTo = destination guardian for swap/grant actions. -export const BNB_ROWS: { +export interface BnbRow { signature: string; target: string; critical: boolean; @@ -28,332 +29,243 @@ export const BNB_ROWS: { guardian3: boolean; action: Action; grantTo?: "guardian1" | "guardian2" | "guardian3"; -}[] = [ - // ==================== venus-protocol ==================== - // ---- Liquidator ---- +} + +// Rows carrying an actual change (revoke / swap / grant) — this is the review surface. The untouched +// "No change" inventory lives in noChangeRows.ts and is read only by the simulation's assertions. +export const BNB_ACTION_ROWS: BnbRow[] = [ { - signature: "addToAllowlist(address,address)", - target: CONTRACTS.Liquidator, + signature: "setCollateralFactor(address,uint256,uint256)", + target: CONTRACTS.Unitroller, critical: true, - guardian1: false, - guardian2: true, + guardian1: true, + guardian2: false, guardian3: false, - action: "none", + action: "revoke", }, { - signature: "removeFromAllowlist(address,address)", - target: CONTRACTS.Liquidator, + signature: "setCollateralFactor(uint96,address,uint256,uint256)", + target: CONTRACTS.Unitroller, critical: true, - guardian1: false, - guardian2: true, + guardian1: true, + guardian2: false, guardian3: false, - action: "none", + action: "revoke", }, { - signature: "restrictLiquidation(address)", - target: CONTRACTS.Liquidator, + signature: "setWhiteListFlashLoanAccount(address,bool)", + target: CONTRACTS.Unitroller, critical: true, guardian1: false, guardian2: true, guardian3: false, - action: "none", + action: "revoke", }, { - signature: "setTreasuryPercent(uint256)", - target: CONTRACTS.Liquidator, + signature: "_setMarketBorrowCaps(address[],uint256[])", + target: CONTRACTS.Unitroller, critical: true, - guardian1: false, + guardian1: true, guardian2: false, guardian3: false, - action: "none", - }, - { - signature: "unrestrictLiquidation(address)", - target: CONTRACTS.Liquidator, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", + action: "revoke", }, { - signature: "pauseForceVAILiquidate()", - target: CONTRACTS.Liquidator, + signature: "_setMarketSupplyCaps(address[],uint256[])", + target: CONTRACTS.Unitroller, critical: true, - guardian1: false, - guardian2: true, + guardian1: true, + guardian2: false, guardian3: false, - action: "none", + action: "revoke", }, { - signature: "resumeForceVAILiquidate()", - target: CONTRACTS.Liquidator, + signature: "setIsBorrowAllowed(uint96,address,bool)", + target: CONTRACTS.Unitroller, critical: true, guardian1: false, guardian2: true, guardian3: false, - action: "none", - }, - // ---- PegStability_USDT ---- - { - signature: "setVAIMintCap(uint256)", - target: CONTRACTS.PegStability_USDT, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", + action: "revoke", }, { - signature: "setFeeIn(uint256)", - target: CONTRACTS.PegStability_USDT, + signature: "_setForcedLiquidation(address,bool)", + target: CONTRACTS.Unitroller, critical: true, guardian1: false, guardian2: false, guardian3: false, - action: "none", + action: "swap", + grantTo: "guardian1", }, { - signature: "setFeeOut(uint256)", - target: CONTRACTS.PegStability_USDT, + signature: "_setForcedLiquidationForUser(address,address,bool)", + target: CONTRACTS.Unitroller, critical: true, guardian1: false, guardian2: false, guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.PegStability_USDT, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", + action: "swap", + grantTo: "guardian1", }, { signature: "resume()", - target: CONTRACTS.PegStability_USDT, + target: CONTRACTS.XVSVaultProxy, critical: true, guardian1: false, guardian2: true, guardian3: false, - action: "none", - }, - // ---- Prime ---- - { - signature: "addMarket(address,address,uint256,uint256)", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", + action: "revoke", }, { - signature: "addMarket(address,uint256,uint256)", - target: CONTRACTS.Prime, + signature: "setDirectPrice(address,uint256)", + target: CONTRACTS.ChainlinkOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, { - signature: "burn(address)", - target: CONTRACTS.Prime, + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.ChainlinkOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, { - signature: "issue(bool,address[])", - target: CONTRACTS.Prime, + signature: "setUnderlyingPrice(address,uint256)", + target: CONTRACTS.ChainlinkOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, { - signature: "updateMultipliers(address,uint256,uint256)", - target: CONTRACTS.Prime, + signature: "setThresholds(address,uint256,uint256)", + target: CONTRACTS.DeviationBoundedOracle, critical: true, guardian1: false, guardian2: false, guardian3: false, - action: "none", + action: "grant", + grantTo: "guardian1", }, { - signature: "setLimit(uint256,uint256)", - target: CONTRACTS.Prime, + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.PythOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, { - signature: "setMaxLoopsLimit(uint256)", - target: CONTRACTS.Prime, + signature: "setDirectPrice(address,uint256)", + target: CONTRACTS.RedStoneOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, { - signature: "setStakedAt(address[],uint256[])", - target: CONTRACTS.Prime, + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.RedStoneOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, { - signature: "updateAlpha(uint128,uint128)", - target: CONTRACTS.Prime, + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.ResilientOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "togglePause()", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, - // ---- PrimeLiquidityProvider ---- { - signature: "setMaxLoopsLimit(uint256)", - target: CONTRACTS.PrimeLiquidityProvider, + signature: "setDirectPrice(address,uint256)", + target: CONTRACTS.USDTChainlinkOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, { - signature: "setMaxTokensDistributionSpeed(address[],uint256[])", - target: CONTRACTS.PrimeLiquidityProvider, + signature: "setTokenConfig(TokenConfig)", + target: CONTRACTS.USDTChainlinkOracle, critical: true, guardian1: false, guardian2: false, - guardian3: false, - action: "none", + guardian3: true, + action: "revoke", }, { - signature: "setTokensDistributionSpeed(address[],uint256[])", - target: CONTRACTS.PrimeLiquidityProvider, + signature: "addOrUpdateDistributionConfigs(DistributionConfig[])", + target: CONTRACTS.ProtocolShareReserve, critical: true, guardian1: false, guardian2: false, guardian3: false, - action: "none", - }, - { - signature: "pauseFundsTransfer()", - target: CONTRACTS.PrimeLiquidityProvider, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", + action: "revoke", }, { - signature: "resumeFundsTransfer()", - target: CONTRACTS.PrimeLiquidityProvider, + signature: "executePositionAccountCall(address,address[],bytes[])", + target: CONTRACTS.RelativePositionManager, critical: true, guardian1: false, guardian2: true, guardian3: false, - action: "none", + action: "revoke", }, - // ---- PrimeV2 ---- { - signature: "pause()", - target: CONTRACTS.PrimeV2, + signature: "setDirectPrice(address,uint256)", + target: CONTRACTS.SentinelOracle, critical: true, guardian1: false, guardian2: true, guardian3: false, - action: "none", + action: "revoke", }, { - signature: "unpause()", - target: CONTRACTS.PrimeV2, + signature: "setTokenOracleConfig(address,address)", + target: CONTRACTS.SentinelOracle, critical: true, guardian1: false, guardian2: true, guardian3: false, - action: "none", - }, - // ---- Unitroller (core pool Comptroller) ---- - { - signature: "addPoolMarkets(uint96[],address[])", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", + action: "revoke", }, { - signature: "createPool(string)", - target: CONTRACTS.Unitroller, + signature: "setWhitelist(address,bool)", + target: CONTRACTS.XVSBridgeAdmin, critical: true, guardian1: false, guardian2: false, guardian3: false, - action: "none", + action: "swap", + grantTo: "guardian1", }, { - signature: "seizeVenus(address[],address)", - target: CONTRACTS.Unitroller, + signature: "setMaxDailyLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, critical: true, guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "seizeVenus(address[],address,address[])", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setCollateralFactor(address,uint256,uint256)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "setCollateralFactor(uint96,address,uint256,uint256)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, + guardian2: true, guardian3: false, action: "revoke", }, { - signature: "setWhiteListFlashLoanAccount(address,bool)", - target: CONTRACTS.Unitroller, + signature: "setMaxDailyReceiveLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, critical: true, guardian1: false, guardian2: true, @@ -361,53 +273,26 @@ export const BNB_ROWS: { action: "revoke", }, { - signature: "_setMarketBorrowCaps(address[],uint256[])", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "_setMarketSupplyCaps(address[],uint256[])", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "removePoolMarket(uint96,address)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setAllowCorePoolFallback(uint96,bool)", - target: CONTRACTS.Unitroller, + signature: "setMaxSingleReceiveTransactionLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, critical: true, guardian1: false, - guardian2: false, + guardian2: true, guardian3: false, - action: "none", + action: "revoke", }, { - signature: "setFlashLoanPaused(bool)", - target: CONTRACTS.Unitroller, + signature: "setMaxSingleTransactionLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, critical: true, guardian1: false, guardian2: true, guardian3: false, - action: "none", + action: "revoke", }, { - signature: "setIsBorrowAllowed(uint96,address,bool)", - target: CONTRACTS.Unitroller, + signature: "unpause()", + target: CONTRACTS.XVSBridgeAdmin, critical: true, guardian1: false, guardian2: true, @@ -415,1640 +300,30 @@ export const BNB_ROWS: { action: "revoke", }, { - signature: "setPoolActive(uint96,bool)", - target: CONTRACTS.Unitroller, + signature: "setLiquidationThreshold(address,uint256)", + target: CONTRACTS.InstitutionalVaultControllerProxy, critical: true, guardian1: false, guardian2: false, guardian3: false, - action: "none", + action: "swap", + grantTo: "guardian1", }, { - signature: "setPoolLabel(uint96,string)", - target: CONTRACTS.Unitroller, + signature: "sweep(address,address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, critical: true, - guardian1: false, + guardian1: true, guardian2: false, guardian3: false, - action: "none", - }, - { - signature: "unlistMarket(address)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "_setActionsPaused(address[],uint8[],bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "_setForcedLiquidation(address,bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "swap", - grantTo: "guardian1", - }, - { - signature: "_setForcedLiquidationForUser(address,address,bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "swap", - grantTo: "guardian1", - }, - { - signature: "_setProtocolPaused(bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- VaiUnitroller ---- - { - signature: "setBaseRate(uint256)", - target: CONTRACTS.VaiUnitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setFloatRate(uint256)", - target: CONTRACTS.VaiUnitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMintCap(uint256)", - target: CONTRACTS.VaiUnitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "toggleOnlyPrimeHolderMint()", - target: CONTRACTS.VaiUnitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- VAIVaultProxy ---- - { - signature: "pause()", - target: CONTRACTS.VAIVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resume()", - target: CONTRACTS.VAIVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- VBNBAdmin ---- - { - signature: "setInterestRateModel(address)", - target: CONTRACTS.VBNBAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- VRTVaultProxy ---- - { - signature: "pause()", - target: CONTRACTS.VRTVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resume()", - target: CONTRACTS.VRTVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- XVSVaultProxy ---- - { - signature: "setRewardAmountPerBlockOrSecond(address,uint256)", - target: CONTRACTS.XVSVaultProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.XVSVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resume()", - target: CONTRACTS.XVSVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - // ==================== oracle ==================== - // ---- BinanceOracle ---- - { - signature: "setMaxStalePeriod(string,uint256)", - target: CONTRACTS.BinanceOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "none", - }, - { - signature: "setSymbolOverride(string,string)", - target: CONTRACTS.BinanceOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "none", - }, - // ---- ChainlinkOracle ---- - { - signature: "setDirectPrice(address,uint256)", - target: CONTRACTS.ChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.ChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setUnderlyingPrice(address,uint256)", - target: CONTRACTS.ChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - // ---- DeviationBoundedOracle ---- - { - signature: "setThresholds(address,uint256,uint256)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "grant", - grantTo: "guardian1", - }, - { - signature: "setTokenConfig((address,uint64,uint256,uint256,bool,bool))", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setTokenConfigs((address,uint64,uint256,uint256,bool,bool)[])", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateMaxPrice(address,uint128)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "updateMinPrice(address,uint128)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setAssetBoundedPricingEnabled(address,bool)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setCachingEnabled(address,bool)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setCooldownPeriod(address,uint64)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "syncPriceBoundsAndProtections((address,uint8,uint256)[])", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "exitProtectionMode(address)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- PythOracle ---- - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.PythOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - // ---- RedStoneOracle ---- - { - signature: "setDirectPrice(address,uint256)", - target: CONTRACTS.RedStoneOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.RedStoneOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - // ---- ResilientOracle ---- - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.ResilientOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "pause()", - target: CONTRACTS.ResilientOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "none", - }, - { - signature: "unpause()", - target: CONTRACTS.ResilientOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "none", - }, - // ---- USDTChainlinkOracle ---- - { - signature: "setDirectPrice(address,uint256)", - target: CONTRACTS.USDTChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.USDTChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - // ==================== protocol-reserve ==================== - // ---- BTCBPrimeConverter ---- - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.BTCBPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.BTCBPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.BTCBPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.BTCBPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- ConverterNetwork ---- - { - signature: "addTokenConverter(address)", - target: CONTRACTS.ConverterNetwork, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removeTokenConverter(address)", - target: CONTRACTS.ConverterNetwork, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- ETHPrimeConverter ---- - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.ETHPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.ETHPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.ETHPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.ETHPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- ProtocolShareReserve ---- - { - signature: "addOrUpdateDistributionConfigs(DistributionConfig[])", - target: CONTRACTS.ProtocolShareReserve, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "removeDistributionConfig(Schema,address)", - target: CONTRACTS.ProtocolShareReserve, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- RiskFundConverter ---- - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setPoolsAssetsDirectTransfer(address[],address[][],bool[][])", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- RiskFundV2 ---- - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.RiskFundV2, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- USDCPrimeConverter ---- - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.USDCPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.USDCPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.USDCPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.USDCPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- USDTPrimeConverter ---- - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.USDTPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // setMinAmountToConvert is not revoked here: the grant looks dangling but the contract/function is live, - // so Critical keeps it (No change). The stale grant, if any, is handled explicitly in a separate cleanup. - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.USDTPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.USDTPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.USDTPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- WBNBBurnConverter ---- - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.WBNBBurnConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.WBNBBurnConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.WBNBBurnConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.WBNBBurnConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- XVSVaultConverter ---- - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.XVSVaultConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.XVSVaultConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.XVSVaultConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.XVSVaultConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- XVSVaultTreasury ---- - { - signature: "fundXVSVault(uint256)", - target: CONTRACTS.XVSVaultTreasury, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ==================== isolated-pools ==================== - // ---- Comptroller_DeFi ---- - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_DeFi, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- Comptroller_GameFi ---- - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_GameFi, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- Comptroller_LiquidStakedBNB ---- - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_LiquidStakedBNB, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- Comptroller_Stablecoins ---- - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_Stablecoins, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- Comptroller_Tron ---- - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_Tron, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- Shortfall ---- - { - signature: "updateIncentiveBps(uint256)", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateMinimumPoolBadDebt(uint256)", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateNextBidderBlockLimit(uint256)", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateWaitForFirstBidder(uint256)", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseAuctions()", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeAuctions()", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ==================== venus-periphery ==================== - // ---- DeviationSentinel ---- - { - signature: "setTokenConfig(address,(uint8,bool))", - target: CONTRACTS.DeviationSentinel, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resetMarketState(address)", - target: CONTRACTS.DeviationSentinel, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setTokenMonitoringEnabled(address,bool)", - target: CONTRACTS.DeviationSentinel, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setTrustedKeeper(address,bool)", - target: CONTRACTS.DeviationSentinel, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- EBrake ---- - { - signature: "decreaseCF(address,uint256)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "decreaseCF(address,uint96,uint256)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "revokeFlashLoanAccess(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMarketBorrowCaps(address[],uint256[])", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMarketSupplyCaps(address[],uint256[])", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "disablePoolBorrow(uint96,address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseActions(address[],uint8[])", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseBorrow(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseFlashLoan()", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseRedeem(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseSupply(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseTransfer(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resetBorrowCapSnapshot(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resetCFSnapshot(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resetSupplyCapSnapshot(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- Executor ---- - { - signature: "setMarketConfig(address,(uint256,uint256,bool))", - target: CONTRACTS.Executor, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- PancakeSwapOracle ---- - { - signature: "setPoolConfig(address,address)", - target: CONTRACTS.PancakeSwapOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- PendlePTVaultAdapter ---- - { - signature: "pause()", - target: CONTRACTS.PendlePTVaultAdapter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "unpause()", - target: CONTRACTS.PendlePTVaultAdapter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- RelativePositionManager ---- - { - signature: "executePositionAccountCall(address,address[],bytes[])", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "addDSAVToken(address)", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setDSAVTokenActive(uint8,bool)", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setProportionalCloseTolerance(uint256)", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "completePause()", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "completeUnpause()", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "partialPause()", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "partialUnpause()", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- SentinelOracle ---- - { - signature: "setDirectPrice(address,uint256)", - target: CONTRACTS.SentinelOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setTokenOracleConfig(address,address)", - target: CONTRACTS.SentinelOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - // ---- UniswapOracle ---- - { - signature: "setPoolConfig(address,address)", - target: CONTRACTS.UniswapOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ==================== governance-contracts ==================== - // ---- AuxiliaryCommandsAggregator ---- - { - signature: "addAuthorizedBatchers(address[])", - target: CONTRACTS.AuxiliaryCommandsAggregator, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "executeBatch(uint256)", - target: CONTRACTS.AuxiliaryCommandsAggregator, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removeAuthorizedBatchers(address[])", - target: CONTRACTS.AuxiliaryCommandsAggregator, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- OmnichainProposalSender ---- - { - signature: "execute(uint16,bytes,bytes,address)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "retryExecute(uint256,uint16,bytes,bytes,address,uint256)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setConfig(uint16,uint16,uint256,bytes)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removeTrustedRemote(uint16)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMaxDailyLimit(uint16,uint256)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setSendVersion(uint16)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "unpause()", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- RiskOracle ---- - { - signature: "removeAuthorizedSender(address)", - target: CONTRACTS.RiskOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setUpdateTypeActive(string,bool)", - target: CONTRACTS.RiskOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ---- RiskStewardReceiver ---- - { - signature: "setWhitelistedExecutor(address,bool)", - target: CONTRACTS.RiskStewardReceiver, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setConfigActive(string,bool)", - target: CONTRACTS.RiskStewardReceiver, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setPaused(bool)", - target: CONTRACTS.RiskStewardReceiver, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - // ==================== token-bridge ==================== - // ---- XVSBridgeAdmin ---- - { - signature: "setConfig(uint16,uint16,uint256,bytes)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setWhitelist(address,bool)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "swap", - grantTo: "guardian1", - }, - { - signature: "dropFailedMessage(uint16,bytes,uint64)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "forceResumeReceive(uint16,bytes)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removeTrustedRemote(uint16)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMaxDailyLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setMaxDailyReceiveLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setMaxSingleReceiveTransactionLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setMaxSingleTransactionLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setMinDstGas(uint16,uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setPayloadSizeLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setReceiveVersion(uint16)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setSendVersion(uint16)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateSendAndCallEnabled(bool)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "unpause()", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - // ==================== fixed-rate-vaults ==================== - // ---- InstitutionalVaultControllerProxy ---- - { - signature: "createVault(VaultConfig,InstitutionalConfig,RiskConfig,string,string,string)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setLiquidationIncentive(address,uint256)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setLiquidationThreshold(address,uint256)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "swap", - grantTo: "guardian1", - }, - { - signature: "setVaultImplementation(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "sweep(address,address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "approvePositionTransfer(address,address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "cancelVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "closeVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "openVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "revokePositionTransfer(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setInstitutionName(address,string)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setInstitutionNameOverride(address,string)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setLatePenaltyRate(address,uint256)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "completePauseVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "partialPauseVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "unpauseVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - // ---- LiquidationAdapterProxy ---- - { - signature: "setCloseFactor(uint256)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "sweepProtocolShareToReserve(address)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setLiquidatorWhitelist(address,bool)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setProtocolLiquidationShare(uint256)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setSettlerWhitelist(address,bool)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", + action: "revoke", }, ]; +// Full row set: actions + untouched inventory. commands.ts builders filter by action; the simulation +// groups by action into its category buckets. +export const BNB_ROWS: BnbRow[] = [...BNB_ACTION_ROWS, ...BNB_NO_CHANGE_ROWS]; + // setCollateralFactor on the isolated-pools wildcard target is revoked from the CriticalTimelock via a // direct ACM.revokeRole on the legacy BNB ACM (the aggregator cannot clear wildcard grants there — see // legacyWildcardRole in utils/commands.ts). diff --git a/vips/vip-665/data/noChangeRows.ts b/vips/vip-665/data/noChangeRows.ts new file mode 100644 index 000000000..75cdc2ad5 --- /dev/null +++ b/vips/vip-665/data/noChangeRows.ts @@ -0,0 +1,1682 @@ +// VIP-665 — BNB Chain permissions the plan leaves untouched ("No change"), extracted from actionPlan.ts +// so the action plan shows only real changes. These rows carry no action and generate no commands; the +// simulation reads them to assert Critical and the listed Guardians retain each capability after execution. +import type { BnbRow } from "./actionPlan"; +import { BNB_CONTRACTS as CONTRACTS } from "./addresses"; + +export const BNB_NO_CHANGE_ROWS: BnbRow[] = [ + { + signature: "addToAllowlist(address,address)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "removeFromAllowlist(address,address)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "restrictLiquidation(address)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTreasuryPercent(uint256)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "unrestrictLiquidation(address)", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseForceVAILiquidate()", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeForceVAILiquidate()", + target: CONTRACTS.Liquidator, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setVAIMintCap(uint256)", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setFeeIn(uint256)", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setFeeOut(uint256)", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resume()", + target: CONTRACTS.PegStability_USDT, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addMarket(address,address,uint256,uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "addMarket(address,uint256,uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "burn(address)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "issue(bool,address[])", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateMultipliers(address,uint256,uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLimit(uint256,uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMaxLoopsLimit(uint256)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setStakedAt(address[],uint256[])", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateAlpha(uint128,uint128)", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "togglePause()", + target: CONTRACTS.Prime, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMaxLoopsLimit(uint256)", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMaxTokensDistributionSpeed(address[],uint256[])", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setTokensDistributionSpeed(address[],uint256[])", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseFundsTransfer()", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeFundsTransfer()", + target: CONTRACTS.PrimeLiquidityProvider, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.PrimeV2, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.PrimeV2, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addPoolMarkets(uint96[],address[])", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "createPool(string)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "seizeVenus(address[],address)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "seizeVenus(address[],address,address[])", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removePoolMarket(uint96,address)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setAllowCorePoolFallback(uint96,bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setFlashLoanPaused(bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setPoolActive(uint96,bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setPoolLabel(uint96,string)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "unlistMarket(address)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "_setActionsPaused(address[],uint8[],bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "_setProtocolPaused(bool)", + target: CONTRACTS.Unitroller, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setBaseRate(uint256)", + target: CONTRACTS.VaiUnitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setFloatRate(uint256)", + target: CONTRACTS.VaiUnitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMintCap(uint256)", + target: CONTRACTS.VaiUnitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "toggleOnlyPrimeHolderMint()", + target: CONTRACTS.VaiUnitroller, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.VAIVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resume()", + target: CONTRACTS.VAIVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setInterestRateModel(address)", + target: CONTRACTS.VBNBAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.VRTVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resume()", + target: CONTRACTS.VRTVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setRewardAmountPerBlockOrSecond(address,uint256)", + target: CONTRACTS.XVSVaultProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.XVSVaultProxy, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMaxStalePeriod(string,uint256)", + target: CONTRACTS.BinanceOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "none", + }, + { + signature: "setSymbolOverride(string,string)", + target: CONTRACTS.BinanceOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "none", + }, + { + signature: "setTokenConfig((address,uint64,uint256,uint256,bool,bool))", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setTokenConfigs((address,uint64,uint256,uint256,bool,bool)[])", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateMaxPrice(address,uint128)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "updateMinPrice(address,uint128)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setAssetBoundedPricingEnabled(address,bool)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setCachingEnabled(address,bool)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setCooldownPeriod(address,uint64)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "syncPriceBoundsAndProtections((address,uint8,uint256)[])", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "exitProtectionMode(address)", + target: CONTRACTS.DeviationBoundedOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.ResilientOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.ResilientOracle, + critical: true, + guardian1: false, + guardian2: false, + guardian3: true, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.BTCBPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.BTCBPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.BTCBPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.BTCBPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addTokenConverter(address)", + target: CONTRACTS.ConverterNetwork, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removeTokenConverter(address)", + target: CONTRACTS.ConverterNetwork, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.ETHPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.ETHPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.ETHPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.ETHPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "removeDistributionConfig(Schema,address)", + target: CONTRACTS.ProtocolShareReserve, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setPoolsAssetsDirectTransfer(address[],address[][],bool[][])", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.RiskFundConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.RiskFundV2, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.USDCPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.USDCPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.USDCPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.USDCPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.USDTPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.USDTPrimeConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.USDTPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.USDTPrimeConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.WBNBBurnConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.WBNBBurnConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.WBNBBurnConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.WBNBBurnConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConversionConfig(address,address,ConversionConfig)", + target: CONTRACTS.XVSVaultConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinAmountToConvert(uint256)", + target: CONTRACTS.XVSVaultConverter, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseConversion()", + target: CONTRACTS.XVSVaultConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeConversion()", + target: CONTRACTS.XVSVaultConverter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "fundXVSVault(uint256)", + target: CONTRACTS.XVSVaultTreasury, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_DeFi, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_GameFi, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_LiquidStakedBNB, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_Stablecoins, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setForcedLiquidation(address,bool)", + target: CONTRACTS.Comptroller_Tron, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateIncentiveBps(uint256)", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateMinimumPoolBadDebt(uint256)", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateNextBidderBlockLimit(uint256)", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateWaitForFirstBidder(uint256)", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pauseAuctions()", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resumeAuctions()", + target: CONTRACTS.Shortfall, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTokenConfig(address,(uint8,bool))", + target: CONTRACTS.DeviationSentinel, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resetMarketState(address)", + target: CONTRACTS.DeviationSentinel, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTokenMonitoringEnabled(address,bool)", + target: CONTRACTS.DeviationSentinel, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setTrustedKeeper(address,bool)", + target: CONTRACTS.DeviationSentinel, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "decreaseCF(address,uint256)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "decreaseCF(address,uint96,uint256)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "revokeFlashLoanAccess(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMarketBorrowCaps(address[],uint256[])", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMarketSupplyCaps(address[],uint256[])", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "disablePoolBorrow(uint96,address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseActions(address[],uint8[])", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseBorrow(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseFlashLoan()", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseRedeem(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseSupply(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pauseTransfer(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resetBorrowCapSnapshot(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resetCFSnapshot(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "resetSupplyCapSnapshot(address)", + target: CONTRACTS.EBrake, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMarketConfig(address,(uint256,uint256,bool))", + target: CONTRACTS.Executor, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setPoolConfig(address,address)", + target: CONTRACTS.PancakeSwapOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.PendlePTVaultAdapter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.PendlePTVaultAdapter, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addDSAVToken(address)", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setDSAVTokenActive(uint8,bool)", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setProportionalCloseTolerance(uint256)", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "completePause()", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "completeUnpause()", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "partialPause()", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "partialUnpause()", + target: CONTRACTS.RelativePositionManager, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setPoolConfig(address,address)", + target: CONTRACTS.UniswapOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "addAuthorizedBatchers(address[])", + target: CONTRACTS.AuxiliaryCommandsAggregator, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "executeBatch(uint256)", + target: CONTRACTS.AuxiliaryCommandsAggregator, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removeAuthorizedBatchers(address[])", + target: CONTRACTS.AuxiliaryCommandsAggregator, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "execute(uint16,bytes,bytes,address)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "retryExecute(uint256,uint16,bytes,bytes,address,uint256)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConfig(uint16,uint16,uint256,bytes)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removeTrustedRemote(uint16)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setMaxDailyLimit(uint16,uint256)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setSendVersion(uint16)", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "unpause()", + target: CONTRACTS.OmnichainProposalSender, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "removeAuthorizedSender(address)", + target: CONTRACTS.RiskOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setUpdateTypeActive(string,bool)", + target: CONTRACTS.RiskOracle, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setWhitelistedExecutor(address,bool)", + target: CONTRACTS.RiskStewardReceiver, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConfigActive(string,bool)", + target: CONTRACTS.RiskStewardReceiver, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setPaused(bool)", + target: CONTRACTS.RiskStewardReceiver, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "setConfig(uint16,uint16,uint256,bytes)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "dropFailedMessage(uint16,bytes,uint64)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "forceResumeReceive(uint16,bytes)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "removeTrustedRemote(uint16)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setMinDstGas(uint16,uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setPayloadSizeLimit(uint16,uint256)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setReceiveVersion(uint16)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setSendVersion(uint16)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "updateSendAndCallEnabled(bool)", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "pause()", + target: CONTRACTS.XVSBridgeAdmin, + critical: true, + guardian1: false, + guardian2: true, + guardian3: false, + action: "none", + }, + { + signature: "createVault(VaultConfig,InstitutionalConfig,RiskConfig,string,string,string)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLiquidationIncentive(address,uint256)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setVaultImplementation(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "approvePositionTransfer(address,address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "cancelVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "closeVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "openVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "revokePositionTransfer(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setInstitutionName(address,string)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setInstitutionNameOverride(address,string)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLatePenaltyRate(address,uint256)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "completePauseVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "partialPauseVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "unpauseVault(address)", + target: CONTRACTS.InstitutionalVaultControllerProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setCloseFactor(uint256)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "sweepProtocolShareToReserve(address)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setLiquidatorWhitelist(address,bool)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setProtocolLiquidationShare(uint256)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: false, + guardian2: false, + guardian3: false, + action: "none", + }, + { + signature: "setSettlerWhitelist(address,bool)", + target: CONTRACTS.LiquidationAdapterProxy, + critical: true, + guardian1: true, + guardian2: false, + guardian3: false, + action: "none", + }, +]; From e444310bd2a864ace535803b19ae8d48070eba87 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 15 Jul 2026 13:17:24 +0530 Subject: [PATCH 10/11] refactor: reduce permission data to changed rows and organize it per chain --- simulations/vip-665/bscmainnet.ts | 59 +- simulations/vip-665/utils/remoteSim.ts | 21 +- vips/vip-665/bscmainnet.ts | 20 +- vips/vip-665/data/actionPlan.ts | 472 ------- vips/vip-665/data/addresses.ts | 434 +++--- vips/vip-665/data/cleanup.ts | 207 +-- vips/vip-665/data/criticalChanges.ts | 269 ++++ vips/vip-665/data/noChangeRows.ts | 1682 ------------------------ vips/vip-665/utils/commands.ts | 8 +- 9 files changed, 552 insertions(+), 2620 deletions(-) delete mode 100644 vips/vip-665/data/actionPlan.ts create mode 100644 vips/vip-665/data/criticalChanges.ts delete mode 100644 vips/vip-665/data/noChangeRows.ts diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts index c134a864a..6308ee59b 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-665/bscmainnet.ts @@ -7,7 +7,7 @@ import { expectEvents, initMainnetUser } from "src/utils"; import { forking, testVip } from "src/vip-framework"; import vip665, { EXPECTED_ROLE_EVENTS } from "../../vips/vip-665/bscmainnet"; -import { BNB_ROWS } from "../../vips/vip-665/data/actionPlan"; +import { BNB_ACTIONS } from "../../vips/vip-665/data/criticalChanges"; import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, ZERO } from "../../vips/vip-665/data/addresses"; import { REDUNDANT_REVOKES, STALE_ROWS } from "../../vips/vip-665/data/cleanup"; import { @@ -31,13 +31,11 @@ const vUSDT = "0xfD5840Cd36d94D7229439859C0112a4185BC0255"; const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["address", "string"], [at, fn]); -// One row bucket per action so every category (no-change / revoke / swap / grant) is asserted -// explicitly. Each bucket is guarded to be non-empty so a data regression that empties a category fails -// loudly instead of passing vacuously. -const NO_CHANGE = BNB_ROWS.filter(row => row.action === "none"); -const REVOKE = BNB_ROWS.filter(row => row.action === "revoke"); -const SWAP = BNB_ROWS.filter(row => row.action === "swap"); -const GRANT = BNB_ROWS.filter(row => row.action === "grant"); +// One bucket per action so each category is asserted explicitly and guarded non-empty (a data regression +// that empties a category fails loudly instead of passing vacuously). +const REVOKE = BNB_ACTIONS.filter(row => row.action === "revoke"); +const SWAP = BNB_ACTIONS.filter(row => row.action === "swap"); +const GRANT = BNB_ACTIONS.filter(row => row.action === "grant"); // Redundant (wildcard-shadowed) target-specific grants revoked as behavior-preserving cleanup. const REDUNDANT = REDUNDANT_REVOKES.bscmainnet; @@ -60,13 +58,12 @@ forking(FORK_BLOCK, async () => { describe("VIP-665 pre-execution permissions (bscmainnet)", () => { it("the action plan covers every category with the expected row counts", () => { - expect(NO_CHANGE.length, "no-change rows").to.equal(186); expect(REVOKE.length, "revoke rows").to.equal(26); expect(SWAP.length, "swap rows").to.equal(4); expect(GRANT.length, "grant rows").to.equal(1); expect(STALE_ROWS.length, "stale (dangling cleanup) rows").to.equal(8); expect(BNB_LEGACY_WILDCARD_REVOKES.length, "legacy wildcard revokes").to.equal(3); - expect(REDUNDANT.length, "redundant revokes").to.equal(25); + expect(REDUNDANT.length, "redundant revokes").to.equal(15); }); it("legacy wildcard: each grantee currently holds the 32-byte wildcard role", async () => { @@ -88,18 +85,8 @@ forking(FORK_BLOCK, async () => { }); it("revoke: Critical currently holds every permission to be revoked", async () => { - for (const row of REVOKE) { + for (const row of REVOKE) expect(await holds(BNB_CRITICAL, row), `pre critical ${row.signature}@${row.target}`).to.be.true; - expect(await holds(BNB_GUARDIANS.guardian1, row), `pre g1 ${row.signature}@${row.target}`).to.equal( - row.guardian1, - ); - expect(await holds(BNB_GUARDIANS.guardian2, row), `pre g2 ${row.signature}@${row.target}`).to.equal( - row.guardian2, - ); - expect(await holds(BNB_GUARDIANS.guardian3, row), `pre g3 ${row.signature}@${row.target}`).to.equal( - row.guardian3, - ); - } }); it("swap: Critical holds each one and the target Guardian does not yet", async () => { @@ -230,34 +217,4 @@ forking(FORK_BLOCK, async () => { await expect(asCritical._setForcedLiquidation(vUSDT, true)).to.be.reverted; }); }); - - // "No change" rows carry no action and were validated at extraction (see data/noChangeRows.ts). This block - // re-confirms post-execution that Critical and every listed Guardian still retain each capability — directly - // or via a surviving wildcard — so the VIP touched nothing it shouldn't have. - describe("VIP-665 no-change permissions retained (bscmainnet)", () => { - it("Critical and every listed Guardian can still call each untouched function", async () => { - for (const row of NO_CHANGE) { - if (row.critical) - expect( - await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), - `no-change critical ${row.signature}@${row.target}`, - ).to.be.true; - if (row.guardian1) - expect( - await acm().isAllowedToCall(BNB_GUARDIANS.guardian1, row.signature, { from: row.target }), - `no-change g1 ${row.signature}@${row.target}`, - ).to.be.true; - if (row.guardian2) - expect( - await acm().isAllowedToCall(BNB_GUARDIANS.guardian2, row.signature, { from: row.target }), - `no-change g2 ${row.signature}@${row.target}`, - ).to.be.true; - if (row.guardian3) - expect( - await acm().isAllowedToCall(BNB_GUARDIANS.guardian3, row.signature, { from: row.target }), - `no-change g3 ${row.signature}@${row.target}`, - ).to.be.true; - } - }); - }); }); diff --git a/simulations/vip-665/utils/remoteSim.ts b/simulations/vip-665/utils/remoteSim.ts index aad621fb0..664a34dd3 100644 --- a/simulations/vip-665/utils/remoteSim.ts +++ b/simulations/vip-665/utils/remoteSim.ts @@ -7,7 +7,7 @@ import { expectEvents, initMainnetUser } from "src/utils"; import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; import vip665, { EXPECTED_ROLE_EVENTS } from "../../../vips/vip-665/bscmainnet"; -import { remoteRowsFor } from "../../../vips/vip-665/data/actionPlan"; +import { remoteRowsFor } from "../../../vips/vip-665/data/criticalChanges"; import { REMOTE_ACM, SYNC_CASH_MARKETS, ZERO } from "../../../vips/vip-665/data/addresses"; import { REDUNDANT_REVOKES, SYNC_CASH_SIG } from "../../../vips/vip-665/data/cleanup"; import { AGGREGATOR, Chain, buildGrantPermissions, buildRevokePermissions } from "../../../vips/vip-665/utils/commands"; @@ -26,7 +26,6 @@ const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["addres // Shared body for the 7 remote-chain simulations. Run each with its matching --fork. export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { const critical = NETWORK_ADDRESSES[chain].CRITICAL_TIMELOCK; - const guardian = NETWORK_ADDRESSES[chain].GUARDIAN; const normal = NETWORK_ADDRESSES[chain].NORMAL_TIMELOCK; const syncCashMarkets = SYNC_CASH_MARKETS[chain]; @@ -62,15 +61,6 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { ).to.be.true; }); - it("no-change: the Guardian flag matches the plan for every row", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const row of rows) - expect( - await acm.hasRole(role(row.target, row.signature), guardian), - `pre guardian ${row.signature}@${row.target}`, - ).to.equal(row.guardian); - }); - it("syncCash: NormalTimelock holds every per-market grant and no wildcard grant yet", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); expect(syncCashMarkets.length, `syncCash markets for ${chain}`).to.be.greaterThan(0); @@ -102,15 +92,6 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { ).to.be.false; }); - it("no-change: the Guardian flag is unchanged for every row", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const row of rows) - expect( - await acm.hasRole(role(row.target, row.signature), guardian), - `post guardian ${row.signature}@${row.target}`, - ).to.equal(row.guardian); - }); - it("redundant: each target-specific grant was revoked", async () => { const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); for (const r of redundant) diff --git a/vips/vip-665/bscmainnet.ts b/vips/vip-665/bscmainnet.ts index f9aeb37df..d5af98e90 100644 --- a/vips/vip-665/bscmainnet.ts +++ b/vips/vip-665/bscmainnet.ts @@ -1,7 +1,7 @@ import { Command, ProposalType } from "src/types"; import { makeProposal } from "src/utils"; -import { LZ_CHAIN_ID, RemoteChain } from "./data/actionPlan"; +import { LZ_CHAIN_ID, RemoteChain } from "./data/criticalChanges"; import { AGGREGATOR, Chain, @@ -10,22 +10,22 @@ import { REVOKE_INDEX, acmOf, buildGrantPermissions, - legacyWildcardCommands, buildRevokePermissions, + legacyWildcardCommands, } from "./utils/commands"; // Expected RoleGranted / RoleRevoked counts per chain, asserted by the simulations after execution. // granted = aggregator grants + wrapper grantRole(DEFAULT_ADMIN). revoked = aggregator revokes + wrapper // revokeRole(DEFAULT_ADMIN) + redundant cleanup + (BNB only) the 3 direct legacy-wildcard revokeRole calls. export const EXPECTED_ROLE_EVENTS: Record<"bscmainnet" | RemoteChain, { granted: number; revoked: number }> = { - bscmainnet: { granted: 6, revoked: 81 }, - ethereum: { granted: 2, revoked: 62 }, - arbitrumone: { granted: 2, revoked: 34 }, - basemainnet: { granted: 2, revoked: 29 }, - zksyncmainnet: { granted: 2, revoked: 23 }, - opmainnet: { granted: 2, revoked: 19 }, - unichainmainnet: { granted: 2, revoked: 19 }, - opbnbmainnet: { granted: 2, revoked: 13 }, + bscmainnet: { granted: 6, revoked: 71 }, + ethereum: { granted: 2, revoked: 53 }, + arbitrumone: { granted: 2, revoked: 25 }, + basemainnet: { granted: 2, revoked: 20 }, + zksyncmainnet: { granted: 2, revoked: 22 }, + opmainnet: { granted: 2, revoked: 18 }, + unichainmainnet: { granted: 2, revoked: 18 }, + opbnbmainnet: { granted: 2, revoked: 12 }, }; // The commands the VIP emits per chain: grant the aggregator DEFAULT_ADMIN_ROLE, execute the grant and/or diff --git a/vips/vip-665/data/actionPlan.ts b/vips/vip-665/data/actionPlan.ts deleted file mode 100644 index 769ae749b..000000000 --- a/vips/vip-665/data/actionPlan.ts +++ /dev/null @@ -1,472 +0,0 @@ -// VIP-665 — reduce CriticalTimelock privileges across BNB Chain and the 7 remote mainnets. -// BNB rows carry the current holder flags and the final action; remote rows are all Critical revokes. -import { NETWORK_ADDRESSES } from "src/networkAddresses"; -import { LzChainId } from "src/types"; - -import { - BNB_CRITICAL, - BNB_CONTRACTS as CONTRACTS, - OMNICHAIN_EXECUTOR_OWNER, - SENTINEL_ORACLE, - XVS_BRIDGE_ADMIN, - ZERO, -} from "./addresses"; -import { BNB_NO_CHANGE_ROWS } from "./noChangeRows"; - -// =================================================================================================== -// BNB Chain -// =================================================================================================== -export type Action = "none" | "revoke" | "swap" | "grant"; -// signature = ACM-registered function signature; target = contract it is scoped to; -// critical/guardian1/guardian2/guardian3 = current holders; action = final action; -// grantTo = destination guardian for swap/grant actions. -export interface BnbRow { - signature: string; - target: string; - critical: boolean; - guardian1: boolean; - guardian2: boolean; - guardian3: boolean; - action: Action; - grantTo?: "guardian1" | "guardian2" | "guardian3"; -} - -// Rows carrying an actual change (revoke / swap / grant) — this is the review surface. The untouched -// "No change" inventory lives in noChangeRows.ts and is read only by the simulation's assertions. -export const BNB_ACTION_ROWS: BnbRow[] = [ - { - signature: "setCollateralFactor(address,uint256,uint256)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "setCollateralFactor(uint96,address,uint256,uint256)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "setWhiteListFlashLoanAccount(address,bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "_setMarketBorrowCaps(address[],uint256[])", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "_setMarketSupplyCaps(address[],uint256[])", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "setIsBorrowAllowed(uint96,address,bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "_setForcedLiquidation(address,bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "swap", - grantTo: "guardian1", - }, - { - signature: "_setForcedLiquidationForUser(address,address,bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "swap", - grantTo: "guardian1", - }, - { - signature: "resume()", - target: CONTRACTS.XVSVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setDirectPrice(address,uint256)", - target: CONTRACTS.ChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.ChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setUnderlyingPrice(address,uint256)", - target: CONTRACTS.ChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setThresholds(address,uint256,uint256)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "grant", - grantTo: "guardian1", - }, - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.PythOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setDirectPrice(address,uint256)", - target: CONTRACTS.RedStoneOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.RedStoneOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.ResilientOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setDirectPrice(address,uint256)", - target: CONTRACTS.USDTChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "setTokenConfig(TokenConfig)", - target: CONTRACTS.USDTChainlinkOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "revoke", - }, - { - signature: "addOrUpdateDistributionConfigs(DistributionConfig[])", - target: CONTRACTS.ProtocolShareReserve, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "revoke", - }, - { - signature: "executePositionAccountCall(address,address[],bytes[])", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setDirectPrice(address,uint256)", - target: CONTRACTS.SentinelOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setTokenOracleConfig(address,address)", - target: CONTRACTS.SentinelOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setWhitelist(address,bool)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "swap", - grantTo: "guardian1", - }, - { - signature: "setMaxDailyLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setMaxDailyReceiveLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setMaxSingleReceiveTransactionLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setMaxSingleTransactionLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "unpause()", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "revoke", - }, - { - signature: "setLiquidationThreshold(address,uint256)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "swap", - grantTo: "guardian1", - }, - { - signature: "sweep(address,address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "revoke", - }, -]; - -// Full row set: actions + untouched inventory. commands.ts builders filter by action; the simulation -// groups by action into its category buckets. -export const BNB_ROWS: BnbRow[] = [...BNB_ACTION_ROWS, ...BNB_NO_CHANGE_ROWS]; - -// setCollateralFactor on the isolated-pools wildcard target is revoked from the CriticalTimelock via a -// direct ACM.revokeRole on the legacy BNB ACM (the aggregator cannot clear wildcard grants there — see -// legacyWildcardRole in utils/commands.ts). -export const BNB_ACTION_LEGACY_WILDCARD_REVOKES: { signature: string; account: string }[] = [ - { signature: "setCollateralFactor(address,uint256,uint256)", account: BNB_CRITICAL }, -]; - -// =================================================================================================== -// Remote chains -// =================================================================================================== -export type RemoteChain = - | "ethereum" - | "arbitrumone" - | "basemainnet" - | "zksyncmainnet" - | "opmainnet" - | "unichainmainnet" - | "opbnbmainnet"; - -export const REMOTE_CHAINS: RemoteChain[] = [ - "ethereum", - "arbitrumone", - "basemainnet", - "zksyncmainnet", - "opmainnet", - "unichainmainnet", - "opbnbmainnet", -]; - -export const LZ_CHAIN_ID: Record = { - ethereum: LzChainId.ethereum, - arbitrumone: LzChainId.arbitrumone, - basemainnet: LzChainId.basemainnet, - zksyncmainnet: LzChainId.zksyncmainnet, - opmainnet: LzChainId.opmainnet, - unichainmainnet: LzChainId.unichainmainnet, - opbnbmainnet: LzChainId.opbnbmainnet, -}; - -const addressesOf = (chain: RemoteChain) => NETWORK_ADDRESSES[chain] as Record; - -// Resolve a contract key to its address on a chain. On Arbitrum/OP the "CHAINLINK_ORACLE" key is the -// SequencerChainlinkOracle adapter. -export const remoteAddr = (chain: RemoteChain, c: string): string => { - switch (c) { - case "WILDCARD": - return ZERO; - case "ResilientOracle": - return addressesOf(chain).RESILIENT_ORACLE; - case "ChainlinkOracle": - return addressesOf(chain).CHAINLINK_ORACLE; - case "RedStoneOracle": - return addressesOf(chain).REDSTONE_ORACLE; - case "SequencerChainlinkOracle": - return addressesOf(chain).CHAINLINK_ORACLE; - case "SentinelOracle": - return SENTINEL_ORACLE[chain]!; - case "XVSBridgeAdmin": - return XVS_BRIDGE_ADMIN[chain]; - case "OmnichainExecutorOwner": - return OMNICHAIN_EXECUTOR_OWNER[chain]; - default: - throw new Error(`unknown remote contract key ${c}`); - } -}; - -const ALL_REMOTES = REMOTE_CHAINS; - -// Every row is a revoke from Critical. contract = contract key (resolved per-chain); chains = where it -// applies; guardian = Guardian currently holds it (must still hold post-VIP). -export const REMOTE_ROWS: { signature: string; contract: string; chains: RemoteChain[]; guardian: boolean }[] = [ - // ── Common to all 7 remotes ── - { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle", chains: ALL_REMOTES, guardian: true }, - { - signature: "setCollateralFactor(address,uint256,uint256)", - contract: "WILDCARD", - chains: ALL_REMOTES, - guardian: true, - }, - { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner", chains: ALL_REMOTES, guardian: true }, - { - signature: "setMaxDailyReceiveLimit(uint256)", - contract: "OmnichainExecutorOwner", - chains: ALL_REMOTES, - guardian: true, - }, - { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin", chains: ALL_REMOTES, guardian: false }, - - // ── Chain-specific ── - { - signature: "setDirectPrice(address,uint256)", - contract: "ChainlinkOracle", - chains: ["ethereum", "basemainnet", "zksyncmainnet"], - guardian: true, - }, - { - signature: "setTokenConfig(TokenConfig)", - contract: "ChainlinkOracle", - chains: ["ethereum", "basemainnet", "zksyncmainnet"], - guardian: true, - }, - { - signature: "setDirectPrice(address,uint256)", - contract: "RedStoneOracle", - chains: ["ethereum", "arbitrumone", "basemainnet", "zksyncmainnet", "opmainnet", "unichainmainnet"], - guardian: true, - }, - { - signature: "setTokenConfig(TokenConfig)", - contract: "RedStoneOracle", - chains: ["ethereum", "arbitrumone", "basemainnet", "zksyncmainnet", "opmainnet", "unichainmainnet"], - guardian: true, - }, - { - signature: "setDirectPrice(address,uint256)", - contract: "SequencerChainlinkOracle", - chains: ["arbitrumone", "opmainnet"], - guardian: true, - }, - { - signature: "setTokenConfig(TokenConfig)", - contract: "SequencerChainlinkOracle", - chains: ["arbitrumone", "opmainnet"], - guardian: true, - }, - { - signature: "setDirectPrice(address,uint256)", - contract: "SentinelOracle", - chains: ["ethereum", "arbitrumone", "basemainnet"], - guardian: true, - }, - { - signature: "setTokenOracleConfig(address,address)", - contract: "SentinelOracle", - chains: ["ethereum", "arbitrumone", "basemainnet"], - guardian: true, - }, -]; - -// Rows applicable to one chain, with resolved target address. -export const remoteRowsFor = (chain: RemoteChain) => - REMOTE_ROWS.filter(r => r.chains.includes(chain)).map(r => ({ - signature: r.signature, - target: remoteAddr(chain, r.contract), - guardian: r.guardian, - })); diff --git a/vips/vip-665/data/addresses.ts b/vips/vip-665/data/addresses.ts index 7408f913c..769f507c4 100644 --- a/vips/vip-665/data/addresses.ts +++ b/vips/vip-665/data/addresses.ts @@ -1,17 +1,22 @@ -// All raw on-chain addresses used by VIP-665, grouped by chain and purpose. actionPlan.ts, cleanup.ts, -// the VIP and the simulations reference these named constants so the plan files stay free of literals. +// All raw on-chain addresses used by VIP-665, organized as one block per chain. Within each block the +// entries are ordered `common` (categories every chain shares, so the shape cross-references the doc's +// common section) then `unique` (chain-specific values). criticalChanges.ts, cleanup.ts, the VIP and the +// simulations reference these named constants so the plan files stay free of literals. The per-chain +// blocks are the review surface; the `Record` exports at the bottom are just reassembled from +// them so consumers can keep indexing by chain key. import { NETWORK_ADDRESSES } from "src/networkAddresses"; -import type { RemoteChain } from "./actionPlan"; import type { RedundantChain } from "./cleanup"; +import type { RemoteChain } from "./criticalChanges"; const { bscmainnet } = NETWORK_ADDRESSES; export const ZERO = "0x0000000000000000000000000000000000000000"; // =================================================================================================== -// bscmainnet +// bscmainnet (governance hub) // =================================================================================================== +// -- common: ACM + Critical timelock + Guardians -- export const BNB_ACM = bscmainnet.ACCESS_CONTROL_MANAGER; export const BNB_CRITICAL = bscmainnet.CRITICAL_TIMELOCK; // Guardian 1 = CRITICAL_GUARDIAN (swap/grant target), 2 = GUARDIAN (pause), 3 = oracles. @@ -21,6 +26,7 @@ export const BNB_GUARDIANS = { guardian3: "0x3a3284dC0FaFfb0b5F0d074c4C704D14326C98cF", }; +// -- unique: contracts this VIP touches on BNB -- // Contracts the action plan is scoped to. export const BNB_CONTRACTS = { Liquidator: "0x0870793286aaDA55D39CE7f82fb2766e8004cF43", @@ -84,193 +90,271 @@ export const RETIRED = { TwapOracle: "0xea2f042e1A4f057EF8A5220e57733AD747ea8867", }; +// Redundant-grant cleanup contracts on BNB (shadowed by an identical wildcard grant). +const BNB_REDUNDANT: Record = { + EBrake: "0x35eBaBB99c7Fb7ba0C90bCc26e5d55Cdf89C23Ec", + Prime: "0xBbCD063efE506c3D42a0Fa2dB5C08430288C71FC", + PrimeLeaderboard: "0x55e2ccF68B7A276dc28AfA107997b8B1Be932c0b", + PrimeLiquidityProvider: "0x23c4F844ffDdC6161174eB32c770D4D8C07833F2", + PrimeV2: "0x059EabA8676b03e4e8f009eFb7F587C28450F50f", + Unitroller: "0xfD36E2c2a6789Db23113685031d7F16329158384", + VBNBAdmin: "0x9A7890534d9d91d473F28cB97962d176e2B65f1d", + VenusERC4626Factory: "0xC2f7924809830886EB04c6b40725Fd68F1891fA2", + vUNI: "0x27FF564707786720C71A2e5c1490A63266683612", +}; + +// =================================================================================================== +// ethereum +// =================================================================================================== +// -- common: ACM + XVS bridge admin + omnichain executor owner -- +const ETH_ACM = NETWORK_ADDRESSES.ethereum.ACCESS_CONTROL_MANAGER; +const ETH_XVS_BRIDGE_ADMIN = "0x9C6C95632A8FB3A74f2fB4B7FfC50B003c992b96"; +const ETH_OMNICHAIN_EXECUTOR_OWNER = "0x87Ed3Fd3a25d157637b955991fb1B41B566916Ba"; +const ETH_REDUNDANT: Record = { + EBrake: "0xCD09042c5DFFed762998Df9a058ec5944e39949B", + Prime: "0x14C4525f47A7f7C984474979c57a2Dccb8EACB39", + PrimeLiquidityProvider: "0x8ba6aFfd0e7Bcd0028D1639225C84DdCf53D8872", + VenusERC4626Factory: "0x39cb747453Be3416E659dAeA169540b6F000c885", +}; +// -- unique: SentinelOracle (hardcoded proxy, verified on-chain) + syncCash() markets -- +const ETH_SENTINEL_ORACLE = "0x444C53E194B40c272fAd683210e2cB1c16Ab132e"; +const ETH_SYNC_CASH_MARKETS = [ + "0x0792b9c60C728C1D2Fd6665b3D7A08762a9b28e0", + "0x0Ec5488e4F8f319213a14cab188E01fB8517Faa8", + "0x0c6B19287999f1e31a5c0a44393b24B62D2C0468", + "0x13eB80FDBe5C5f4a7039728E258A6f05fb3B912b", + "0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe", + "0x17C07e0c232f2f80DfDbd7a95b942D893A4C5ACb", + "0x256AdDBe0a387c98f487e44b85c29eb983413c5e", + "0x25C20e6e110A1cE3FEbaCC8b7E48368c7b2F0C91", + "0x2d499800239C4CD3012473Cb1EAE33562F0A6933", + "0x30aD10Bd5Be62CAb37863C2BfcC6E8fb4fD85BDa", + "0x325cEB02fe1C2fF816A83a5770eA0E88e2faEcF2", + "0x475d0C68a8CD275c15D1F01F4f291804E445F677", + "0x4a240F0ee138697726C8a3E43eFE6Ac3593432CB", + "0x4fAfbDc4F2a9876Bd1764827b26fb8dc4FD1dB95", + "0x520d67226Bc904aC122dcE66ed2f8f61AA1ED764", + "0x5e35C312862d53FD566737892aDCf010cb4928F7", + "0x62D9E2010Cff87Bae05B91d5E04605ef864ABc3B", + "0x672208C10aaAA2F9A6719F449C4C8227bc0BC202", + "0x76697f8eaeA4bE01C678376aAb97498Ee8f80D5C", + "0x7c8ff7d2A1372433726f879BD945fFb250B94c65", + "0x8716554364f20BCA783cb2BAA744d39361fd1D8d", + "0x8C3e3821259B82fFb32B2450A95d2dcbf161C24E", + "0xA854D35664c658280fFf27B6eDC6C4195c3229B3", + "0xCca202a95E8096315E3F19E46e19E1b326634889", + "0xDB6C345f864883a8F4cae87852Ac342589E76D1B", + "0xE0ee5dDeBFe0abe0a4Af50299D68b74Cec31668e", + "0xE36Ae842DbbD7aE372ebA02C8239cd431cC063d6", + "0xEF26C64bC06A8dE4CA5D31f119835f9A1d9433b9", + "0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E", + "0xa0EE2bAA024cC3AA1BC9395522D07B7970Ca75b3", + "0xa836ce315b7A6Bb19397Ee996551659B1D92298e", + "0xa8e7f9473635a5CB79646f14356a9Fc394CA111A", + "0xb4933AF59868986316Ed37fa865C829Eba2df0C7", + "0xba3916302cBA4aBcB51a01e706fC6051AaF272A0", + "0xc42E4bfb996ED35235bda505430cBE404Eb49F77", + "0xc82780Db1257C788F262FBbDA960B3706Dfdcaf2", + "0xd8AdD9B41D4E1cd64Edad8722AB0bA8D35536657", + "0xf87c0a64dc3a8622D6c63265FA29137788163879", +]; + +// =================================================================================================== +// arbitrumone +// =================================================================================================== +// -- common -- +const ARB_ACM = NETWORK_ADDRESSES.arbitrumone.ACCESS_CONTROL_MANAGER; +const ARB_XVS_BRIDGE_ADMIN = "0xf5d81C6F7DAA3F97A6265C8441f92eFda22Ad784"; +const ARB_OMNICHAIN_EXECUTOR_OWNER = "0xf72C1Aa0A1227B4bCcB28E1B1015F0616E2db7fD"; +const ARB_REDUNDANT: Record = { + EBrake: "0xFc4CE7Ca9BB5119705Cfb84d6e4476e8a4032b26", + Prime: "0xFE69720424C954A2da05648a0FAC84f9bf11Ef49", + PrimeLiquidityProvider: "0x86bf21dB200f29F21253080942Be8af61046Ec29", + VenusERC4626Factory: "0xC1422B928cb6FC9BA52880892078578a93aa5Cc7", +}; +// -- unique -- +const ARB_SENTINEL_ORACLE = "0x3563CAbc541a0432C66A64942ffB4070a9726226"; +const ARB_SYNC_CASH_MARKETS = [ + "0x246a35E79a3a0618535A469aDaF5091cAA9f7E88", + "0x39D6d13Ea59548637104E40e729E4aABE27FE106", + "0x4f3a73f318C5EA67A86eaaCE24309F29f89900dF", + "0x68a34332983f4Bf866768DD6D6E638b02eF5e1f0", + "0x7D8609f8da70fF9027E9bc5229Af4F6727662707", + "0x9bb8cEc9C0d46F53b4f2173BB2A0221F66c353cC", + "0x9df6B5132135f14719696bBAe3C54BAb272fDb16", + "0xAeB0FEd69354f34831fe1D16475D9A83ddaCaDA6", + "0xB9F9117d4200dC296F9AcD1e8bE1937df834a2fD", + "0xaDa57840B372D4c28623E87FC175dE8490792811", +]; + +// =================================================================================================== +// basemainnet +// =================================================================================================== +// -- common -- +const BASE_ACM = NETWORK_ADDRESSES.basemainnet.ACCESS_CONTROL_MANAGER; +const BASE_XVS_BRIDGE_ADMIN = "0x6303FEcee7161bF959d65df4Afb9e1ba5701f78e"; +const BASE_OMNICHAIN_EXECUTOR_OWNER = "0x8BA591f72a90fb379b9a82087b190d51b226F0a9"; +const BASE_REDUNDANT: Record = { + EBrake: "0x062C68Af7B9Fb059DCB7FA4B6b92E633350fb7c2", + Prime: "0xD2e84244f1e9Fca03Ff024af35b8f9612D5d7a30", + PrimeLiquidityProvider: "0xcB293EB385dEFF2CdeDa4E7060974BB90ee0B208", + VenusERC4626Factory: "0x1A430825B31DdA074751D6731Ce7Dca38D012D13", +}; +// -- unique -- +const BASE_SENTINEL_ORACLE = "0xCdD6D79Fd313C21967CED04C1b8bE70BDc27574D"; +const BASE_SYNC_CASH_MARKETS = [ + "0x133d3BCD77158D125B75A17Cb517fFD4B4BE64C5", + "0x3cb752d175740043Ec463673094e06ACDa2F9a2e", + "0x75201D81B3B0b9D17b179118837Be37f64fc4930", + "0x7bBd1005bB24Ec84705b04e1f2DfcCad533b6D72", + "0xEB8A79bD44cF4500943bf94a2b4434c95C008599", +]; + +// =================================================================================================== +// zksyncmainnet +// =================================================================================================== +// -- common -- +const ZK_ACM = NETWORK_ADDRESSES.zksyncmainnet.ACCESS_CONTROL_MANAGER; +const ZK_XVS_BRIDGE_ADMIN = "0x2471043F05Cc41A6051dd6714DC967C7BfC8F902"; +const ZK_OMNICHAIN_EXECUTOR_OWNER = "0xdfaed3E5d9707629Ed5c225b4fB980c064286771"; +const ZK_REDUNDANT: Record = { + Prime: "0xdFe62Dcba3Ce0A827439390d7d45Af8baE599978", + PrimeLiquidityProvider: "0x0EDE6d7fB474614C5D3d5a16581628bb96CB5dff", + VenusERC4626Factory: "0xDC59Dd76Dd7A64d743C764a9aa8C96Ff2Ea8BAc3", +}; +// -- unique (no SentinelOracle on this chain) -- +const ZK_SYNC_CASH_MARKETS = [ + "0x03CAd66259f7F34EE075f8B62D133563D249eDa4", + "0x183dE3C349fCf546aAe925E1c7F364EA6FB4033c", + "0x1Fa916C27c7C2c4602124A14C77Dbb40a5FF1BE8", + "0x1aF23bD57c62A99C59aD48236553D0Dd11e49D2D", + "0x697a70779C1A03Ba2BD28b7627a902BFf831b616", + "0x69cDA960E3b20DFD480866fFfd377Ebe40bd0A46", + "0x84064c058F2EFea4AB648bB6Bd7e40f83fFDe39a", + "0xAF8fD83cFCbe963211FAaf1847F0F217F80B4719", + "0xCEb7Da150d16aCE58F090754feF2775C23C8b631", +]; + +// =================================================================================================== +// opmainnet +// =================================================================================================== +// -- common (ACM not in networkAddresses — hardcoded, verified on-chain) -- +const OP_ACM = "0xD71b1F33f6B0259683f11174EE4Ddc2bb9cE4eD6"; +const OP_XVS_BRIDGE_ADMIN = "0x3c307DF1Bf3198a2417d9CA86806B307D147Ddf7"; +const OP_OMNICHAIN_EXECUTOR_OWNER = "0xe6d9Eb3A07a1dc4496fc71417D7A7b9d5666BaA3"; +const OP_REDUNDANT: Record = { + Prime: "0xE76d2173546Be97Fa6E18358027BdE9742a649f7", + PrimeLiquidityProvider: "0x6412f6cd58D0182aE150b90B5A99e285b91C1a12", + VenusERC4626Factory: "0xc801B471F00Dc22B9a7d7b839CBE87E46d70946F", +}; +// -- unique (no SentinelOracle on this chain) -- +const OP_SYNC_CASH_MARKETS = [ + "0x1C9406ee95B7af55F005996947b19F91B6D55b15", + "0x37ac9731B0B02df54975cd0c7240e0977a051721", + "0x66d5AE25731Ce99D46770745385e662C8e0B4025", + "0x6b846E3418455804C1920fA4CC7a31A51C659A2D", + "0x9EfdCfC2373f81D3DF24647B1c46e15268884c46", +]; + +// =================================================================================================== +// unichainmainnet +// =================================================================================================== +// -- common (ACM not in networkAddresses — hardcoded, verified on-chain) -- +const UNI_ACM = "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0"; +const UNI_XVS_BRIDGE_ADMIN = "0x2EAaa880f97C9B63d37b39b0b316022d93d43604"; +const UNI_OMNICHAIN_EXECUTOR_OWNER = "0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd"; +const UNI_REDUNDANT: Record = { + Prime: "0x600aFf613d40D87C8Fe90Cb2e78e8e6667c0C872", + PrimeLiquidityProvider: "0x045a45603E1b073F444fe3Be7d5C7e0a5035afB7", + VenusERC4626Factory: "0x102fEb723C25c67dbdfDccCa3B1c1a6e1a662D2f", +}; +// -- unique (no SentinelOracle on this chain) -- +const UNI_SYNC_CASH_MARKETS = [ + "0x0170398083eb0D0387709523baFCA6426146C218", + "0x67716D6Bf76170Af816F5735e14c4d44D0B05eD2", + "0x68e2A6F7257FAc2F5a557b9E83E1fE6D5B408CE5", + "0xB953f92B9f759d97d2F2Dec10A8A3cf75fcE3A95", + "0xDa7Ce7Ba016d266645712e2e4Ebc6cC75eA8E4CD", + "0xbEC19Bef402C697a7be315d3e59E5F65b89Fa1BB", + "0xc219BC179C7cDb37eACB03f993f9fDc2495e3374", +]; + +// =================================================================================================== +// opbnbmainnet +// =================================================================================================== +// -- common (ACM not in networkAddresses — hardcoded, verified on-chain) -- +const OPBNB_ACM = "0xA60Deae5344F1152426cA440fb6552eA0e3005D6"; +const OPBNB_XVS_BRIDGE_ADMIN = "0x52fcE05aDbf6103d71ed2BA8Be7A317282731831"; +const OPBNB_OMNICHAIN_EXECUTOR_OWNER = "0xf7e4c81Cf4A03d52472a4d00c3d9Ef35aF127E45"; +const OPBNB_REDUNDANT: Record = { + VenusERC4626Factory: "0x89A5Ce0A6db7e66E53F148B50D879b700dEB81C8", +}; +// -- unique (no SentinelOracle on this chain) -- +const OPBNB_SYNC_CASH_MARKETS = [ + "0x13B492B8A03d072Bab5C54AC91Dba5b830a50917", + "0x509e81eF638D489936FA85BC58F52Df01190d26C", + "0x53d11cB8A0e5320Cd7229C3acc80d1A0707F2672", + "0xED827b80Bd838192EA95002C01B5c6dA8354219a", + "0xb7a01Ba126830692238521a1aA7E7A7509410b8e", +]; + // =================================================================================================== -// Remote chains +// Reassembled per-chain records — indexed by chain key by consumers. Edit the per-chain blocks above, +// not these. // =================================================================================================== -// ACM for op / unichain / opBNB is not in networkAddresses — hardcoded (verified on-chain). export const REMOTE_ACM: Record = { - ethereum: NETWORK_ADDRESSES.ethereum.ACCESS_CONTROL_MANAGER, - arbitrumone: NETWORK_ADDRESSES.arbitrumone.ACCESS_CONTROL_MANAGER, - basemainnet: NETWORK_ADDRESSES.basemainnet.ACCESS_CONTROL_MANAGER, - zksyncmainnet: NETWORK_ADDRESSES.zksyncmainnet.ACCESS_CONTROL_MANAGER, - opmainnet: "0xD71b1F33f6B0259683f11174EE4Ddc2bb9cE4eD6", - unichainmainnet: "0x1f12014c497a9d905155eB9BfDD9FaC6885e61d0", - opbnbmainnet: "0xA60Deae5344F1152426cA440fb6552eA0e3005D6", + ethereum: ETH_ACM, + arbitrumone: ARB_ACM, + basemainnet: BASE_ACM, + zksyncmainnet: ZK_ACM, + opmainnet: OP_ACM, + unichainmainnet: UNI_ACM, + opbnbmainnet: OPBNB_ACM, }; -// Per-chain contract addresses that networkAddresses does not key. export const XVS_BRIDGE_ADMIN: Record = { - ethereum: "0x9C6C95632A8FB3A74f2fB4B7FfC50B003c992b96", - arbitrumone: "0xf5d81C6F7DAA3F97A6265C8441f92eFda22Ad784", - basemainnet: "0x6303FEcee7161bF959d65df4Afb9e1ba5701f78e", - zksyncmainnet: "0x2471043F05Cc41A6051dd6714DC967C7BfC8F902", - opmainnet: "0x3c307DF1Bf3198a2417d9CA86806B307D147Ddf7", - unichainmainnet: "0x2EAaa880f97C9B63d37b39b0b316022d93d43604", - opbnbmainnet: "0x52fcE05aDbf6103d71ed2BA8Be7A317282731831", + ethereum: ETH_XVS_BRIDGE_ADMIN, + arbitrumone: ARB_XVS_BRIDGE_ADMIN, + basemainnet: BASE_XVS_BRIDGE_ADMIN, + zksyncmainnet: ZK_XVS_BRIDGE_ADMIN, + opmainnet: OP_XVS_BRIDGE_ADMIN, + unichainmainnet: UNI_XVS_BRIDGE_ADMIN, + opbnbmainnet: OPBNB_XVS_BRIDGE_ADMIN, }; export const OMNICHAIN_EXECUTOR_OWNER: Record = { - ethereum: "0x87Ed3Fd3a25d157637b955991fb1B41B566916Ba", - arbitrumone: "0xf72C1Aa0A1227B4bCcB28E1B1015F0616E2db7fD", - basemainnet: "0x8BA591f72a90fb379b9a82087b190d51b226F0a9", - zksyncmainnet: "0xdfaed3E5d9707629Ed5c225b4fB980c064286771", - opmainnet: "0xe6d9Eb3A07a1dc4496fc71417D7A7b9d5666BaA3", - unichainmainnet: "0x6E78a0d96257F8F2615d72F3ee48cb6fb2c970bd", - opbnbmainnet: "0xf7e4c81Cf4A03d52472a4d00c3d9Ef35aF127E45", + ethereum: ETH_OMNICHAIN_EXECUTOR_OWNER, + arbitrumone: ARB_OMNICHAIN_EXECUTOR_OWNER, + basemainnet: BASE_OMNICHAIN_EXECUTOR_OWNER, + zksyncmainnet: ZK_OMNICHAIN_EXECUTOR_OWNER, + opmainnet: OP_OMNICHAIN_EXECUTOR_OWNER, + unichainmainnet: UNI_OMNICHAIN_EXECUTOR_OWNER, + opbnbmainnet: OPBNB_OMNICHAIN_EXECUTOR_OWNER, }; -// SentinelOracle is not published in the @venusprotocol deployment packages — hardcoded proxies, -// verified on-chain. export const SENTINEL_ORACLE: Partial> = { - ethereum: "0x444C53E194B40c272fAd683210e2cB1c16Ab132e", - arbitrumone: "0x3563CAbc541a0432C66A64942ffB4070a9726226", - basemainnet: "0xCdD6D79Fd313C21967CED04C1b8bE70BDc27574D", + ethereum: ETH_SENTINEL_ORACLE, + arbitrumone: ARB_SENTINEL_ORACLE, + basemainnet: BASE_SENTINEL_ORACLE, }; -// Markets whose syncCash() role is currently granted per-market to the NormalTimelock, per chain. export const SYNC_CASH_MARKETS: Record = { - ethereum: [ - "0x0792b9c60C728C1D2Fd6665b3D7A08762a9b28e0", - "0x0Ec5488e4F8f319213a14cab188E01fB8517Faa8", - "0x0c6B19287999f1e31a5c0a44393b24B62D2C0468", - "0x13eB80FDBe5C5f4a7039728E258A6f05fb3B912b", - "0x17142a05fe678e9584FA1d88EfAC1bF181bF7ABe", - "0x17C07e0c232f2f80DfDbd7a95b942D893A4C5ACb", - "0x256AdDBe0a387c98f487e44b85c29eb983413c5e", - "0x25C20e6e110A1cE3FEbaCC8b7E48368c7b2F0C91", - "0x2d499800239C4CD3012473Cb1EAE33562F0A6933", - "0x30aD10Bd5Be62CAb37863C2BfcC6E8fb4fD85BDa", - "0x325cEB02fe1C2fF816A83a5770eA0E88e2faEcF2", - "0x475d0C68a8CD275c15D1F01F4f291804E445F677", - "0x4a240F0ee138697726C8a3E43eFE6Ac3593432CB", - "0x4fAfbDc4F2a9876Bd1764827b26fb8dc4FD1dB95", - "0x520d67226Bc904aC122dcE66ed2f8f61AA1ED764", - "0x5e35C312862d53FD566737892aDCf010cb4928F7", - "0x62D9E2010Cff87Bae05B91d5E04605ef864ABc3B", - "0x672208C10aaAA2F9A6719F449C4C8227bc0BC202", - "0x76697f8eaeA4bE01C678376aAb97498Ee8f80D5C", - "0x7c8ff7d2A1372433726f879BD945fFb250B94c65", - "0x8716554364f20BCA783cb2BAA744d39361fd1D8d", - "0x8C3e3821259B82fFb32B2450A95d2dcbf161C24E", - "0xA854D35664c658280fFf27B6eDC6C4195c3229B3", - "0xCca202a95E8096315E3F19E46e19E1b326634889", - "0xDB6C345f864883a8F4cae87852Ac342589E76D1B", - "0xE0ee5dDeBFe0abe0a4Af50299D68b74Cec31668e", - "0xE36Ae842DbbD7aE372ebA02C8239cd431cC063d6", - "0xEF26C64bC06A8dE4CA5D31f119835f9A1d9433b9", - "0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E", - "0xa0EE2bAA024cC3AA1BC9395522D07B7970Ca75b3", - "0xa836ce315b7A6Bb19397Ee996551659B1D92298e", - "0xa8e7f9473635a5CB79646f14356a9Fc394CA111A", - "0xb4933AF59868986316Ed37fa865C829Eba2df0C7", - "0xba3916302cBA4aBcB51a01e706fC6051AaF272A0", - "0xc42E4bfb996ED35235bda505430cBE404Eb49F77", - "0xc82780Db1257C788F262FBbDA960B3706Dfdcaf2", - "0xd8AdD9B41D4E1cd64Edad8722AB0bA8D35536657", - "0xf87c0a64dc3a8622D6c63265FA29137788163879", - ], - arbitrumone: [ - "0x246a35E79a3a0618535A469aDaF5091cAA9f7E88", - "0x39D6d13Ea59548637104E40e729E4aABE27FE106", - "0x4f3a73f318C5EA67A86eaaCE24309F29f89900dF", - "0x68a34332983f4Bf866768DD6D6E638b02eF5e1f0", - "0x7D8609f8da70fF9027E9bc5229Af4F6727662707", - "0x9bb8cEc9C0d46F53b4f2173BB2A0221F66c353cC", - "0x9df6B5132135f14719696bBAe3C54BAb272fDb16", - "0xAeB0FEd69354f34831fe1D16475D9A83ddaCaDA6", - "0xB9F9117d4200dC296F9AcD1e8bE1937df834a2fD", - "0xaDa57840B372D4c28623E87FC175dE8490792811", - ], - basemainnet: [ - "0x133d3BCD77158D125B75A17Cb517fFD4B4BE64C5", - "0x3cb752d175740043Ec463673094e06ACDa2F9a2e", - "0x75201D81B3B0b9D17b179118837Be37f64fc4930", - "0x7bBd1005bB24Ec84705b04e1f2DfcCad533b6D72", - "0xEB8A79bD44cF4500943bf94a2b4434c95C008599", - ], - zksyncmainnet: [ - "0x03CAd66259f7F34EE075f8B62D133563D249eDa4", - "0x183dE3C349fCf546aAe925E1c7F364EA6FB4033c", - "0x1Fa916C27c7C2c4602124A14C77Dbb40a5FF1BE8", - "0x1aF23bD57c62A99C59aD48236553D0Dd11e49D2D", - "0x697a70779C1A03Ba2BD28b7627a902BFf831b616", - "0x69cDA960E3b20DFD480866fFfd377Ebe40bd0A46", - "0x84064c058F2EFea4AB648bB6Bd7e40f83fFDe39a", - "0xAF8fD83cFCbe963211FAaf1847F0F217F80B4719", - "0xCEb7Da150d16aCE58F090754feF2775C23C8b631", - ], - opmainnet: [ - "0x1C9406ee95B7af55F005996947b19F91B6D55b15", - "0x37ac9731B0B02df54975cd0c7240e0977a051721", - "0x66d5AE25731Ce99D46770745385e662C8e0B4025", - "0x6b846E3418455804C1920fA4CC7a31A51C659A2D", - "0x9EfdCfC2373f81D3DF24647B1c46e15268884c46", - ], - unichainmainnet: [ - "0x0170398083eb0D0387709523baFCA6426146C218", - "0x67716D6Bf76170Af816F5735e14c4d44D0B05eD2", - "0x68e2A6F7257FAc2F5a557b9E83E1fE6D5B408CE5", - "0xB953f92B9f759d97d2F2Dec10A8A3cf75fcE3A95", - "0xDa7Ce7Ba016d266645712e2e4Ebc6cC75eA8E4CD", - "0xbEC19Bef402C697a7be315d3e59E5F65b89Fa1BB", - "0xc219BC179C7cDb37eACB03f993f9fDc2495e3374", - ], - opbnbmainnet: [ - "0x13B492B8A03d072Bab5C54AC91Dba5b830a50917", - "0x509e81eF638D489936FA85BC58F52Df01190d26C", - "0x53d11cB8A0e5320Cd7229C3acc80d1A0707F2672", - "0xED827b80Bd838192EA95002C01B5c6dA8354219a", - "0xb7a01Ba126830692238521a1aA7E7A7509410b8e", - ], + ethereum: ETH_SYNC_CASH_MARKETS, + arbitrumone: ARB_SYNC_CASH_MARKETS, + basemainnet: BASE_SYNC_CASH_MARKETS, + zksyncmainnet: ZK_SYNC_CASH_MARKETS, + opmainnet: OP_SYNC_CASH_MARKETS, + unichainmainnet: UNI_SYNC_CASH_MARKETS, + opbnbmainnet: OPBNB_SYNC_CASH_MARKETS, }; -// Contracts the redundant-grant cleanup is scoped to, per chain. export const REDUNDANT_CONTRACTS: Record> = { - bscmainnet: { - EBrake: "0x35eBaBB99c7Fb7ba0C90bCc26e5d55Cdf89C23Ec", - Prime: "0xBbCD063efE506c3D42a0Fa2dB5C08430288C71FC", - PrimeLeaderboard: "0x55e2ccF68B7A276dc28AfA107997b8B1Be932c0b", - PrimeLiquidityProvider: "0x23c4F844ffDdC6161174eB32c770D4D8C07833F2", - PrimeV2: "0x059EabA8676b03e4e8f009eFb7F587C28450F50f", - Unitroller: "0xfD36E2c2a6789Db23113685031d7F16329158384", - VBNBAdmin: "0x9A7890534d9d91d473F28cB97962d176e2B65f1d", - VenusERC4626Factory: "0xC2f7924809830886EB04c6b40725Fd68F1891fA2", - vUNI: "0x27FF564707786720C71A2e5c1490A63266683612", - }, - ethereum: { - EBrake: "0xCD09042c5DFFed762998Df9a058ec5944e39949B", - Prime: "0x14C4525f47A7f7C984474979c57a2Dccb8EACB39", - PrimeLiquidityProvider: "0x8ba6aFfd0e7Bcd0028D1639225C84DdCf53D8872", - VenusERC4626Factory: "0x39cb747453Be3416E659dAeA169540b6F000c885", - }, - arbitrumone: { - EBrake: "0xFc4CE7Ca9BB5119705Cfb84d6e4476e8a4032b26", - Prime: "0xFE69720424C954A2da05648a0FAC84f9bf11Ef49", - PrimeLiquidityProvider: "0x86bf21dB200f29F21253080942Be8af61046Ec29", - VenusERC4626Factory: "0xC1422B928cb6FC9BA52880892078578a93aa5Cc7", - }, - basemainnet: { - EBrake: "0x062C68Af7B9Fb059DCB7FA4B6b92E633350fb7c2", - Prime: "0xD2e84244f1e9Fca03Ff024af35b8f9612D5d7a30", - PrimeLiquidityProvider: "0xcB293EB385dEFF2CdeDa4E7060974BB90ee0B208", - VenusERC4626Factory: "0x1A430825B31DdA074751D6731Ce7Dca38D012D13", - }, - opmainnet: { - Prime: "0xE76d2173546Be97Fa6E18358027BdE9742a649f7", - PrimeLiquidityProvider: "0x6412f6cd58D0182aE150b90B5A99e285b91C1a12", - VenusERC4626Factory: "0xc801B471F00Dc22B9a7d7b839CBE87E46d70946F", - }, - unichainmainnet: { - Prime: "0x600aFf613d40D87C8Fe90Cb2e78e8e6667c0C872", - PrimeLiquidityProvider: "0x045a45603E1b073F444fe3Be7d5C7e0a5035afB7", - VenusERC4626Factory: "0x102fEb723C25c67dbdfDccCa3B1c1a6e1a662D2f", - }, - zksyncmainnet: { - Prime: "0xdFe62Dcba3Ce0A827439390d7d45Af8baE599978", - PrimeLiquidityProvider: "0x0EDE6d7fB474614C5D3d5a16581628bb96CB5dff", - VenusERC4626Factory: "0xDC59Dd76Dd7A64d743C764a9aa8C96Ff2Ea8BAc3", - }, - opbnbmainnet: { - VenusERC4626Factory: "0x89A5Ce0A6db7e66E53F148B50D879b700dEB81C8", - }, + bscmainnet: BNB_REDUNDANT, + ethereum: ETH_REDUNDANT, + arbitrumone: ARB_REDUNDANT, + basemainnet: BASE_REDUNDANT, + opmainnet: OP_REDUNDANT, + unichainmainnet: UNI_REDUNDANT, + zksyncmainnet: ZK_REDUNDANT, + opbnbmainnet: OPBNB_REDUNDANT, }; diff --git a/vips/vip-665/data/cleanup.ts b/vips/vip-665/data/cleanup.ts index f30d03d2d..6e29ef56b 100644 --- a/vips/vip-665/data/cleanup.ts +++ b/vips/vip-665/data/cleanup.ts @@ -5,7 +5,7 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import type { Permission } from "../utils/commands"; -import { RemoteChain } from "./actionPlan"; +import { RemoteChain } from "./criticalChanges"; import { BNB_GUARDIANS, REDUNDANT_CONTRACTS as CONTRACTS, RETIRED, SYNC_CASH_MARKETS, ZERO } from "./addresses"; const { bscmainnet } = NETWORK_ADDRESSES; @@ -107,36 +107,6 @@ export interface RedundantRevoke { // The 75 redundant target-specific grants, per chain. export const REDUNDANT_REVOKES: Record = { bscmainnet: [ - { - contract: CONTRACTS.bscmainnet.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.bscmainnet.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.bscmainnet.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.bscmainnet.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.bscmainnet.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.bscmainnet.CRITICAL_TIMELOCK, - }, - { - contract: CONTRACTS.bscmainnet.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.bscmainnet.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.bscmainnet.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.bscmainnet.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.bscmainnet.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.bscmainnet.CRITICAL_TIMELOCK, - }, { contract: CONTRACTS.bscmainnet.Prime, signature: "setMaxLoopsLimit(uint256)", @@ -197,31 +167,11 @@ export const REDUNDANT_REVOKES: Record = { signature: "unlistMarket(address)", account: na.bscmainnet.GUARDIAN, }, - { - contract: CONTRACTS.bscmainnet.VBNBAdmin, - signature: "setInterestRateModel(address)", - account: na.bscmainnet.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.bscmainnet.VBNBAdmin, - signature: "setInterestRateModel(address)", - account: na.bscmainnet.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.bscmainnet.VBNBAdmin, - signature: "setInterestRateModel(address)", - account: na.bscmainnet.CRITICAL_TIMELOCK, - }, { contract: CONTRACTS.bscmainnet.VenusERC4626Factory, signature: "setMaxLoopsLimit(uint256)", account: na.bscmainnet.NORMAL_TIMELOCK, }, - { - contract: CONTRACTS.bscmainnet.VenusERC4626Factory, - signature: "setRewardRecipient(address)", - account: na.bscmainnet.NORMAL_TIMELOCK, - }, { contract: CONTRACTS.bscmainnet.vUNI, signature: "_setReserveFactor(uint256)", @@ -234,46 +184,6 @@ export const REDUNDANT_REVOKES: Record = { }, ], ethereum: [ - { - contract: CONTRACTS.ethereum.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.ethereum.GUARDIAN, - }, - { - contract: CONTRACTS.ethereum.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.ethereum.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.ethereum.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.ethereum.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.ethereum.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.ethereum.CRITICAL_TIMELOCK, - }, - { - contract: CONTRACTS.ethereum.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.ethereum.GUARDIAN, - }, - { - contract: CONTRACTS.ethereum.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.ethereum.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.ethereum.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.ethereum.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.ethereum.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.ethereum.CRITICAL_TIMELOCK, - }, { contract: CONTRACTS.ethereum.Prime, signature: "setMaxLoopsLimit(uint256)", @@ -289,53 +199,8 @@ export const REDUNDANT_REVOKES: Record = { signature: "setMaxLoopsLimit(uint256)", account: na.ethereum.NORMAL_TIMELOCK, }, - { - contract: CONTRACTS.ethereum.VenusERC4626Factory, - signature: "setRewardRecipient(address)", - account: na.ethereum.NORMAL_TIMELOCK, - }, ], arbitrumone: [ - { - contract: CONTRACTS.arbitrumone.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.arbitrumone.GUARDIAN, - }, - { - contract: CONTRACTS.arbitrumone.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.arbitrumone.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.arbitrumone.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.arbitrumone.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.arbitrumone.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.arbitrumone.CRITICAL_TIMELOCK, - }, - { - contract: CONTRACTS.arbitrumone.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.arbitrumone.GUARDIAN, - }, - { - contract: CONTRACTS.arbitrumone.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.arbitrumone.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.arbitrumone.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.arbitrumone.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.arbitrumone.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.arbitrumone.CRITICAL_TIMELOCK, - }, { contract: CONTRACTS.arbitrumone.Prime, signature: "setMaxLoopsLimit(uint256)", @@ -351,53 +216,8 @@ export const REDUNDANT_REVOKES: Record = { signature: "setMaxLoopsLimit(uint256)", account: na.arbitrumone.NORMAL_TIMELOCK, }, - { - contract: CONTRACTS.arbitrumone.VenusERC4626Factory, - signature: "setRewardRecipient(address)", - account: na.arbitrumone.NORMAL_TIMELOCK, - }, ], basemainnet: [ - { - contract: CONTRACTS.basemainnet.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.basemainnet.GUARDIAN, - }, - { - contract: CONTRACTS.basemainnet.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.basemainnet.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.basemainnet.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.basemainnet.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.basemainnet.EBrake, - signature: "setMarketBorrowCaps(address[],uint256[])", - account: na.basemainnet.CRITICAL_TIMELOCK, - }, - { - contract: CONTRACTS.basemainnet.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.basemainnet.GUARDIAN, - }, - { - contract: CONTRACTS.basemainnet.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.basemainnet.NORMAL_TIMELOCK, - }, - { - contract: CONTRACTS.basemainnet.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.basemainnet.FAST_TRACK_TIMELOCK, - }, - { - contract: CONTRACTS.basemainnet.EBrake, - signature: "setMarketSupplyCaps(address[],uint256[])", - account: na.basemainnet.CRITICAL_TIMELOCK, - }, { contract: CONTRACTS.basemainnet.Prime, signature: "setMaxLoopsLimit(uint256)", @@ -413,11 +233,6 @@ export const REDUNDANT_REVOKES: Record = { signature: "setMaxLoopsLimit(uint256)", account: na.basemainnet.NORMAL_TIMELOCK, }, - { - contract: CONTRACTS.basemainnet.VenusERC4626Factory, - signature: "setRewardRecipient(address)", - account: na.basemainnet.NORMAL_TIMELOCK, - }, ], opmainnet: [ { @@ -435,11 +250,6 @@ export const REDUNDANT_REVOKES: Record = { signature: "setMaxLoopsLimit(uint256)", account: na.opmainnet.NORMAL_TIMELOCK, }, - { - contract: CONTRACTS.opmainnet.VenusERC4626Factory, - signature: "setRewardRecipient(address)", - account: na.opmainnet.NORMAL_TIMELOCK, - }, ], unichainmainnet: [ { @@ -457,11 +267,6 @@ export const REDUNDANT_REVOKES: Record = { signature: "setMaxLoopsLimit(uint256)", account: na.unichainmainnet.NORMAL_TIMELOCK, }, - { - contract: CONTRACTS.unichainmainnet.VenusERC4626Factory, - signature: "setRewardRecipient(address)", - account: na.unichainmainnet.NORMAL_TIMELOCK, - }, ], zksyncmainnet: [ { @@ -479,11 +284,6 @@ export const REDUNDANT_REVOKES: Record = { signature: "setMaxLoopsLimit(uint256)", account: na.zksyncmainnet.NORMAL_TIMELOCK, }, - { - contract: CONTRACTS.zksyncmainnet.VenusERC4626Factory, - signature: "setRewardRecipient(address)", - account: na.zksyncmainnet.NORMAL_TIMELOCK, - }, ], opbnbmainnet: [ { @@ -491,10 +291,5 @@ export const REDUNDANT_REVOKES: Record = { signature: "setMaxLoopsLimit(uint256)", account: na.opbnbmainnet.NORMAL_TIMELOCK, }, - { - contract: CONTRACTS.opbnbmainnet.VenusERC4626Factory, - signature: "setRewardRecipient(address)", - account: na.opbnbmainnet.NORMAL_TIMELOCK, - }, ], }; diff --git a/vips/vip-665/data/criticalChanges.ts b/vips/vip-665/data/criticalChanges.ts new file mode 100644 index 000000000..46026311c --- /dev/null +++ b/vips/vip-665/data/criticalChanges.ts @@ -0,0 +1,269 @@ +// VIP-665 — CriticalTimelock privilege changes across BNB Chain and the 7 remote mainnets. +// This file is the review surface: only permissions the VIP actually changes. Untouched ("No change") +// permissions are intentionally not listed — the VIP does not touch them, so there is nothing to assert. +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { LzChainId } from "src/types"; + +import { + BNB_CRITICAL, + BNB_CONTRACTS as CONTRACTS, + OMNICHAIN_EXECUTOR_OWNER, + SENTINEL_ORACLE, + XVS_BRIDGE_ADMIN, + ZERO, +} from "./addresses"; + +// =================================================================================================== +// BNB Chain +// =================================================================================================== +// revoke = remove from Critical · swap = grant to the Guardian then revoke from Critical · grant = add to +// the Guardian while Critical keeps it. grantTo = destination Guardian for swap/grant. +export type Action = "revoke" | "swap" | "grant"; + +export interface BnbAction { + target: string; + signature: string; + action: Action; + grantTo?: "guardian1" | "guardian2" | "guardian3"; +} + +export const BNB_ACTIONS: BnbAction[] = [ + { target: CONTRACTS.Unitroller, signature: "setCollateralFactor(address,uint256,uint256)", action: "revoke" }, + { target: CONTRACTS.Unitroller, signature: "setCollateralFactor(uint96,address,uint256,uint256)", action: "revoke" }, + { target: CONTRACTS.Unitroller, signature: "setWhiteListFlashLoanAccount(address,bool)", action: "revoke" }, + { target: CONTRACTS.Unitroller, signature: "_setMarketBorrowCaps(address[],uint256[])", action: "revoke" }, + { target: CONTRACTS.Unitroller, signature: "_setMarketSupplyCaps(address[],uint256[])", action: "revoke" }, + { target: CONTRACTS.Unitroller, signature: "setIsBorrowAllowed(uint96,address,bool)", action: "revoke" }, + { + target: CONTRACTS.Unitroller, + signature: "_setForcedLiquidation(address,bool)", + action: "swap", + grantTo: "guardian1", + }, + { + target: CONTRACTS.Unitroller, + signature: "_setForcedLiquidationForUser(address,address,bool)", + action: "swap", + grantTo: "guardian1", + }, + { target: CONTRACTS.XVSVaultProxy, signature: "resume()", action: "revoke" }, + { target: CONTRACTS.ChainlinkOracle, signature: "setDirectPrice(address,uint256)", action: "revoke" }, + { target: CONTRACTS.ChainlinkOracle, signature: "setTokenConfig(TokenConfig)", action: "revoke" }, + { target: CONTRACTS.ChainlinkOracle, signature: "setUnderlyingPrice(address,uint256)", action: "revoke" }, + { + target: CONTRACTS.DeviationBoundedOracle, + signature: "setThresholds(address,uint256,uint256)", + action: "grant", + grantTo: "guardian1", + }, + { target: CONTRACTS.PythOracle, signature: "setTokenConfig(TokenConfig)", action: "revoke" }, + { target: CONTRACTS.RedStoneOracle, signature: "setDirectPrice(address,uint256)", action: "revoke" }, + { target: CONTRACTS.RedStoneOracle, signature: "setTokenConfig(TokenConfig)", action: "revoke" }, + { target: CONTRACTS.ResilientOracle, signature: "setTokenConfig(TokenConfig)", action: "revoke" }, + { target: CONTRACTS.USDTChainlinkOracle, signature: "setDirectPrice(address,uint256)", action: "revoke" }, + { target: CONTRACTS.USDTChainlinkOracle, signature: "setTokenConfig(TokenConfig)", action: "revoke" }, + { + target: CONTRACTS.ProtocolShareReserve, + signature: "addOrUpdateDistributionConfigs(DistributionConfig[])", + action: "revoke", + }, + { + target: CONTRACTS.RelativePositionManager, + signature: "executePositionAccountCall(address,address[],bytes[])", + action: "revoke", + }, + { target: CONTRACTS.SentinelOracle, signature: "setDirectPrice(address,uint256)", action: "revoke" }, + { target: CONTRACTS.SentinelOracle, signature: "setTokenOracleConfig(address,address)", action: "revoke" }, + { target: CONTRACTS.XVSBridgeAdmin, signature: "setWhitelist(address,bool)", action: "swap", grantTo: "guardian1" }, + { target: CONTRACTS.XVSBridgeAdmin, signature: "setMaxDailyLimit(uint16,uint256)", action: "revoke" }, + { target: CONTRACTS.XVSBridgeAdmin, signature: "setMaxDailyReceiveLimit(uint16,uint256)", action: "revoke" }, + { + target: CONTRACTS.XVSBridgeAdmin, + signature: "setMaxSingleReceiveTransactionLimit(uint16,uint256)", + action: "revoke", + }, + { target: CONTRACTS.XVSBridgeAdmin, signature: "setMaxSingleTransactionLimit(uint16,uint256)", action: "revoke" }, + { target: CONTRACTS.XVSBridgeAdmin, signature: "unpause()", action: "revoke" }, + { + target: CONTRACTS.InstitutionalVaultControllerProxy, + signature: "setLiquidationThreshold(address,uint256)", + action: "swap", + grantTo: "guardian1", + }, + { target: CONTRACTS.InstitutionalVaultControllerProxy, signature: "sweep(address,address)", action: "revoke" }, +]; + +// setCollateralFactor on the isolated-pools wildcard target is revoked from Critical via a direct +// ACM.revokeRole on the legacy BNB ACM (the aggregator cannot clear wildcard grants there — see +// legacyWildcardRole in utils/commands.ts). +export const BNB_ACTION_LEGACY_WILDCARD_REVOKES: { signature: string; account: string }[] = [ + { signature: "setCollateralFactor(address,uint256,uint256)", account: BNB_CRITICAL }, +]; + +// =================================================================================================== +// Remote chains — all Critical revokes +// =================================================================================================== +export type RemoteChain = + | "ethereum" + | "arbitrumone" + | "basemainnet" + | "zksyncmainnet" + | "opmainnet" + | "unichainmainnet" + | "opbnbmainnet"; + +export const REMOTE_CHAINS: RemoteChain[] = [ + "ethereum", + "arbitrumone", + "basemainnet", + "zksyncmainnet", + "opmainnet", + "unichainmainnet", + "opbnbmainnet", +]; + +export const LZ_CHAIN_ID: Record = { + ethereum: LzChainId.ethereum, + arbitrumone: LzChainId.arbitrumone, + basemainnet: LzChainId.basemainnet, + zksyncmainnet: LzChainId.zksyncmainnet, + opmainnet: LzChainId.opmainnet, + unichainmainnet: LzChainId.unichainmainnet, + opbnbmainnet: LzChainId.opbnbmainnet, +}; + +const addressesOf = (chain: RemoteChain) => NETWORK_ADDRESSES[chain] as Record; + +// Resolve a contract key to its address on a chain. On Arbitrum/OP the "CHAINLINK_ORACLE" key is the +// SequencerChainlinkOracle adapter. +export const remoteAddr = (chain: RemoteChain, c: string): string => { + switch (c) { + case "WILDCARD": + return ZERO; + case "ResilientOracle": + return addressesOf(chain).RESILIENT_ORACLE; + case "ChainlinkOracle": + return addressesOf(chain).CHAINLINK_ORACLE; + case "RedStoneOracle": + return addressesOf(chain).REDSTONE_ORACLE; + case "SequencerChainlinkOracle": + return addressesOf(chain).CHAINLINK_ORACLE; + case "SentinelOracle": + return SENTINEL_ORACLE[chain]!; + case "XVSBridgeAdmin": + return XVS_BRIDGE_ADMIN[chain]; + case "OmnichainExecutorOwner": + return OMNICHAIN_EXECUTOR_OWNER[chain]; + default: + throw new Error(`unknown remote contract key ${c}`); + } +}; + +// One revoke-from-Critical row. contract = contract key resolved per-chain by remoteAddr. +export interface RemoteRow { + signature: string; + contract: string; +} + +// Revoke rows written out explicitly per chain. Each block is ordered `common` (the 5 rows every remote +// shares — repeated in every block by design, for readability) then `chain-specific`. Editing here is the +// review surface; remoteRowsFor() just resolves each contract key to its address. +export const REMOTE_ROWS_BY_CHAIN: Record = { + ethereum: [ + // ── common to all remotes ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle" }, + { signature: "setCollateralFactor(address,uint256,uint256)", contract: "WILDCARD" }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner" }, + { signature: "setMaxDailyReceiveLimit(uint256)", contract: "OmnichainExecutorOwner" }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin" }, + // ── chain-specific ── + { signature: "setDirectPrice(address,uint256)", contract: "ChainlinkOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "ChainlinkOracle" }, + { signature: "setDirectPrice(address,uint256)", contract: "RedStoneOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "RedStoneOracle" }, + { signature: "setDirectPrice(address,uint256)", contract: "SentinelOracle" }, + { signature: "setTokenOracleConfig(address,address)", contract: "SentinelOracle" }, + ], + arbitrumone: [ + // ── common to all remotes ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle" }, + { signature: "setCollateralFactor(address,uint256,uint256)", contract: "WILDCARD" }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner" }, + { signature: "setMaxDailyReceiveLimit(uint256)", contract: "OmnichainExecutorOwner" }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin" }, + // ── chain-specific ── + { signature: "setDirectPrice(address,uint256)", contract: "RedStoneOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "RedStoneOracle" }, + { signature: "setDirectPrice(address,uint256)", contract: "SequencerChainlinkOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "SequencerChainlinkOracle" }, + { signature: "setDirectPrice(address,uint256)", contract: "SentinelOracle" }, + { signature: "setTokenOracleConfig(address,address)", contract: "SentinelOracle" }, + ], + basemainnet: [ + // ── common to all remotes ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle" }, + { signature: "setCollateralFactor(address,uint256,uint256)", contract: "WILDCARD" }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner" }, + { signature: "setMaxDailyReceiveLimit(uint256)", contract: "OmnichainExecutorOwner" }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin" }, + // ── chain-specific ── + { signature: "setDirectPrice(address,uint256)", contract: "ChainlinkOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "ChainlinkOracle" }, + { signature: "setDirectPrice(address,uint256)", contract: "RedStoneOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "RedStoneOracle" }, + { signature: "setDirectPrice(address,uint256)", contract: "SentinelOracle" }, + { signature: "setTokenOracleConfig(address,address)", contract: "SentinelOracle" }, + ], + zksyncmainnet: [ + // ── common to all remotes ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle" }, + { signature: "setCollateralFactor(address,uint256,uint256)", contract: "WILDCARD" }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner" }, + { signature: "setMaxDailyReceiveLimit(uint256)", contract: "OmnichainExecutorOwner" }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin" }, + // ── chain-specific ── + { signature: "setDirectPrice(address,uint256)", contract: "ChainlinkOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "ChainlinkOracle" }, + { signature: "setDirectPrice(address,uint256)", contract: "RedStoneOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "RedStoneOracle" }, + ], + opmainnet: [ + // ── common to all remotes ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle" }, + { signature: "setCollateralFactor(address,uint256,uint256)", contract: "WILDCARD" }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner" }, + { signature: "setMaxDailyReceiveLimit(uint256)", contract: "OmnichainExecutorOwner" }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin" }, + // ── chain-specific ── + { signature: "setDirectPrice(address,uint256)", contract: "RedStoneOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "RedStoneOracle" }, + { signature: "setDirectPrice(address,uint256)", contract: "SequencerChainlinkOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "SequencerChainlinkOracle" }, + ], + unichainmainnet: [ + // ── common to all remotes ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle" }, + { signature: "setCollateralFactor(address,uint256,uint256)", contract: "WILDCARD" }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner" }, + { signature: "setMaxDailyReceiveLimit(uint256)", contract: "OmnichainExecutorOwner" }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin" }, + // ── chain-specific ── + { signature: "setDirectPrice(address,uint256)", contract: "RedStoneOracle" }, + { signature: "setTokenConfig(TokenConfig)", contract: "RedStoneOracle" }, + ], + opbnbmainnet: [ + // ── common to all remotes (no chain-specific rows) ── + { signature: "setTokenConfig(TokenConfig)", contract: "ResilientOracle" }, + { signature: "setCollateralFactor(address,uint256,uint256)", contract: "WILDCARD" }, + { signature: "addTimelocks(address[])", contract: "OmnichainExecutorOwner" }, + { signature: "setMaxDailyReceiveLimit(uint256)", contract: "OmnichainExecutorOwner" }, + { signature: "setWhitelist(address,bool)", contract: "XVSBridgeAdmin" }, + ], +}; + +// Rows applicable to one chain, with resolved target address. +export const remoteRowsFor = (chain: RemoteChain) => + REMOTE_ROWS_BY_CHAIN[chain].map(r => ({ + signature: r.signature, + target: remoteAddr(chain, r.contract), + })); diff --git a/vips/vip-665/data/noChangeRows.ts b/vips/vip-665/data/noChangeRows.ts deleted file mode 100644 index 75cdc2ad5..000000000 --- a/vips/vip-665/data/noChangeRows.ts +++ /dev/null @@ -1,1682 +0,0 @@ -// VIP-665 — BNB Chain permissions the plan leaves untouched ("No change"), extracted from actionPlan.ts -// so the action plan shows only real changes. These rows carry no action and generate no commands; the -// simulation reads them to assert Critical and the listed Guardians retain each capability after execution. -import type { BnbRow } from "./actionPlan"; -import { BNB_CONTRACTS as CONTRACTS } from "./addresses"; - -export const BNB_NO_CHANGE_ROWS: BnbRow[] = [ - { - signature: "addToAllowlist(address,address)", - target: CONTRACTS.Liquidator, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "removeFromAllowlist(address,address)", - target: CONTRACTS.Liquidator, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "restrictLiquidation(address)", - target: CONTRACTS.Liquidator, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setTreasuryPercent(uint256)", - target: CONTRACTS.Liquidator, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "unrestrictLiquidation(address)", - target: CONTRACTS.Liquidator, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseForceVAILiquidate()", - target: CONTRACTS.Liquidator, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeForceVAILiquidate()", - target: CONTRACTS.Liquidator, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setVAIMintCap(uint256)", - target: CONTRACTS.PegStability_USDT, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setFeeIn(uint256)", - target: CONTRACTS.PegStability_USDT, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setFeeOut(uint256)", - target: CONTRACTS.PegStability_USDT, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.PegStability_USDT, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resume()", - target: CONTRACTS.PegStability_USDT, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "addMarket(address,address,uint256,uint256)", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "addMarket(address,uint256,uint256)", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "burn(address)", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "issue(bool,address[])", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateMultipliers(address,uint256,uint256)", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setLimit(uint256,uint256)", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMaxLoopsLimit(uint256)", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setStakedAt(address[],uint256[])", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateAlpha(uint128,uint128)", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "togglePause()", - target: CONTRACTS.Prime, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMaxLoopsLimit(uint256)", - target: CONTRACTS.PrimeLiquidityProvider, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMaxTokensDistributionSpeed(address[],uint256[])", - target: CONTRACTS.PrimeLiquidityProvider, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setTokensDistributionSpeed(address[],uint256[])", - target: CONTRACTS.PrimeLiquidityProvider, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseFundsTransfer()", - target: CONTRACTS.PrimeLiquidityProvider, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeFundsTransfer()", - target: CONTRACTS.PrimeLiquidityProvider, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.PrimeV2, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "unpause()", - target: CONTRACTS.PrimeV2, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "addPoolMarkets(uint96[],address[])", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "createPool(string)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "seizeVenus(address[],address)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "seizeVenus(address[],address,address[])", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removePoolMarket(uint96,address)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setAllowCorePoolFallback(uint96,bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setFlashLoanPaused(bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setPoolActive(uint96,bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setPoolLabel(uint96,string)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "unlistMarket(address)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "_setActionsPaused(address[],uint8[],bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "_setProtocolPaused(bool)", - target: CONTRACTS.Unitroller, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setBaseRate(uint256)", - target: CONTRACTS.VaiUnitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setFloatRate(uint256)", - target: CONTRACTS.VaiUnitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMintCap(uint256)", - target: CONTRACTS.VaiUnitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "toggleOnlyPrimeHolderMint()", - target: CONTRACTS.VaiUnitroller, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.VAIVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resume()", - target: CONTRACTS.VAIVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setInterestRateModel(address)", - target: CONTRACTS.VBNBAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.VRTVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resume()", - target: CONTRACTS.VRTVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setRewardAmountPerBlockOrSecond(address,uint256)", - target: CONTRACTS.XVSVaultProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.XVSVaultProxy, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMaxStalePeriod(string,uint256)", - target: CONTRACTS.BinanceOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "none", - }, - { - signature: "setSymbolOverride(string,string)", - target: CONTRACTS.BinanceOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "none", - }, - { - signature: "setTokenConfig((address,uint64,uint256,uint256,bool,bool))", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setTokenConfigs((address,uint64,uint256,uint256,bool,bool)[])", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateMaxPrice(address,uint128)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "updateMinPrice(address,uint128)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setAssetBoundedPricingEnabled(address,bool)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setCachingEnabled(address,bool)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setCooldownPeriod(address,uint64)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "syncPriceBoundsAndProtections((address,uint8,uint256)[])", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "exitProtectionMode(address)", - target: CONTRACTS.DeviationBoundedOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.ResilientOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "none", - }, - { - signature: "unpause()", - target: CONTRACTS.ResilientOracle, - critical: true, - guardian1: false, - guardian2: false, - guardian3: true, - action: "none", - }, - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.BTCBPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.BTCBPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.BTCBPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.BTCBPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "addTokenConverter(address)", - target: CONTRACTS.ConverterNetwork, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removeTokenConverter(address)", - target: CONTRACTS.ConverterNetwork, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.ETHPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.ETHPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.ETHPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.ETHPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "removeDistributionConfig(Schema,address)", - target: CONTRACTS.ProtocolShareReserve, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setPoolsAssetsDirectTransfer(address[],address[][],bool[][])", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.RiskFundConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.RiskFundV2, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.USDCPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.USDCPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.USDCPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.USDCPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.USDTPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.USDTPrimeConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.USDTPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.USDTPrimeConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.WBNBBurnConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.WBNBBurnConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.WBNBBurnConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.WBNBBurnConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setConversionConfig(address,address,ConversionConfig)", - target: CONTRACTS.XVSVaultConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinAmountToConvert(uint256)", - target: CONTRACTS.XVSVaultConverter, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseConversion()", - target: CONTRACTS.XVSVaultConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeConversion()", - target: CONTRACTS.XVSVaultConverter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "fundXVSVault(uint256)", - target: CONTRACTS.XVSVaultTreasury, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_DeFi, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_GameFi, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_LiquidStakedBNB, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_Stablecoins, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setForcedLiquidation(address,bool)", - target: CONTRACTS.Comptroller_Tron, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateIncentiveBps(uint256)", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateMinimumPoolBadDebt(uint256)", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateNextBidderBlockLimit(uint256)", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateWaitForFirstBidder(uint256)", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pauseAuctions()", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resumeAuctions()", - target: CONTRACTS.Shortfall, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setTokenConfig(address,(uint8,bool))", - target: CONTRACTS.DeviationSentinel, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resetMarketState(address)", - target: CONTRACTS.DeviationSentinel, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setTokenMonitoringEnabled(address,bool)", - target: CONTRACTS.DeviationSentinel, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setTrustedKeeper(address,bool)", - target: CONTRACTS.DeviationSentinel, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "decreaseCF(address,uint256)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "decreaseCF(address,uint96,uint256)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "revokeFlashLoanAccess(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMarketBorrowCaps(address[],uint256[])", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMarketSupplyCaps(address[],uint256[])", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "disablePoolBorrow(uint96,address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseActions(address[],uint8[])", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseBorrow(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseFlashLoan()", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseRedeem(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseSupply(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pauseTransfer(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resetBorrowCapSnapshot(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resetCFSnapshot(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "resetSupplyCapSnapshot(address)", - target: CONTRACTS.EBrake, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMarketConfig(address,(uint256,uint256,bool))", - target: CONTRACTS.Executor, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setPoolConfig(address,address)", - target: CONTRACTS.PancakeSwapOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.PendlePTVaultAdapter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "unpause()", - target: CONTRACTS.PendlePTVaultAdapter, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "addDSAVToken(address)", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setDSAVTokenActive(uint8,bool)", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setProportionalCloseTolerance(uint256)", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "completePause()", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "completeUnpause()", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "partialPause()", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "partialUnpause()", - target: CONTRACTS.RelativePositionManager, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setPoolConfig(address,address)", - target: CONTRACTS.UniswapOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "addAuthorizedBatchers(address[])", - target: CONTRACTS.AuxiliaryCommandsAggregator, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "executeBatch(uint256)", - target: CONTRACTS.AuxiliaryCommandsAggregator, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removeAuthorizedBatchers(address[])", - target: CONTRACTS.AuxiliaryCommandsAggregator, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "execute(uint16,bytes,bytes,address)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "retryExecute(uint256,uint16,bytes,bytes,address,uint256)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setConfig(uint16,uint16,uint256,bytes)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removeTrustedRemote(uint16)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setMaxDailyLimit(uint16,uint256)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setSendVersion(uint16)", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "unpause()", - target: CONTRACTS.OmnichainProposalSender, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "removeAuthorizedSender(address)", - target: CONTRACTS.RiskOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setUpdateTypeActive(string,bool)", - target: CONTRACTS.RiskOracle, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setWhitelistedExecutor(address,bool)", - target: CONTRACTS.RiskStewardReceiver, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setConfigActive(string,bool)", - target: CONTRACTS.RiskStewardReceiver, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setPaused(bool)", - target: CONTRACTS.RiskStewardReceiver, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "setConfig(uint16,uint16,uint256,bytes)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "dropFailedMessage(uint16,bytes,uint64)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "forceResumeReceive(uint16,bytes)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "removeTrustedRemote(uint16)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setMinDstGas(uint16,uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setPayloadSizeLimit(uint16,uint256)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setReceiveVersion(uint16)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setSendVersion(uint16)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "updateSendAndCallEnabled(bool)", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "pause()", - target: CONTRACTS.XVSBridgeAdmin, - critical: true, - guardian1: false, - guardian2: true, - guardian3: false, - action: "none", - }, - { - signature: "createVault(VaultConfig,InstitutionalConfig,RiskConfig,string,string,string)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setLiquidationIncentive(address,uint256)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setVaultImplementation(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "approvePositionTransfer(address,address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "cancelVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "closeVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "openVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "revokePositionTransfer(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setInstitutionName(address,string)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setInstitutionNameOverride(address,string)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setLatePenaltyRate(address,uint256)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "completePauseVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "partialPauseVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "unpauseVault(address)", - target: CONTRACTS.InstitutionalVaultControllerProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setCloseFactor(uint256)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "sweepProtocolShareToReserve(address)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setLiquidatorWhitelist(address,bool)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setProtocolLiquidationShare(uint256)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: false, - guardian2: false, - guardian3: false, - action: "none", - }, - { - signature: "setSettlerWhitelist(address,bool)", - target: CONTRACTS.LiquidationAdapterProxy, - critical: true, - guardian1: true, - guardian2: false, - guardian3: false, - action: "none", - }, -]; diff --git a/vips/vip-665/utils/commands.ts b/vips/vip-665/utils/commands.ts index cc09571c9..adb15d89d 100644 --- a/vips/vip-665/utils/commands.ts +++ b/vips/vip-665/utils/commands.ts @@ -3,12 +3,12 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { Command } from "src/types"; import { + BNB_ACTIONS, BNB_ACTION_LEGACY_WILDCARD_REVOKES, - BNB_ROWS, REMOTE_CHAINS, RemoteChain, remoteRowsFor, -} from "../data/actionPlan"; +} from "../data/criticalChanges"; import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, REMOTE_ACM } from "../data/addresses"; import { CLEANUP_LEGACY_WILDCARD_REVOKES, @@ -74,7 +74,7 @@ export interface Permission { // have no Guardian swaps/grants. export const buildGrantPermissions = (chain: Chain): Permission[] => { if (chain !== "bscmainnet") return syncCashGrants(chain); - return BNB_ROWS.filter(r => r.action === "swap" || r.action === "grant").map(r => ({ + return BNB_ACTIONS.filter(r => r.action === "swap" || r.action === "grant").map(r => ({ contractAddress: r.target, functionSig: r.signature, account: BNB_GUARDIANS[r.grantTo ?? "guardian1"], @@ -101,7 +101,7 @@ const redundantRevokes = (chain: Chain): Permission[] => export const buildRevokePermissions = (chain: Chain): Permission[] => { let base: Permission[]; if (chain === "bscmainnet") { - base = BNB_ROWS.filter(r => r.action === "revoke" || r.action === "swap").map(r => ({ + base = BNB_ACTIONS.filter(r => r.action === "revoke" || r.action === "swap").map(r => ({ contractAddress: r.target, functionSig: r.signature, account: BNB_CRITICAL, From f00785550129bd03f41a57270834ab4e8fa700c6 Mon Sep 17 00:00:00 2001 From: GitGuru7 Date: Wed, 15 Jul 2026 13:37:08 +0530 Subject: [PATCH 11/11] refactor: build permissions by critical/cleanup category and group sims to match --- simulations/vip-665/bscmainnet.ts | 180 +++++++++++++++---------- simulations/vip-665/utils/remoteSim.ts | 129 ++++++++++-------- vips/vip-665/utils/commands.ts | 110 +++++++++------ 3 files changed, 257 insertions(+), 162 deletions(-) diff --git a/simulations/vip-665/bscmainnet.ts b/simulations/vip-665/bscmainnet.ts index 6308ee59b..1ef5b6cf2 100644 --- a/simulations/vip-665/bscmainnet.ts +++ b/simulations/vip-665/bscmainnet.ts @@ -7,12 +7,11 @@ import { expectEvents, initMainnetUser } from "src/utils"; import { forking, testVip } from "src/vip-framework"; import vip665, { EXPECTED_ROLE_EVENTS } from "../../vips/vip-665/bscmainnet"; -import { BNB_ACTIONS } from "../../vips/vip-665/data/criticalChanges"; import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, ZERO } from "../../vips/vip-665/data/addresses"; -import { REDUNDANT_REVOKES, STALE_ROWS } from "../../vips/vip-665/data/cleanup"; +import { CLEANUP_LEGACY_WILDCARD_REVOKES, REDUNDANT_REVOKES, STALE_ROWS } from "../../vips/vip-665/data/cleanup"; +import { BNB_ACTIONS, BNB_ACTION_LEGACY_WILDCARD_REVOKES } from "../../vips/vip-665/data/criticalChanges"; import { AGGREGATOR, - BNB_LEGACY_WILDCARD_REVOKES, buildGrantPermissions, buildRevokePermissions, legacyWildcardRole, @@ -31,12 +30,12 @@ const vUSDT = "0xfD5840Cd36d94D7229439859C0112a4185BC0255"; const role = (at: string, fn: string) => ethers.utils.solidityKeccak256(["address", "string"], [at, fn]); -// One bucket per action so each category is asserted explicitly and guarded non-empty (a data regression -// that empties a category fails loudly instead of passing vacuously). +// Critical maintenance rows, bucketed per action so each category is asserted explicitly and guarded +// non-empty (a data regression that empties a category fails loudly instead of passing vacuously). const REVOKE = BNB_ACTIONS.filter(row => row.action === "revoke"); const SWAP = BNB_ACTIONS.filter(row => row.action === "swap"); const GRANT = BNB_ACTIONS.filter(row => row.action === "grant"); -// Redundant (wildcard-shadowed) target-specific grants revoked as behavior-preserving cleanup. +// Cleanup: redundant (wildcard-shadowed) target-specific grants revoked as behavior-preserving cleanup. const REDUNDANT = REDUNDANT_REVOKES.bscmainnet; forking(FORK_BLOCK, async () => { @@ -56,32 +55,15 @@ forking(FORK_BLOCK, async () => { ); }); - describe("VIP-665 pre-execution permissions (bscmainnet)", () => { - it("the action plan covers every category with the expected row counts", () => { + // ================================================================================================== + // Critical maintenance — reduce CriticalTimelock privileges (revoke / swap / grant + legacy wildcard). + // ================================================================================================== + describe("VIP-665 Critical maintenance — pre-execution (bscmainnet)", () => { + it("covers the expected revoke / swap / grant counts", () => { expect(REVOKE.length, "revoke rows").to.equal(26); expect(SWAP.length, "swap rows").to.equal(4); expect(GRANT.length, "grant rows").to.equal(1); - expect(STALE_ROWS.length, "stale (dangling cleanup) rows").to.equal(8); - expect(BNB_LEGACY_WILDCARD_REVOKES.length, "legacy wildcard revokes").to.equal(3); - expect(REDUNDANT.length, "redundant revokes").to.equal(15); - }); - - it("legacy wildcard: each grantee currently holds the 32-byte wildcard role", async () => { - for (const r of BNB_LEGACY_WILDCARD_REVOKES) { - expect( - await acm().hasRole(legacyWildcardRole(r.signature), r.account), - `pre legacy wildcard ${r.signature} ${r.account}`, - ).to.be.true; - } - }); - - it("redundant: each target-specific grant is currently held by its account", async () => { - for (const r of REDUNDANT) { - expect( - await acm().hasRole(role(r.contract, r.signature), r.account), - `pre redundant ${r.signature}@${r.contract} ${r.account}`, - ).to.be.true; - } + expect(BNB_ACTION_LEGACY_WILDCARD_REVOKES.length, "critical legacy wildcard revokes").to.equal(1); }); it("revoke: Critical currently holds every permission to be revoked", async () => { @@ -103,10 +85,53 @@ forking(FORK_BLOCK, async () => { } }); - it("stale (dangling cleanup): every listed grantee currently holds the dangling permission", async () => { - for (const staleRow of STALE_ROWS) - for (const who of staleRow.revokeFrom) - expect(await holds(who, staleRow), `pre stale ${staleRow.signature}@${staleRow.target} ${who}`).to.be.true; + it("legacy wildcard: Critical currently holds the 32-byte wildcard role", async () => { + for (const r of BNB_ACTION_LEGACY_WILDCARD_REVOKES) + expect( + await acm().hasRole(legacyWildcardRole(r.signature), r.account), + `pre legacy wildcard ${r.signature} ${r.account}`, + ).to.be.true; + }); + }); + + // ================================================================================================== + // Cleanup — ACM maintenance: stale/dangling grants, redundant wildcard-shadowed grants, and the retired + // risk-steward legacy-wildcard cap powers. (BNB has no syncCash normalization — that is remotes only.) + // ================================================================================================== + describe("VIP-665 Cleanup — pre-execution (bscmainnet)", () => { + describe("stale (dangling grants)", () => { + it("covers the expected count", () => expect(STALE_ROWS.length, "stale rows").to.equal(8)); + + it("every listed grantee currently holds the dangling permission", async () => { + for (const staleRow of STALE_ROWS) + for (const who of staleRow.revokeFrom) + expect(await holds(who, staleRow), `pre stale ${staleRow.signature}@${staleRow.target} ${who}`).to.be.true; + }); + }); + + describe("redundant (wildcard-shadowed grants)", () => { + it("covers the expected count", () => expect(REDUNDANT.length, "redundant rows").to.equal(15)); + + it("each target-specific grant is currently held by its account", async () => { + for (const r of REDUNDANT) + expect( + await acm().hasRole(role(r.contract, r.signature), r.account), + `pre redundant ${r.signature}@${r.contract} ${r.account}`, + ).to.be.true; + }); + }); + + describe("legacy wildcard (retired risk-steward caps)", () => { + it("covers the expected count", () => + expect(CLEANUP_LEGACY_WILDCARD_REVOKES.length, "cleanup legacy wildcard revokes").to.equal(2)); + + it("each grantee currently holds the 32-byte wildcard role", async () => { + for (const r of CLEANUP_LEGACY_WILDCARD_REVOKES) + expect( + await acm().hasRole(legacyWildcardRole(r.signature), r.account), + `pre legacy wildcard ${r.signature} ${r.account}`, + ).to.be.true; + }); }); }); @@ -128,13 +153,16 @@ forking(FORK_BLOCK, async () => { }, }); - describe("VIP-665 post-execution permissions (bscmainnet)", () => { + // ================================================================================================== + // Critical maintenance — post-execution. + // ================================================================================================== + describe("VIP-665 Critical maintenance — post-execution (bscmainnet)", () => { it("revoke: the CriticalTimelock lost each target-specific grant", async () => { for (const row of REVOKE) expect(await holds(BNB_CRITICAL, row), `post critical ${row.signature}@${row.target}`).to.be.false; }); - it("behavioral: the CriticalTimelock can no longer call any revoked function", async () => { + it("revoke behavioral: the CriticalTimelock can no longer call any revoked function", async () => { for (const row of REVOKE) expect( await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), @@ -156,45 +184,15 @@ forking(FORK_BLOCK, async () => { } }); - it("stale (dangling cleanup): every listed grantee lost the dangling permission", async () => { - for (const staleRow of STALE_ROWS) - for (const who of staleRow.revokeFrom) - expect(await holds(who, staleRow), `post stale ${staleRow.signature}@${staleRow.target} ${who}`).to.be.false; - }); - - it("legacy wildcard: each grantee lost the 32-byte wildcard role", async () => { - for (const r of BNB_LEGACY_WILDCARD_REVOKES) { + it("legacy wildcard: Critical lost the 32-byte wildcard role", async () => { + for (const r of BNB_ACTION_LEGACY_WILDCARD_REVOKES) expect( await acm().hasRole(legacyWildcardRole(r.signature), r.account), `post legacy wildcard ${r.signature} ${r.account}`, ).to.be.false; - } - }); - - it("redundant: each target-specific grant was revoked", async () => { - for (const r of REDUNDANT) { - expect( - await acm().hasRole(role(r.contract, r.signature), r.account), - `post redundant ${r.signature}@${r.contract} ${r.account}`, - ).to.be.false; - } - }); - - it("redundant behavioral: each account can still call its function via the surviving wildcard", async () => { - for (const r of REDUNDANT) { - // setCollateralFactor from Critical is the single case whose wildcard is also revoked, so its power is - // fully removed (asserted in the revoke test). Every other redundant revoke is behavior-preserving. - if (r.signature === "setCollateralFactor(address,uint256,uint256)" && r.account === BNB_CRITICAL) continue; - expect( - await acm().isAllowedToCall(r.account, r.signature, { from: r.contract }), - `still callable ${r.signature}@${r.contract} ${r.account}`, - ).to.be.true; - } }); - }); - describe("Post-VIP behavioral: swapped permissions follow the ACM authorization checks", () => { - it("every swapped function is allowed for the target Guardian and denied for Critical", async () => { + it("swap behavioral: every swapped function is allowed for the target Guardian and denied for Critical", async () => { for (const row of SWAP.filter(swapRow => swapRow.target !== ZERO)) { expect( await acm().isAllowedToCall(BNB_CRITICAL, row.signature, { from: row.target }), @@ -217,4 +215,50 @@ forking(FORK_BLOCK, async () => { await expect(asCritical._setForcedLiquidation(vUSDT, true)).to.be.reverted; }); }); + + // ================================================================================================== + // Cleanup — post-execution. + // ================================================================================================== + describe("VIP-665 Cleanup — post-execution (bscmainnet)", () => { + describe("stale (dangling grants)", () => { + it("every listed grantee lost the dangling permission", async () => { + for (const staleRow of STALE_ROWS) + for (const who of staleRow.revokeFrom) + expect(await holds(who, staleRow), `post stale ${staleRow.signature}@${staleRow.target} ${who}`).to.be + .false; + }); + }); + + describe("redundant (wildcard-shadowed grants)", () => { + it("each target-specific grant was revoked", async () => { + for (const r of REDUNDANT) + expect( + await acm().hasRole(role(r.contract, r.signature), r.account), + `post redundant ${r.signature}@${r.contract} ${r.account}`, + ).to.be.false; + }); + + it("behavioral: each account can still call its function via the surviving wildcard", async () => { + for (const r of REDUNDANT) { + // setCollateralFactor from Critical is the single case whose wildcard is also revoked, so its power + // is fully removed (asserted in the critical revoke test). Every other redundant revoke preserves it. + if (r.signature === "setCollateralFactor(address,uint256,uint256)" && r.account === BNB_CRITICAL) continue; + expect( + await acm().isAllowedToCall(r.account, r.signature, { from: r.contract }), + `still callable ${r.signature}@${r.contract} ${r.account}`, + ).to.be.true; + } + }); + }); + + describe("legacy wildcard (retired risk-steward caps)", () => { + it("each grantee lost the 32-byte wildcard role", async () => { + for (const r of CLEANUP_LEGACY_WILDCARD_REVOKES) + expect( + await acm().hasRole(legacyWildcardRole(r.signature), r.account), + `post legacy wildcard ${r.signature} ${r.account}`, + ).to.be.false; + }); + }); + }); }); diff --git a/simulations/vip-665/utils/remoteSim.ts b/simulations/vip-665/utils/remoteSim.ts index 664a34dd3..d7655c47a 100644 --- a/simulations/vip-665/utils/remoteSim.ts +++ b/simulations/vip-665/utils/remoteSim.ts @@ -7,9 +7,9 @@ import { expectEvents, initMainnetUser } from "src/utils"; import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; import vip665, { EXPECTED_ROLE_EVENTS } from "../../../vips/vip-665/bscmainnet"; -import { remoteRowsFor } from "../../../vips/vip-665/data/criticalChanges"; import { REMOTE_ACM, SYNC_CASH_MARKETS, ZERO } from "../../../vips/vip-665/data/addresses"; import { REDUNDANT_REVOKES, SYNC_CASH_SIG } from "../../../vips/vip-665/data/cleanup"; +import { remoteRowsFor } from "../../../vips/vip-665/data/criticalChanges"; import { AGGREGATOR, Chain, buildGrantPermissions, buildRevokePermissions } from "../../../vips/vip-665/utils/commands"; import { seedAggregator } from "../../../vips/vip-665/utils/seed"; import ACCESS_CONTROL_MANAGER_ABI from "../abi/AccessControlManager.json"; @@ -35,38 +35,50 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { await seedAggregator(signer, AGGREGATOR[chain], buildGrantPermissions(chain), buildRevokePermissions(chain)); }); + const acm = () => new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); const rows = remoteRowsFor(chain); const redundant = REDUNDANT_REVOKES[chain]; - describe(`VIP-665 pre-execution permissions (${chain})`, () => { + // ================================================================================================ + // Critical maintenance — reduce CriticalTimelock privileges (remotes revoke only, no grants/swaps). + // ================================================================================================ + describe(`VIP-665 Critical maintenance — pre-execution (${chain})`, () => { it("the plan has at least one revoke row for this chain", () => { expect(rows.length, `revoke rows for ${chain}`).to.be.greaterThan(0); }); - it("redundant: each target-specific grant is currently held by its account", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const r of redundant) - expect( - await acm.hasRole(role(r.contract, r.signature), r.account), - `pre redundant ${r.signature}@${r.contract} ${r.account}`, - ).to.be.true; - }); - it("revoke: Critical currently holds every permission to be revoked", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); for (const row of rows) expect( - await acm.hasRole(role(row.target, row.signature), critical), + await acm().hasRole(role(row.target, row.signature), critical), `pre critical ${row.signature}@${row.target}`, ).to.be.true; }); + }); - it("syncCash: NormalTimelock holds every per-market grant and no wildcard grant yet", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - expect(syncCashMarkets.length, `syncCash markets for ${chain}`).to.be.greaterThan(0); - expect(await acm.hasRole(role(ZERO, SYNC_CASH_SIG), normal), "pre wildcard syncCash").to.be.false; - for (const market of syncCashMarkets) - expect(await acm.hasRole(role(market, SYNC_CASH_SIG), normal), `pre normal syncCash@${market}`).to.be.true; + // ================================================================================================ + // Cleanup — ACM maintenance: syncCash() wildcard normalization and redundant wildcard-shadowed grants. + // (No stale/dangling grants on remotes — that is BNB only.) + // ================================================================================================ + describe(`VIP-665 Cleanup — pre-execution (${chain})`, () => { + describe("syncCash (wildcard normalization)", () => { + it("NormalTimelock holds every per-market grant and no wildcard grant yet", async () => { + expect(syncCashMarkets.length, `syncCash markets for ${chain}`).to.be.greaterThan(0); + expect(await acm().hasRole(role(ZERO, SYNC_CASH_SIG), normal), "pre wildcard syncCash").to.be.false; + for (const market of syncCashMarkets) + expect(await acm().hasRole(role(market, SYNC_CASH_SIG), normal), `pre normal syncCash@${market}`).to.be + .true; + }); + }); + + describe("redundant (wildcard-shadowed grants)", () => { + it("each target-specific grant is currently held by its account", async () => { + for (const r of redundant) + expect( + await acm().hasRole(role(r.contract, r.signature), r.account), + `pre redundant ${r.signature}@${r.contract} ${r.account}`, + ).to.be.true; + }); }); }); @@ -82,58 +94,65 @@ export const runRemoteSim = (chain: RemoteChain, forkBlock: number) => { }, }); - describe(`VIP-665 post-execution permissions (${chain})`, () => { + // ================================================================================================ + // Critical maintenance — post-execution. + // ================================================================================================ + describe(`VIP-665 Critical maintenance — post-execution (${chain})`, () => { it("revoke: Critical lost every revoked permission", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); for (const row of rows) expect( - await acm.hasRole(role(row.target, row.signature), critical), + await acm().hasRole(role(row.target, row.signature), critical), `post critical ${row.signature}@${row.target}`, ).to.be.false; }); - it("redundant: each target-specific grant was revoked", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const r of redundant) - expect( - await acm.hasRole(role(r.contract, r.signature), r.account), - `post redundant ${r.signature}@${r.contract} ${r.account}`, - ).to.be.false; - }); - - it("redundant behavioral: each account can still call the function via the surviving wildcard", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const r of redundant) - expect( - await acm.isAllowedToCall(r.account, r.signature, { from: r.contract }), - `post callable ${r.signature}@${r.contract} ${r.account}`, - ).to.be.true; - }); - - it("behavioral: Critical is no longer allowed to call any revoked function", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + it("revoke behavioral: Critical is no longer allowed to call any revoked function", async () => { for (const row of rows) if (row.target !== ZERO) expect( - await acm.isAllowedToCall(critical, row.signature, { from: row.target }), + await acm().isAllowedToCall(critical, row.signature, { from: row.target }), `crit !allowed ${row.signature}`, ).to.be.false; }); + }); - it("syncCash: NormalTimelock gained the wildcard grant and lost every per-market grant", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - expect(await acm.hasRole(role(ZERO, SYNC_CASH_SIG), normal), "post wildcard syncCash").to.be.true; - for (const market of syncCashMarkets) - expect(await acm.hasRole(role(market, SYNC_CASH_SIG), normal), `post normal syncCash@${market}`).to.be.false; + // ================================================================================================ + // Cleanup — post-execution. + // ================================================================================================ + describe(`VIP-665 Cleanup — post-execution (${chain})`, () => { + describe("syncCash (wildcard normalization)", () => { + it("NormalTimelock gained the wildcard grant and lost every per-market grant", async () => { + expect(await acm().hasRole(role(ZERO, SYNC_CASH_SIG), normal), "post wildcard syncCash").to.be.true; + for (const market of syncCashMarkets) + expect(await acm().hasRole(role(market, SYNC_CASH_SIG), normal), `post normal syncCash@${market}`).to.be + .false; + }); + + it("behavioral: NormalTimelock is still allowed to call syncCash on every market via wildcard", async () => { + for (const market of syncCashMarkets) + expect( + await acm().isAllowedToCall(normal, SYNC_CASH_SIG, { from: market }), + `normal allowed syncCash@${market}`, + ).to.be.true; + }); }); - it("syncCash behavioral: NormalTimelock is still allowed to call syncCash on every market via wildcard", async () => { - const acm = new Contract(REMOTE_ACM[chain], ACCESS_CONTROL_MANAGER_ABI, ethers.provider); - for (const market of syncCashMarkets) - expect( - await acm.isAllowedToCall(normal, SYNC_CASH_SIG, { from: market }), - `normal allowed syncCash@${market}`, - ).to.be.true; + describe("redundant (wildcard-shadowed grants)", () => { + it("each target-specific grant was revoked", async () => { + for (const r of redundant) + expect( + await acm().hasRole(role(r.contract, r.signature), r.account), + `post redundant ${r.signature}@${r.contract} ${r.account}`, + ).to.be.false; + }); + + it("behavioral: each account can still call the function via the surviving wildcard", async () => { + for (const r of redundant) + expect( + await acm().isAllowedToCall(r.account, r.signature, { from: r.contract }), + `post callable ${r.signature}@${r.contract} ${r.account}`, + ).to.be.true; + }); }); }); }); diff --git a/vips/vip-665/utils/commands.ts b/vips/vip-665/utils/commands.ts index adb15d89d..007af806c 100644 --- a/vips/vip-665/utils/commands.ts +++ b/vips/vip-665/utils/commands.ts @@ -2,13 +2,6 @@ import { ethers } from "ethers"; import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { Command } from "src/types"; -import { - BNB_ACTIONS, - BNB_ACTION_LEGACY_WILDCARD_REVOKES, - REMOTE_CHAINS, - RemoteChain, - remoteRowsFor, -} from "../data/criticalChanges"; import { BNB_ACM, BNB_CRITICAL, BNB_GUARDIANS, REMOTE_ACM } from "../data/addresses"; import { CLEANUP_LEGACY_WILDCARD_REVOKES, @@ -18,6 +11,13 @@ import { syncCashGrants, syncCashRevokes, } from "../data/cleanup"; +import { + BNB_ACTIONS, + BNB_ACTION_LEGACY_WILDCARD_REVOKES, + REMOTE_CHAINS, + RemoteChain, + remoteRowsFor, +} from "../data/criticalChanges"; export type Chain = "bscmainnet" | RemoteChain; export const CHAINS: Chain[] = ["bscmainnet", ...REMOTE_CHAINS]; @@ -69,11 +69,12 @@ export interface Permission { account: string; } -// Permissions the aggregator grants on a chain. On BNB: swap → move a function to a Guardian, grant → add a -// Guardian alongside Critical. On remotes: the single wildcard syncCash() grant to NormalTimelock; remotes -// have no Guardian swaps/grants. -export const buildGrantPermissions = (chain: Chain): Permission[] => { - if (chain !== "bscmainnet") return syncCashGrants(chain); +// ==================================================================================================== +// Critical maintenance — the VIP's core intent: reduce CriticalTimelock privileges. +// ==================================================================================================== +// Grants: on BNB a swap/grant action hands the function to a Guardian. Remotes only revoke, so no grants. +export const criticalGrants = (chain: Chain): Permission[] => { + if (chain !== "bscmainnet") return []; return BNB_ACTIONS.filter(r => r.action === "swap" || r.action === "grant").map(r => ({ contractAddress: r.target, functionSig: r.signature, @@ -81,12 +82,32 @@ export const buildGrantPermissions = (chain: Chain): Permission[] => { })); }; -// Key identifying a unique ACM revoke (contract + function + grantee), used to de-duplicate the redundant -// cleanup against the base plan (e.g. Unitroller setCollateralFactor from Critical is in both). -const revokeKey = (p: Permission) => `${p.contractAddress.toLowerCase()}|${p.functionSig}|${p.account.toLowerCase()}`; +// Revokes: on BNB every revoke/swap action drops the function from Critical; on remotes every remote row +// from that chain's Critical. +export const criticalRevokes = (chain: Chain): Permission[] => { + if (chain === "bscmainnet") + return BNB_ACTIONS.filter(r => r.action === "revoke" || r.action === "swap").map(r => ({ + contractAddress: r.target, + functionSig: r.signature, + account: BNB_CRITICAL, + })); + const critical = criticalOf(chain); + return remoteRowsFor(chain).map(r => ({ + contractAddress: r.target, + functionSig: r.signature, + account: critical, + })); +}; -// Redundant target-specific grants to revoke on a chain — shadowed by an identical wildcard grant held by the -// same account, so revoking them is behavior-preserving. +// ==================================================================================================== +// Cleanup — ACM maintenance, independent of the Critical privilege reduction. Three sub-categories: +// syncCash() normalization (remotes), stale/dangling grants (BNB), and redundant wildcard-shadowed grants. +// ==================================================================================================== +// Grants: the single wildcard syncCash() grant to NormalTimelock (remotes only; BNB has no cleanup grant). +export const cleanupGrants = (chain: Chain): Permission[] => (chain === "bscmainnet" ? [] : syncCashGrants(chain)); + +// Redundant target-specific grants — shadowed by an identical wildcard grant held by the same account, so +// revoking them is behavior-preserving. const redundantRevokes = (chain: Chain): Permission[] => REDUNDANT_REVOKES[chain as RedundantChain].map(r => ({ contractAddress: r.contract, @@ -94,32 +115,43 @@ const redundantRevokes = (chain: Chain): Permission[] => account: r.account, })); -// Permissions the aggregator revokes on a chain: revoke/swap rows from Critical on BNB (plus the -// dangling-grant cleanup); on remotes every remote row from that chain's Critical, plus the per-market -// syncCash() grants from NormalTimelock (replaced by the wildcard grant). Finally the redundant -// (wildcard-shadowed) target-specific grants, de-duplicated against everything above. -export const buildRevokePermissions = (chain: Chain): Permission[] => { - let base: Permission[]; +// Revokes: the stale/dangling grants (BNB) or the per-market syncCash() grants (remotes), then the redundant +// grants (all chains). De-duplication against the Critical revokes happens in buildRevokePermissions. +export const cleanupRevokes = (chain: Chain): Permission[] => { + const rows: Permission[] = []; if (chain === "bscmainnet") { - base = BNB_ACTIONS.filter(r => r.action === "revoke" || r.action === "swap").map(r => ({ - contractAddress: r.target, - functionSig: r.signature, - account: BNB_CRITICAL, - })); for (const s of STALE_ROWS) - for (const who of s.revokeFrom) base.push({ contractAddress: s.target, functionSig: s.signature, account: who }); + for (const who of s.revokeFrom) rows.push({ contractAddress: s.target, functionSig: s.signature, account: who }); } else { - const critical = criticalOf(chain); - const criticalRevokes = remoteRowsFor(chain).map(r => ({ - contractAddress: r.target, - functionSig: r.signature, - account: critical, - })); - base = [...criticalRevokes, ...syncCashRevokes(chain)]; + rows.push(...syncCashRevokes(chain)); } - const seen = new Set(base.map(revokeKey)); - const redundant = redundantRevokes(chain).filter(p => !seen.has(revokeKey(p))); - return [...base, ...redundant]; + rows.push(...redundantRevokes(chain)); + return rows; +}; + +// ==================================================================================================== +// Combined — every grant / every revoke for a chain. These are what seed the ACM aggregator. +// ==================================================================================================== +// Key identifying a unique ACM revoke (contract + function + grantee). +const revokeKey = (p: Permission) => `${p.contractAddress.toLowerCase()}|${p.functionSig}|${p.account.toLowerCase()}`; + +// Every grant: Critical maintenance + cleanup. The two never overlap, so no de-duplication needed. +export const buildGrantPermissions = (chain: Chain): Permission[] => [ + ...criticalGrants(chain), + ...cleanupGrants(chain), +]; + +// Every revoke: Critical maintenance + cleanup, then de-duplicated. A redundant revoke can coincide with a +// Critical revoke (e.g. Unitroller.setCollateralFactor from Critical on BNB), and the aggregator must not +// revoke the same (contract, function, account) twice. +export const buildRevokePermissions = (chain: Chain): Permission[] => { + const seen = new Set(); + return [...criticalRevokes(chain), ...cleanupRevokes(chain)].filter(p => { + const k = revokeKey(p); + if (seen.has(k)) return false; + seen.add(k); + return true; + }); }; // BNB legacy-ACM wildcard quirk. The AccessControlManager on bscmainnet derives a wildcard ("any contract")