diff --git a/simulations/vip-664/abi/ACMAggregator.json b/simulations/vip-627/abi/ACMAggregator.json similarity index 100% rename from simulations/vip-664/abi/ACMAggregator.json rename to simulations/vip-627/abi/ACMAggregator.json diff --git a/simulations/vip-664/abi/AccessControlManager.json b/simulations/vip-627/abi/AccessControlManager.json similarity index 100% rename from simulations/vip-664/abi/AccessControlManager.json rename to simulations/vip-627/abi/AccessControlManager.json diff --git a/simulations/vip-627/abi/InstitutionPositionToken.json b/simulations/vip-627/abi/InstitutionPositionToken.json new file mode 100644 index 000000000..a77897421 --- /dev/null +++ b/simulations/vip-627/abi/InstitutionPositionToken.json @@ -0,0 +1,631 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "acceptOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "approveTransfer", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "approvedRecipient", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getApproved", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isApprovedForAll", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "operator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "mint", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nextTokenId", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "ownerOf", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingOwner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "revokeTransferApproval", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "safeTransferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "safeTransferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setApprovalForAll", + "inputs": [ + { + "name": "operator", + "type": "address", + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { + "name": "interfaceId", + "type": "bytes4", + "internalType": "bytes4" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "tokenIdToVault", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "tokenURI", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "vaultToTokenId", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "approved", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ApprovalForAll", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferStarted", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PositionTokenMinted", + "inputs": [ + { + "name": "vault", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "institution", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PositionTransferApproved", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "recipient", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PositionTransferRevoked", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "tokenId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "OwnershipCannotBeRenounced", + "inputs": [] + }, + { + "type": "error", + "name": "TransferNotApproved", + "inputs": [ + { + "name": "tokenId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "ZeroAddress", + "inputs": [] + } +] diff --git a/simulations/vip-664/abi/InstitutionalLoanVault.json b/simulations/vip-627/abi/InstitutionalLoanVault.json similarity index 98% rename from simulations/vip-664/abi/InstitutionalLoanVault.json rename to simulations/vip-627/abi/InstitutionalLoanVault.json index efe35a44d..21b72547f 100644 --- a/simulations/vip-664/abi/InstitutionalLoanVault.json +++ b/simulations/vip-627/abi/InstitutionalLoanVault.json @@ -147,6 +147,13 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "cancelVault", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "claimRaisedFunds", @@ -626,11 +633,6 @@ "type": "uint256", "internalType": "uint256" }, - { - "name": "idealCollateralValuation", - "type": "uint256", - "internalType": "uint256" - }, { "name": "confiscatedMarginRemaining", "type": "uint256", @@ -1748,6 +1750,25 @@ ], "anonymous": false }, + { + "type": "event", + "name": "VaultCancelled", + "inputs": [ + { + "name": "recipient", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "collateralAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, { "type": "event", "name": "VaultClosed", @@ -1963,11 +1984,6 @@ "name": "PartiallyPaused", "inputs": [] }, - { - "type": "error", - "name": "PositionTokenIdNotSet", - "inputs": [] - }, { "type": "error", "name": "SameStateTransition", @@ -1988,11 +2004,6 @@ "name": "WithdrawalWouldBreachLT", "inputs": [] }, - { - "type": "error", - "name": "ZeroAddress", - "inputs": [] - }, { "type": "error", "name": "ZeroRepayAmount", diff --git a/simulations/vip-627/abi/InstitutionalVaultController.json b/simulations/vip-627/abi/InstitutionalVaultController.json new file mode 100644 index 000000000..3622b4807 --- /dev/null +++ b/simulations/vip-627/abi/InstitutionalVaultController.json @@ -0,0 +1,1100 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "MANTISSA_ONE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "MANTISSA_ONE_AND_HALF", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "MAX_APY_BPS", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "acceptOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "acceptPositionTokenOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "accessControlManager", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IAccessControlManagerV8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allVaults", + "inputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "allVaultsLength", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approvePositionTransfer", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "cancelVault", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "closeVault", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "completePauseVault", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "comptroller", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "createVault", + "inputs": [ + { + "name": "_vaultConfig", + "type": "tuple", + "internalType": "struct VaultConfig", + "components": [ + { + "name": "supplyAsset", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "fixedAPY", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "reserveFactor", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minBorrowCap", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxBorrowCap", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minSupplierDeposit", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "openDuration", + "type": "uint40", + "internalType": "uint40" + }, + { + "name": "lockDuration", + "type": "uint40", + "internalType": "uint40" + }, + { + "name": "settlementWindow", + "type": "uint40", + "internalType": "uint40" + } + ] + }, + { + "name": "_instConfig", + "type": "tuple", + "internalType": "struct InstitutionalConfig", + "components": [ + { + "name": "collateralAsset", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "idealCollateralAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "marginRate", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "institutionOperator", + "type": "address", + "internalType": "address" + }, + { + "name": "positionTokenId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "_riskConfig", + "type": "tuple", + "internalType": "struct RiskConfig", + "components": [ + { + "name": "liquidationThreshold", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "liquidationIncentive", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "latePenaltyRate", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "_name", + "type": "string", + "internalType": "string" + }, + { + "name": "_symbol", + "type": "string", + "internalType": "string" + } + ], + "outputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getAggregatedVaultStates", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "tuple[]", + "internalType": "struct VaultStateInfo[]", + "components": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + }, + { + "name": "state", + "type": "uint8", + "internalType": "enum VaultState" + }, + { + "name": "institutionOperator", + "type": "address", + "internalType": "address" + }, + { + "name": "totalRaised", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "outstandingDebt", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "vaultImplementation_", + "type": "address", + "internalType": "address" + }, + { + "name": "oracle_", + "type": "address", + "internalType": "address" + }, + { + "name": "protocolShareReserve_", + "type": "address", + "internalType": "address" + }, + { + "name": "comptroller_", + "type": "address", + "internalType": "address" + }, + { + "name": "treasury_", + "type": "address", + "internalType": "address" + }, + { + "name": "positionToken_", + "type": "address", + "internalType": "address" + }, + { + "name": "acm_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "institutionNonce", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isRegistered", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "liquidationAdapter", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "openVault", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "oracle", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "partialPauseVault", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "pendingOwner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "positionToken", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IInstitutionPositionToken" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "predictVaultAddress", + "inputs": [ + { + "name": "institution", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "protocolShareReserve", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "revokePositionTransfer", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setAccessControlManager", + "inputs": [ + { + "name": "accessControlManager_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setComptroller", + "inputs": [ + { + "name": "comptroller_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLatePenaltyRate", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + }, + { + "name": "newRate", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLiquidationAdapter", + "inputs": [ + { + "name": "adapter", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLiquidationIncentive", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + }, + { + "name": "newLI", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLiquidationThreshold", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + }, + { + "name": "newLT", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setOracle", + "inputs": [ + { + "name": "oracle_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setProtocolShareReserve", + "inputs": [ + { + "name": "psr", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setTreasury", + "inputs": [ + { + "name": "treasury_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setVaultImplementation", + "inputs": [ + { + "name": "impl", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "sweep", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "treasury", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unpauseVault", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "vaultImplementation", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "ComptrollerUpdated", + "inputs": [ + { + "name": "oldComptroller", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newComptroller", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LatePenaltyRateUpdated", + "inputs": [ + { + "name": "vault", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newRate", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidationAdapterUpdated", + "inputs": [ + { + "name": "oldAdapter", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newAdapter", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidationIncentiveUpdated", + "inputs": [ + { + "name": "vault", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newLI", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidationThresholdUpdated", + "inputs": [ + { + "name": "vault", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newLT", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NewAccessControlManager", + "inputs": [ + { + "name": "oldAccessControlManager", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "newAccessControlManager", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OracleUpdated", + "inputs": [ + { + "name": "oldOracle", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOracle", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferStarted", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProtocolShareReserveUpdated", + "inputs": [ + { + "name": "oldPSR", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newPSR", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TreasuryUpdated", + "inputs": [ + { + "name": "oldTreasury", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newTreasury", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "VaultCreated", + "inputs": [ + { + "name": "vault", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "institution", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "VaultImplementationUpdated", + "inputs": [ + { + "name": "oldImpl", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newImpl", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "InvalidAddress", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidConfig", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidLatePenaltyRate", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidLiquidationIncentive", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidLiquidationThreshold", + "inputs": [] + }, + { + "type": "error", + "name": "OwnershipCannotBeRenounced", + "inputs": [] + }, + { + "type": "error", + "name": "Unauthorized", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "calledContract", + "type": "address", + "internalType": "address" + }, + { + "name": "methodSignature", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "VaultNotRegistered", + "inputs": [] + } +] diff --git a/simulations/vip-627/abi/LiquidationAdapter.json b/simulations/vip-627/abi/LiquidationAdapter.json new file mode 100644 index 000000000..c57002d5e --- /dev/null +++ b/simulations/vip-627/abi/LiquidationAdapter.json @@ -0,0 +1,585 @@ +[ + { + "type": "constructor", + "inputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "MANTISSA_ONE", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "acceptOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "accessControlManager", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IAccessControlManagerV8" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "closeFactor", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "vaultController_", + "type": "address", + "internalType": "address" + }, + { + "name": "protocolLiquidationShare_", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "closeFactor_", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "acm_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isWhitelistedLiquidator", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isWhitelistedSettler", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "liquidate", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + }, + { + "name": "repayAmount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "liquidateOverdueVault", + "inputs": [ + { + "name": "vault", + "type": "address", + "internalType": "address" + }, + { + "name": "repayAmount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pendingOwner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "protocolLiquidationShare", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "protocolShareAccrued", + "inputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "setAccessControlManager", + "inputs": [ + { + "name": "accessControlManager_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setCloseFactor", + "inputs": [ + { + "name": "newCF", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLiquidatorWhitelist", + "inputs": [ + { + "name": "liquidator", + "type": "address", + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setProtocolLiquidationShare", + "inputs": [ + { + "name": "share", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setSettlerWhitelist", + "inputs": [ + { + "name": "settler", + "type": "address", + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "internalType": "bool" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "sweepProtocolShareToReserve", + "inputs": [ + { + "name": "collateral", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "vaultController", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "CloseFactorUpdated", + "inputs": [ + { + "name": "oldCloseFactor", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newCloseFactor", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidationCollateralSplit", + "inputs": [ + { + "name": "totalSeized", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "protocolAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "callerAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LiquidatorWhitelistUpdated", + "inputs": [ + { + "name": "liquidator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NewAccessControlManager", + "inputs": [ + { + "name": "oldAccessControlManager", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "newAccessControlManager", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferStarted", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProtocolLiquidationShareUpdated", + "inputs": [ + { + "name": "oldShare", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newShare", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ProtocolShareSweptToReserve", + "inputs": [ + { + "name": "collateral", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SettlerWhitelistUpdated", + "inputs": [ + { + "name": "settler", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "InvalidAddress", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidCloseFactor", + "inputs": [] + }, + { + "type": "error", + "name": "InvalidShare", + "inputs": [] + }, + { + "type": "error", + "name": "NotWhitelistedLiquidator", + "inputs": [] + }, + { + "type": "error", + "name": "NotWhitelistedSettler", + "inputs": [] + }, + { + "type": "error", + "name": "OwnershipCannotBeRenounced", + "inputs": [] + }, + { + "type": "error", + "name": "Unauthorized", + "inputs": [ + { + "name": "sender", + "type": "address", + "internalType": "address" + }, + { + "name": "calledContract", + "type": "address", + "internalType": "address" + }, + { + "name": "methodSignature", + "type": "string", + "internalType": "string" + } + ] + }, + { + "type": "error", + "name": "VaultNotRegistered", + "inputs": [] + }, + { + "type": "error", + "name": "ZeroRepayAmount", + "inputs": [] + } +] diff --git a/simulations/vip-627/abi/ProxyAdmin.json b/simulations/vip-627/abi/ProxyAdmin.json new file mode 100644 index 000000000..b4c51d8df --- /dev/null +++ b/simulations/vip-627/abi/ProxyAdmin.json @@ -0,0 +1,151 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "changeProxyAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + } + ], + "name": "getProxyAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + } + ], + "name": "getProxyImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "upgrade", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "implementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] diff --git a/simulations/vip-627/bscmainnet.ts b/simulations/vip-627/bscmainnet.ts new file mode 100644 index 000000000..d996cc59e --- /dev/null +++ b/simulations/vip-627/bscmainnet.ts @@ -0,0 +1,310 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { parseEther } from "ethers/lib/utils"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents, initMainnetUser } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import vip627, { + ACM_AGGREGATOR, + ACM_AGGREGATOR_INDEX, + DEFAULT_ADMIN_ROLE, + EXPECTED_PERMISSION_GRANTED_EVENTS, + INSTITUTIONAL_VAULT_CONTROLLER, + INSTITUTION_POSITION_TOKEN, + LIQUIDATION_ADAPTER, + LIQUIDATOR_WHITELIST, + NEW_PSR_IMPLEMENTATION, + PERMISSIONS, + PERMISSION_ENTRIES, + PROTOCOL_SHARE_RESERVE, + PROXY_ADMIN, + SETTLER_WHITELIST, +} from "../../vips/vip-627/bscmainnet"; +import ACM_AGGREGATOR_ABI from "./abi/ACMAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import INSTITUTION_POSITION_TOKEN_ABI from "./abi/InstitutionPositionToken.json"; +import INSTITUTIONAL_VAULT_CONTROLLER_ABI from "./abi/InstitutionalVaultController.json"; +import LIQUIDATION_ADAPTER_ABI from "./abi/LiquidationAdapter.json"; +import PROXY_ADMIN_ABI from "./abi/ProxyAdmin.json"; + +const { + NORMAL_TIMELOCK: NORMAL, + FAST_TRACK_TIMELOCK: FAST_TRACK, + CRITICAL_TIMELOCK: CRITICAL, + CRITICAL_GUARDIAN, + ACCESS_CONTROL_MANAGER, +} = NETWORK_ADDRESSES.bscmainnet; + +const FORK_BLOCK = 100701625; + +// To make test names readable. +const LABEL: Record = { + [NORMAL]: "Normal", + [FAST_TRACK]: "FastTrack", + [CRITICAL]: "Critical", + [CRITICAL_GUARDIAN]: "CriticalGuardian", +}; + +const SUPPORTER = "0xe5e62386933b74ea81bfd73a6a6591598e7f8ced"; + +forking(FORK_BLOCK, async () => { + let accessControlManager: Contract; + let controller: Contract; + let liquidationAdapter: Contract; + let positionToken: Contract; + let acmAggregator: Contract; + let proxyAdmin: Contract; + + before(async () => { + accessControlManager = new ethers.Contract(ACCESS_CONTROL_MANAGER, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + controller = new ethers.Contract( + INSTITUTIONAL_VAULT_CONTROLLER, + INSTITUTIONAL_VAULT_CONTROLLER_ABI, + ethers.provider, + ); + liquidationAdapter = new ethers.Contract(LIQUIDATION_ADAPTER, LIQUIDATION_ADAPTER_ABI, ethers.provider); + positionToken = new ethers.Contract(INSTITUTION_POSITION_TOKEN, INSTITUTION_POSITION_TOKEN_ABI, ethers.provider); + acmAggregator = new ethers.Contract(ACM_AGGREGATOR, ACM_AGGREGATOR_ABI, ethers.provider); + proxyAdmin = new ethers.Contract(PROXY_ADMIN, PROXY_ADMIN_ABI, ethers.provider); + }); + + // Contracts deployed and deploy-script state is in place. + describe("Pre-VIP: verify deployments", () => { + it("InstitutionalVaultController proxy should be deployed", async () => { + expect(await ethers.provider.getCode(INSTITUTIONAL_VAULT_CONTROLLER)).to.not.equal("0x"); + }); + + it("LiquidationAdapter proxy should be deployed", async () => { + expect(await ethers.provider.getCode(LIQUIDATION_ADAPTER)).to.not.equal("0x"); + }); + + it("InstitutionPositionToken should be deployed", async () => { + expect(await ethers.provider.getCode(INSTITUTION_POSITION_TOKEN)).to.not.equal("0x"); + }); + + it("InstitutionPositionToken pendingOwner should be the controller proxy", async () => { + expect(await positionToken.pendingOwner()).to.equal(INSTITUTIONAL_VAULT_CONTROLLER); + }); + + it("controller pendingOwner should be Normal timelock", async () => { + expect(await controller.pendingOwner()).to.equal(NORMAL); + }); + + it("liquidationAdapter pendingOwner should be Normal timelock", async () => { + expect(await liquidationAdapter.pendingOwner()).to.equal(NORMAL); + }); + + it("liquidationAdapter protocolLiquidationShare should be 0.5e18", async () => { + expect(await liquidationAdapter.protocolLiquidationShare()).to.equal(parseEther("0.5")); + }); + + it("liquidationAdapter closeFactor should be 0.5e18", async () => { + expect(await liquidationAdapter.closeFactor()).to.equal(parseEther("0.5")); + }); + + it("controller liquidationAdapter should be address(0) before VIP", async () => { + expect(await controller.liquidationAdapter()).to.equal(ethers.constants.AddressZero); + }); + + it("ProtocolShareReserve should not yet point to the new implementation", async () => { + expect(await proxyAdmin.getProxyImplementation(PROTOCOL_SHARE_RESERVE)).to.not.equal(NEW_PSR_IMPLEMENTATION); + }); + }); + + // Permissions are pre-loaded in the Aggregator but not yet applied to the ACM. + describe("Pre-VIP: ACM permissions not yet granted", () => { + it("aggregator should hold the pre-loaded batch at ACM_AGGREGATOR_INDEX", async () => { + for (let i = 0; i < PERMISSIONS.length; i++) { + const stored = await acmAggregator.grantPermissions(ACM_AGGREGATOR_INDEX, i); + expect(stored.contractAddress.toLowerCase()).to.equal(PERMISSIONS[i][0].toLowerCase()); + expect(stored.functionSig).to.equal(PERMISSIONS[i][1]); + expect(stored.account.toLowerCase()).to.equal(PERMISSIONS[i][2].toLowerCase()); + } + }); + + for (const { target, fn, callers } of PERMISSION_ENTRIES) { + for (const account of callers) { + it(`${LABEL[account]} should NOT yet have permission: ${fn} on ${target}`, async () => { + expect(await accessControlManager.isAllowedToCall(account, fn, { from: target })).to.be.false; + }); + } + } + }); + + testVip("VIP-627 [BNB Chain] Configure Institutional Fixed Rate Vault System", await vip627(), { + supporter: SUPPORTER, + callbackAfterExecution: async txResponse => { + await expectEvents( + txResponse, + [ACCESS_CONTROL_MANAGER_ABI], + ["RoleGranted", "RoleRevoked"], + [EXPECTED_PERMISSION_GRANTED_EVENTS + 1, 1], + ); + await expectEvents(txResponse, [ACM_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + }, + }); + + // Every planned grant is now active. + describe("Post-VIP: ACM permissions granted", () => { + for (const { target, fn, callers } of PERMISSION_ENTRIES) { + for (const account of callers) { + it(`${LABEL[account]} should have permission: ${fn} on ${target}`, async () => { + expect(await accessControlManager.isAllowedToCall(account, fn, { from: target })).to.be.true; + }); + } + } + }); + + // Ownership accepted, adapter wired, admin role revoked. + describe("Post-VIP: ownership and wiring", () => { + it("controller owner should be Normal timelock", async () => { + expect(await controller.owner()).to.equal(NORMAL); + }); + + it("liquidationAdapter owner should be Normal timelock", async () => { + expect(await liquidationAdapter.owner()).to.equal(NORMAL); + }); + + it("InstitutionPositionToken owner should be the controller proxy", async () => { + expect(await positionToken.owner()).to.equal(INSTITUTIONAL_VAULT_CONTROLLER); + }); + + it("controller liquidationAdapter should be set to the adapter proxy", async () => { + expect(await controller.liquidationAdapter()).to.equal(LIQUIDATION_ADAPTER); + }); + + it("DEFAULT_ADMIN_ROLE should be revoked from ACM Aggregator", async () => { + expect(await accessControlManager.hasRole(DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR)).to.be.false; + }); + + it("ProtocolShareReserve should point to the new implementation", async () => { + expect(await proxyAdmin.getProxyImplementation(PROTOCOL_SHARE_RESERVE)).to.equal(NEW_PSR_IMPLEMENTATION); + }); + }); + + describe("Post-VIP: liquidator/settler whitelists", () => { + for (const account of LIQUIDATOR_WHITELIST) { + it(`${account} should be a whitelisted liquidator`, async () => { + expect(await liquidationAdapter.isWhitelistedLiquidator(account)).to.be.true; + }); + } + + for (const account of SETTLER_WHITELIST) { + it(`${account} should be a whitelisted settler`, async () => { + expect(await liquidationAdapter.isWhitelistedSettler(account)).to.be.true; + }); + } + }); + + describe("Post-VIP: createVault ACM gating", () => { + const USDT = "0x55d398326f99059fF775485246999027B3197955"; + const USDC = "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d"; + + const ONE_DAY = 24 * 60 * 60; + const vaultConfig = { + supplyAsset: USDT, + fixedAPY: parseEther("0.05"), // 5% APY + reserveFactor: parseEther("0.1"), // 10% + minBorrowCap: parseEther("1000"), // 1,000 USDT + maxBorrowCap: parseEther("10000000"), // 10M USDT + minSupplierDeposit: parseEther("100"), // 100 USDT + openDuration: 7 * ONE_DAY, + lockDuration: 30 * ONE_DAY, + settlementWindow: ONE_DAY, + }; + const instConfig = { + collateralAsset: USDC, + idealCollateralAmount: parseEther("100000"), + marginRate: parseEther("1.5"), + institutionOperator: CRITICAL_GUARDIAN, + positionTokenId: 1, + }; + const riskConfig = { + liquidationThreshold: parseEther("0.85"), + liquidationIncentive: parseEther("1.08"), + latePenaltyRate: parseEther("1.15"), + }; + + it("random address should revert with Unauthorized when trying to create vault", async () => { + const stranger = await initMainnetUser( + "0x000000000000000000000000000000000000dEaD", + ethers.utils.parseEther("1"), + ); + await expect( + controller.connect(stranger).createVault(vaultConfig, instConfig, riskConfig, "Test", "TEST"), + ).to.be.revertedWithCustomError(controller, "Unauthorized"); + }); + + it("CriticalGuardian should be able to create vault", async () => { + const criticalGuardian = await initMainnetUser(CRITICAL_GUARDIAN, ethers.utils.parseEther("1")); + const call = controller + .connect(criticalGuardian) + .createVault(vaultConfig, instConfig, riskConfig, "Test", "TEST"); + await expect(call).to.not.be.revertedWithCustomError(controller, "Unauthorized"); + }); + + it("CriticalGuardian should successfully create a vault and register it", async () => { + // testVip advances time past the timelock delay, which makes the real ResilientOracle's + // underlying chainlink feeds stale. Deploy a minimal stub oracle that always returns 1e18 + // and swap it in via NT (which now holds setOracle on the controller). + // + // Stub source (compiled with solc 0.8.25, optimizer off): + // contract StubOracle { + // function getPrice(address) external pure returns (uint256) { return 1e18; } + // } + const STUB_ORACLE_BYTECODE = + "0x6080604052348015600e575f80fd5b5061015e8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c806341976e091461002d575b5f80fd5b610047600480360381019061004291906100cc565b61005d565b604051610054919061010f565b60405180910390f35b5f670de0b6b3a76400009050919050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61009b82610072565b9050919050565b6100ab81610091565b81146100b5575f80fd5b50565b5f813590506100c6816100a2565b92915050565b5f602082840312156100e1576100e061006e565b5b5f6100ee848285016100b8565b91505092915050565b5f819050919050565b610109816100f7565b82525050565b5f6020820190506101225f830184610100565b9291505056fea26469706673582212209282f7f2d85233912d0088d6dc45ce2459097d2866597e41f0a286059758c12c64736f6c63430008190033"; + const STUB_ORACLE_ABI = ["function getPrice(address) external pure returns (uint256)"]; + const [deployer] = await ethers.getSigners(); + const stubFactory = new ethers.ContractFactory(STUB_ORACLE_ABI, STUB_ORACLE_BYTECODE, deployer); + const stubOracle = await stubFactory.deploy(); + await stubOracle.deployed(); + + const normalTimelock = await initMainnetUser(NORMAL, ethers.utils.parseEther("1")); + await controller.connect(normalTimelock).setOracle(stubOracle.address); + + const criticalGuardian = await initMainnetUser(CRITICAL_GUARDIAN, ethers.utils.parseEther("1")); + + // Valid config — passes every check in InstitutionalVaultController._validateVaultConfig. + const validVaultConfig = { + supplyAsset: USDT, + fixedAPY: 500, // 5% in basis points (cap is MAX_APY_BPS = 10_000) + reserveFactor: parseEther("0.1"), + minBorrowCap: parseEther("1000"), + maxBorrowCap: parseEther("10000000"), + minSupplierDeposit: parseEther("100"), + openDuration: 7 * ONE_DAY, + lockDuration: 30 * ONE_DAY, + settlementWindow: ONE_DAY, + }; + const validInstConfig = { + collateralAsset: USDC, + idealCollateralAmount: parseEther("100000"), + marginRate: parseEther("0.5"), // 50% — must be ≤ MANTISSA_ONE (1e18) + institutionOperator: CRITICAL_GUARDIAN, + positionTokenId: 0, // overridden by controller with the freshly-minted tokenId + }; + const validRiskConfig = { + liquidationThreshold: parseEther("0.85"), + liquidationIncentive: parseEther("1.08"), + latePenaltyRate: parseEther("1.15"), + }; + + const vaultsBefore = await controller.allVaultsLength(); + + await expect( + controller + .connect(criticalGuardian) + .createVault(validVaultConfig, validInstConfig, validRiskConfig, "Test Vault", "TVAULT"), + ).to.emit(controller, "VaultCreated"); + + const vaultsAfter = await controller.allVaultsLength(); + expect(vaultsAfter).to.equal(vaultsBefore.add(1)); + + const newVault = await controller.allVaults(vaultsAfter.sub(1)); + expect(await controller.isRegistered(newVault)).to.be.true; + }); + }); +}); diff --git a/simulations/vip-627/bsctestnet-addendum.ts b/simulations/vip-627/bsctestnet-addendum.ts new file mode 100644 index 000000000..e03458d7d --- /dev/null +++ b/simulations/vip-627/bsctestnet-addendum.ts @@ -0,0 +1,248 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { parseEther } from "ethers/lib/utils"; +import { ethers } from "hardhat"; +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { expectEvents, initMainnetUser } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; + +import vip664TestnetAddendum, { + ACM_AGGREGATOR, + ACM_AGGREGATOR_INDEX, + DEFAULT_ADMIN_ROLE, + EXPECTED_PERMISSION_GRANTED_EVENTS, + INSTITUTIONAL_VAULT_CONTROLLER, + INSTITUTION_POSITION_TOKEN, + LIQUIDATION_ADAPTER, + LIQUIDATOR_WHITELIST, + NEW_PSR_IMPLEMENTATION, + PERMISSIONS, + PERMISSION_ENTRIES, + PROTOCOL_SHARE_RESERVE, + PROXY_ADMIN, + SETTLER_WHITELIST, +} from "../../vips/vip-627/bsctestnet-addendum"; +import ACM_AGGREGATOR_ABI from "./abi/ACMAggregator.json"; +import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; +import INSTITUTION_POSITION_TOKEN_ABI from "./abi/InstitutionPositionToken.json"; +import INSTITUTIONAL_VAULT_CONTROLLER_ABI from "./abi/InstitutionalVaultController.json"; +import LIQUIDATION_ADAPTER_ABI from "./abi/LiquidationAdapter.json"; +import PROXY_ADMIN_ABI from "./abi/ProxyAdmin.json"; + +const { + NORMAL_TIMELOCK: NORMAL, + FAST_TRACK_TIMELOCK: FAST_TRACK, + CRITICAL_TIMELOCK: CRITICAL, + GUARDIAN, + ACCESS_CONTROL_MANAGER, +} = NETWORK_ADDRESSES.bsctestnet; + +const FORK_BLOCK = 109840621; + +// To make test names readable. +const LABEL: Record = { + [NORMAL]: "Normal", + [FAST_TRACK]: "FastTrack", + [CRITICAL]: "Critical", + [GUARDIAN]: "Guardian", +}; + +forking(FORK_BLOCK, async () => { + let accessControlManager: Contract; + let controller: Contract; + let liquidationAdapter: Contract; + let positionToken: Contract; + let acmAggregator: Contract; + let proxyAdmin: Contract; + + before(async () => { + accessControlManager = new ethers.Contract(ACCESS_CONTROL_MANAGER, ACCESS_CONTROL_MANAGER_ABI, ethers.provider); + controller = new ethers.Contract( + INSTITUTIONAL_VAULT_CONTROLLER, + INSTITUTIONAL_VAULT_CONTROLLER_ABI, + ethers.provider, + ); + liquidationAdapter = new ethers.Contract(LIQUIDATION_ADAPTER, LIQUIDATION_ADAPTER_ABI, ethers.provider); + positionToken = new ethers.Contract(INSTITUTION_POSITION_TOKEN, INSTITUTION_POSITION_TOKEN_ABI, ethers.provider); + acmAggregator = new ethers.Contract(ACM_AGGREGATOR, ACM_AGGREGATOR_ABI, ethers.provider); + proxyAdmin = new ethers.Contract(PROXY_ADMIN, PROXY_ADMIN_ABI, ethers.provider); + }); + + // Contracts redeployed and deploy-script state is in place. + describe("Pre-VIP: verify redeployments", () => { + it("InstitutionalVaultController proxy should be deployed", async () => { + expect(await ethers.provider.getCode(INSTITUTIONAL_VAULT_CONTROLLER)).to.not.equal("0x"); + }); + + it("LiquidationAdapter proxy should be deployed", async () => { + expect(await ethers.provider.getCode(LIQUIDATION_ADAPTER)).to.not.equal("0x"); + }); + + it("InstitutionPositionToken should be deployed", async () => { + expect(await ethers.provider.getCode(INSTITUTION_POSITION_TOKEN)).to.not.equal("0x"); + }); + + it("InstitutionPositionToken pendingOwner should be the controller proxy", async () => { + expect(await positionToken.pendingOwner()).to.equal(INSTITUTIONAL_VAULT_CONTROLLER); + }); + + it("controller pendingOwner should be Normal timelock", async () => { + expect(await controller.pendingOwner()).to.equal(NORMAL); + }); + + it("liquidationAdapter pendingOwner should be Normal timelock", async () => { + expect(await liquidationAdapter.pendingOwner()).to.equal(NORMAL); + }); + + it("liquidationAdapter protocolLiquidationShare should be 0.5e18", async () => { + expect(await liquidationAdapter.protocolLiquidationShare()).to.equal(parseEther("0.5")); + }); + + it("liquidationAdapter closeFactor should be 0.5e18", async () => { + expect(await liquidationAdapter.closeFactor()).to.equal(parseEther("0.5")); + }); + + it("controller liquidationAdapter should be address(0) before VIP", async () => { + expect(await controller.liquidationAdapter()).to.equal(ethers.constants.AddressZero); + }); + + it("ProtocolShareReserve should not yet point to the new implementation", async () => { + expect(await proxyAdmin.getProxyImplementation(PROTOCOL_SHARE_RESERVE)).to.not.equal(NEW_PSR_IMPLEMENTATION); + }); + }); + + // Permissions are pre-loaded but not yet applied to the ACM. + describe("Pre-VIP: ACM permissions not yet granted", () => { + it("aggregator should hold the pre-loaded batch at ACM_AGGREGATOR_INDEX", async () => { + for (let i = 0; i < PERMISSIONS.length; i++) { + const stored = await acmAggregator.grantPermissions(ACM_AGGREGATOR_INDEX, i); + expect(stored.contractAddress.toLowerCase()).to.equal(PERMISSIONS[i][0].toLowerCase()); + expect(stored.functionSig).to.equal(PERMISSIONS[i][1]); + expect(stored.account.toLowerCase()).to.equal(PERMISSIONS[i][2].toLowerCase()); + } + }); + + for (const { target, fn, callers } of PERMISSION_ENTRIES) { + for (const account of callers) { + it(`${LABEL[account] ?? account} should NOT yet have permission: ${fn} on ${target}`, async () => { + expect(await accessControlManager.hasPermission(account, target, fn)).to.be.false; + }); + } + } + }); + + testVip( + "VIP-664 Addendum [BNB Chain Testnet] Configure redeployed Institutional Fixed Rate Vault System", + await vip664TestnetAddendum(), + { + callbackAfterExecution: async txResponse => { + await expectEvents( + txResponse, + [ACCESS_CONTROL_MANAGER_ABI], + ["PermissionGranted", "RoleGranted", "RoleRevoked"], + [EXPECTED_PERMISSION_GRANTED_EVENTS, EXPECTED_PERMISSION_GRANTED_EVENTS + 1, 1], + ); + await expectEvents(txResponse, [ACM_AGGREGATOR_ABI], ["GrantPermissionsExecuted"], [1]); + }, + }, + ); + + // Every planned grant is now active. + describe("Post-VIP: ACM permissions granted", () => { + for (const { target, fn, callers } of PERMISSION_ENTRIES) { + for (const account of callers) { + it(`${LABEL[account] ?? account} should have permission: ${fn} on ${target}`, async () => { + expect(await accessControlManager.hasPermission(account, target, fn)).to.be.true; + }); + } + } + }); + + // Ownership accepted, adapter wired, admin role revoked. + describe("Post-VIP: ownership and wiring", () => { + it("controller owner should be Normal timelock", async () => { + expect(await controller.owner()).to.equal(NORMAL); + }); + + it("liquidationAdapter owner should be Normal timelock", async () => { + expect(await liquidationAdapter.owner()).to.equal(NORMAL); + }); + + it("InstitutionPositionToken owner should be the controller proxy", async () => { + expect(await positionToken.owner()).to.equal(INSTITUTIONAL_VAULT_CONTROLLER); + }); + + it("controller liquidationAdapter should be set to the adapter proxy", async () => { + expect(await controller.liquidationAdapter()).to.equal(LIQUIDATION_ADAPTER); + }); + + it("DEFAULT_ADMIN_ROLE should be revoked from ACM Aggregator", async () => { + expect(await accessControlManager.hasRole(DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR)).to.be.false; + }); + + it("ProtocolShareReserve should point to the new implementation", async () => { + expect(await proxyAdmin.getProxyImplementation(PROTOCOL_SHARE_RESERVE)).to.equal(NEW_PSR_IMPLEMENTATION); + }); + }); + + // Dedicated operator addresses whitelisted. + describe("Post-VIP: liquidator/settler whitelists", () => { + for (const account of LIQUIDATOR_WHITELIST) { + it(`${LABEL[account] ?? account} should be a whitelisted liquidator`, async () => { + expect(await liquidationAdapter.isWhitelistedLiquidator(account)).to.be.true; + }); + } + + for (const account of SETTLER_WHITELIST) { + it(`${LABEL[account] ?? account} should be a whitelisted settler`, async () => { + expect(await liquidationAdapter.isWhitelistedSettler(account)).to.be.true; + }); + } + }); + + describe("Post-VIP: createVault ACM gating", () => { + const USDT = "0xA11c8D9DC9b66E209Ef60F0C8D969D3CD988782c"; + const USDC = "0x16227D60f7a0e586C66B005219dfc887D13C9531"; + + const ONE_DAY = 24 * 60 * 60; + const vaultConfig = { + supplyAsset: USDT, + fixedAPY: parseEther("0.05"), // 5% APY + reserveFactor: parseEther("0.1"), // 10% + minBorrowCap: parseEther("1000"), // 1,000 USDT + maxBorrowCap: parseEther("10000000"), // 10M USDT + minSupplierDeposit: parseEther("100"), // 100 USDT + openDuration: 7 * ONE_DAY, // 7 days + lockDuration: 30 * ONE_DAY, // 30 days + settlementWindow: ONE_DAY, // 1 day + }; + const instConfig = { + collateralAsset: USDC, + idealCollateralAmount: parseEther("100000"), // 100k USDC + marginRate: parseEther("1.5"), + institutionOperator: GUARDIAN, + positionTokenId: 1, + }; + const riskConfig = { + liquidationThreshold: parseEther("0.85"), // 85% + liquidationIncentive: parseEther("1.08"), // 8% incentive + latePenaltyRate: parseEther("1.15"), // 15% late penalty + }; + + it("unauthorized caller should revert when trying to create vault", async () => { + const stranger = await initMainnetUser( + "0x000000000000000000000000000000000000dEaD", + ethers.utils.parseEther("1"), + ); + await expect( + controller.connect(stranger).createVault(vaultConfig, instConfig, riskConfig, "Test", "TEST"), + ).to.be.revertedWithCustomError(controller, "Unauthorized"); + }); + + it("Guardian should be able to create vault", async () => { + const guardian = await initMainnetUser(GUARDIAN, ethers.utils.parseEther("1")); + const call = controller.connect(guardian).createVault(vaultConfig, instConfig, riskConfig, "Test", "TEST"); + await expect(call).to.not.be.revertedWithCustomError(controller, "Unauthorized"); + }); + }); +}); diff --git a/simulations/vip-664/bsctestnet.ts b/simulations/vip-627/bsctestnet.ts similarity index 98% rename from simulations/vip-664/bsctestnet.ts rename to simulations/vip-627/bsctestnet.ts index 9eb5d5841..4dfea73a9 100644 --- a/simulations/vip-664/bsctestnet.ts +++ b/simulations/vip-627/bsctestnet.ts @@ -6,7 +6,7 @@ import { NETWORK_ADDRESSES } from "src/networkAddresses"; import { expectEvents } from "src/utils"; import { forking, testVip } from "src/vip-framework"; -import vip664, { +import vip627, { ACM_AGGREGATOR, ACM_AGGREGATOR_INDEX, ADAPTER_FUNCTIONS, @@ -19,7 +19,7 @@ import vip664, { INSTITUTION_POSITION_TOKEN, LIQUIDATION_ADAPTER, PERMISSIONS, -} from "../../vips/vip-664/bsctestnet"; +} from "../../vips/vip-627/bsctestnet"; import ACM_AGGREGATOR_ABI from "./abi/ACMAggregator.json"; import ACCESS_CONTROL_MANAGER_ABI from "./abi/AccessControlManager.json"; import INSTITUTION_POSITION_TOKEN_ABI from "./abi/InstitutionPositionToken.json"; @@ -139,7 +139,7 @@ forking(FORK_BLOCK, async () => { // ────────────────────────────────────────────────────────────────────── // VIP execution // ────────────────────────────────────────────────────────────────────── - testVip("VIP-664 [BNB Chain Testnet] Configure Institutional Fixed Rate Vault System", await vip664(), { + testVip("VIP-627 [BNB Chain Testnet] Configure Institutional Fixed Rate Vault System", await vip627(), { callbackAfterExecution: async txResponse => { await expectEvents( txResponse, diff --git a/simulations/vip-664/abi/InstitutionPositionToken.json b/simulations/vip-664/abi/InstitutionPositionToken.json deleted file mode 100644 index 8933a45ce..000000000 --- a/simulations/vip-664/abi/InstitutionPositionToken.json +++ /dev/null @@ -1,267 +0,0 @@ -[ - { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, - { "inputs": [], "name": "OwnershipCannotBeRenounced", "type": "error" }, - { - "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "name": "TransferNotApproved", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "approved", "type": "address" }, - { "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, - { "indexed": false, "internalType": "bool", "name": "approved", "type": "bool" } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "OwnershipTransferStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "vault", "type": "address" }, - { "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" }, - { "indexed": true, "internalType": "address", "name": "institution", "type": "address" } - ], - "name": "PositionTokenMinted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [{ "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "name": "PositionTransferApproved", - "type": "event" - }, - { - "anonymous": false, - "inputs": [{ "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "name": "PositionTransferRevoked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, - { "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "Transfer", - "type": "event" - }, - { "inputs": [], "name": "acceptOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "name": "approveTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], - "name": "balanceOf", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "name": "getApproved", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "address", "name": "operator", "type": "address" } - ], - "name": "isApprovedForAll", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "address", "name": "vault", "type": "address" } - ], - "name": "mint", - "outputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "nextTokenId", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "name": "ownerOf", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pendingOwner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "name": "revokeTransferApproval", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "operator", "type": "address" }, - { "internalType": "bool", "name": "approved", "type": "bool" } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }], - "name": "supportsInterface", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "name": "tokenIdToVault", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "tokenId", "type": "uint256" }], - "name": "tokenURI", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "name": "transferApproved", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "", "type": "address" }], - "name": "vaultToTokenId", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - } -] diff --git a/simulations/vip-664/abi/InstitutionalVaultController.json b/simulations/vip-664/abi/InstitutionalVaultController.json deleted file mode 100644 index 0bf203dbb..000000000 --- a/simulations/vip-664/abi/InstitutionalVaultController.json +++ /dev/null @@ -1,505 +0,0 @@ -[ - { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, - { "inputs": [], "name": "InvalidAddress", "type": "error" }, - { "inputs": [], "name": "InvalidConfig", "type": "error" }, - { "inputs": [], "name": "InvalidLatePenaltyRate", "type": "error" }, - { "inputs": [], "name": "InvalidLiquidationIncentive", "type": "error" }, - { "inputs": [], "name": "InvalidLiquidationThreshold", "type": "error" }, - { "inputs": [], "name": "OwnershipCannotBeRenounced", "type": "error" }, - { - "inputs": [ - { "internalType": "address", "name": "sender", "type": "address" }, - { "internalType": "address", "name": "calledContract", "type": "address" }, - { "internalType": "string", "name": "methodSignature", "type": "string" } - ], - "name": "Unauthorized", - "type": "error" - }, - { "inputs": [], "name": "VaultNotRegistered", "type": "error" }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "oldComptroller", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newComptroller", "type": "address" } - ], - "name": "ComptrollerUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [{ "indexed": false, "internalType": "uint8", "name": "version", "type": "uint8" }], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "vault", "type": "address" }, - { "indexed": false, "internalType": "uint256", "name": "newRate", "type": "uint256" } - ], - "name": "LatePenaltyRateUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "oldAdapter", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newAdapter", "type": "address" } - ], - "name": "LiquidationAdapterUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "vault", "type": "address" }, - { "indexed": false, "internalType": "uint256", "name": "newLI", "type": "uint256" } - ], - "name": "LiquidationIncentiveUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "vault", "type": "address" }, - { "indexed": false, "internalType": "uint256", "name": "newLT", "type": "uint256" } - ], - "name": "LiquidationThresholdUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": false, "internalType": "address", "name": "oldAccessControlManager", "type": "address" }, - { "indexed": false, "internalType": "address", "name": "newAccessControlManager", "type": "address" } - ], - "name": "NewAccessControlManager", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "oldOracle", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newOracle", "type": "address" } - ], - "name": "OracleUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "OwnershipTransferStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "oldPSR", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newPSR", "type": "address" } - ], - "name": "ProtocolShareReserveUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "oldTreasury", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newTreasury", "type": "address" } - ], - "name": "TreasuryUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "vault", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "institution", "type": "address" } - ], - "name": "VaultCreated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "oldImpl", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "newImpl", "type": "address" } - ], - "name": "VaultImplementationUpdated", - "type": "event" - }, - { - "inputs": [], - "name": "MANTISSA_ONE", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MANTISSA_ONE_AND_HALF", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MAX_APY_BPS", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { "inputs": [], "name": "acceptOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "acceptPositionTokenOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "accessControlManager", - "outputs": [{ "internalType": "contract IAccessControlManagerV8", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "name": "allVaults", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "allVaultsLength", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "vault", "type": "address" }], - "name": "approvePositionTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "vault", "type": "address" }], - "name": "closeVault", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "vault", "type": "address" }], - "name": "completePauseVault", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "comptroller", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { "internalType": "contract IERC20", "name": "supplyAsset", "type": "address" }, - { "internalType": "uint256", "name": "fixedAPY", "type": "uint256" }, - { "internalType": "uint256", "name": "reserveFactor", "type": "uint256" }, - { "internalType": "uint256", "name": "minBorrowCap", "type": "uint256" }, - { "internalType": "uint256", "name": "maxBorrowCap", "type": "uint256" }, - { "internalType": "uint256", "name": "minSupplierDeposit", "type": "uint256" }, - { "internalType": "uint40", "name": "openDuration", "type": "uint40" }, - { "internalType": "uint40", "name": "lockDuration", "type": "uint40" }, - { "internalType": "uint40", "name": "settlementWindow", "type": "uint40" } - ], - "internalType": "struct VaultConfig", - "name": "_vaultConfig", - "type": "tuple" - }, - { - "components": [ - { "internalType": "contract IERC20", "name": "collateralAsset", "type": "address" }, - { "internalType": "uint256", "name": "idealCollateralAmount", "type": "uint256" }, - { "internalType": "uint256", "name": "marginRate", "type": "uint256" }, - { "internalType": "address", "name": "institutionOperator", "type": "address" }, - { "internalType": "uint256", "name": "positionTokenId", "type": "uint256" } - ], - "internalType": "struct InstitutionalConfig", - "name": "_instConfig", - "type": "tuple" - }, - { - "components": [ - { "internalType": "uint256", "name": "liquidationThreshold", "type": "uint256" }, - { "internalType": "uint256", "name": "liquidationIncentive", "type": "uint256" }, - { "internalType": "uint256", "name": "latePenaltyRate", "type": "uint256" } - ], - "internalType": "struct RiskConfig", - "name": "_riskConfig", - "type": "tuple" - }, - { "internalType": "string", "name": "_name", "type": "string" }, - { "internalType": "string", "name": "_symbol", "type": "string" } - ], - "name": "createVault", - "outputs": [{ "internalType": "address", "name": "vault", "type": "address" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "getAggregatedVaultStates", - "outputs": [ - { - "components": [ - { "internalType": "address", "name": "vault", "type": "address" }, - { "internalType": "enum VaultState", "name": "state", "type": "uint8" }, - { "internalType": "address", "name": "institutionOperator", "type": "address" }, - { "internalType": "uint256", "name": "totalRaised", "type": "uint256" }, - { "internalType": "uint256", "name": "outstandingDebt", "type": "uint256" } - ], - "internalType": "struct VaultStateInfo[]", - "name": "", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "vaultImplementation_", "type": "address" }, - { "internalType": "address", "name": "oracle_", "type": "address" }, - { "internalType": "address", "name": "protocolShareReserve_", "type": "address" }, - { "internalType": "address", "name": "comptroller_", "type": "address" }, - { "internalType": "address", "name": "treasury_", "type": "address" }, - { "internalType": "address", "name": "positionToken_", "type": "address" }, - { "internalType": "address", "name": "acm_", "type": "address" } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "", "type": "address" }], - "name": "institutionNonce", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "", "type": "address" }], - "name": "isRegistered", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "liquidationAdapter", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "vault", "type": "address" }], - "name": "openVault", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "oracle", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "vault", "type": "address" }], - "name": "partialPauseVault", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "pendingOwner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "positionToken", - "outputs": [{ "internalType": "contract IInstitutionPositionToken", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "institution", "type": "address" }], - "name": "predictVaultAddress", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "protocolShareReserve", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [{ "internalType": "address", "name": "vault", "type": "address" }], - "name": "revokePositionTransfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "accessControlManager_", "type": "address" }], - "name": "setAccessControlManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "comptroller_", "type": "address" }], - "name": "setComptroller", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "vault", "type": "address" }, - { "internalType": "uint256", "name": "newRate", "type": "uint256" } - ], - "name": "setLatePenaltyRate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "adapter", "type": "address" }], - "name": "setLiquidationAdapter", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "vault", "type": "address" }, - { "internalType": "uint256", "name": "newLI", "type": "uint256" } - ], - "name": "setLiquidationIncentive", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "vault", "type": "address" }, - { "internalType": "uint256", "name": "newLT", "type": "uint256" } - ], - "name": "setLiquidationThreshold", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "oracle_", "type": "address" }], - "name": "setOracle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "psr", "type": "address" }], - "name": "setProtocolShareReserve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "treasury_", "type": "address" }], - "name": "setTreasury", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "impl", "type": "address" }], - "name": "setVaultImplementation", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "vault", "type": "address" }, - { "internalType": "address", "name": "token", "type": "address" } - ], - "name": "sweep", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "treasury", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "vault", "type": "address" }], - "name": "unpauseVault", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "vaultImplementation", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - } -] diff --git a/simulations/vip-664/abi/LiquidationAdapter.json b/simulations/vip-664/abi/LiquidationAdapter.json deleted file mode 100644 index c90cf602b..000000000 --- a/simulations/vip-664/abi/LiquidationAdapter.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "inputs": [], - "name": "acceptOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pendingOwner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "protocolLiquidationShare", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "closeFactor", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - } -] diff --git a/vips/vip-664/addGrantPermissions.ts b/vips/vip-627/addGrantPermissions.ts similarity index 64% rename from vips/vip-664/addGrantPermissions.ts rename to vips/vip-627/addGrantPermissions.ts index d18cae838..9f72efe3e 100644 --- a/vips/vip-664/addGrantPermissions.ts +++ b/vips/vip-627/addGrantPermissions.ts @@ -1,6 +1,12 @@ -import { ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; -import { ACM_AGGREGATOR, PERMISSIONS } from "./bsctestnet"; +import * as bscmainnet from "./bscmainnet"; +import * as bsctestnet from "./bsctestnet-addendum"; + +const NETWORK_CONFIG: Record = { + bsctestnet: { ACM_AGGREGATOR: bsctestnet.ACM_AGGREGATOR, PERMISSIONS: bsctestnet.PERMISSIONS }, + bscmainnet: { ACM_AGGREGATOR: bscmainnet.ACM_AGGREGATOR, PERMISSIONS: bscmainnet.PERMISSIONS }, +}; const ACM_AGGREGATOR_ABI = [ { @@ -30,6 +36,16 @@ const ACM_AGGREGATOR_ABI = [ ]; async function main() { + const networkName = hre.network.name; + const config = NETWORK_CONFIG[networkName]; + if (!config) { + throw new Error( + `addGrantPermissions: unsupported network "${networkName}". Use --network bsctestnet or --network bscmainnet.`, + ); + } + const { ACM_AGGREGATOR, PERMISSIONS } = config; + + console.log(`Network: ${networkName}, ACM Aggregator: ${ACM_AGGREGATOR}`); console.log(`Total PERMISSIONS to add: ${PERMISSIONS.length}`); const [signer] = await ethers.getSigners(); diff --git a/vips/vip-627/bscmainnet.ts b/vips/vip-627/bscmainnet.ts new file mode 100644 index 000000000..bbd3cedfb --- /dev/null +++ b/vips/vip-627/bscmainnet.ts @@ -0,0 +1,269 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +const { + NORMAL_TIMELOCK: NORMAL, + FAST_TRACK_TIMELOCK: FAST_TRACK, + CRITICAL_TIMELOCK: CRITICAL, + CRITICAL_GUARDIAN, + ACCESS_CONTROL_MANAGER, +} = NETWORK_ADDRESSES.bscmainnet; + +export interface PermissionEntry { + target: string; + fn: string; + callers: string[]; +} + +// Deployed addresses +export const INSTITUTIONAL_VAULT_CONTROLLER = "0x6D9e91cB766259af42619c14c994E694E57e6E85"; +export const LIQUIDATION_ADAPTER = "0x17A6222fB8b4b6D852cA54f5bc376a6A2c6224Bd"; +export const INSTITUTION_POSITION_TOKEN = "0x3Ed56f6937fc8549f9325405d1e8E650739647Fa"; + +// ProtocolShareReserve upgrade +export const PROTOCOL_SHARE_RESERVE = "0xCa01D5A9A248a830E9D93231e791B1afFed7c446"; +export const PROXY_ADMIN = "0x6beb6d2695b67feb73ad4f172e8e2975497187e4"; +export const NEW_PSR_IMPLEMENTATION = "0x4eC6D748a2647000895b455c408f85602A144Ed6"; + +// ACM aggregator (mainnet) +export const ACM_AGGREGATOR = "0x8b443Ea6726E56DF4C4F62f80F0556bB9B2a7c64"; +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; + +export const ACM_AGGREGATOR_INDEX = 3; + +export const LIQUIDATOR_WHITELIST: string[] = [CRITICAL_GUARDIAN]; +export const SETTLER_WHITELIST: string[] = [CRITICAL_GUARDIAN]; + +export const PERMISSION_ENTRIES: PermissionEntry[] = [ + // InstitutionalVaultController + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "acceptPositionTokenOwnership()", callers: [NORMAL] }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "createVault(VaultConfig,InstitutionalConfig,RiskConfig,string,string)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "openVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "cancelVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "partialPauseVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "completePauseVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "unpauseVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "closeVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "sweep(address,address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "approvePositionTransfer(address,address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "revokePositionTransfer(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setLiquidationThreshold(address,uint256)", + callers: [NORMAL, FAST_TRACK, CRITICAL], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setLiquidationIncentive(address,uint256)", + callers: [NORMAL, FAST_TRACK, CRITICAL], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setLatePenaltyRate(address,uint256)", + callers: [NORMAL, FAST_TRACK, CRITICAL], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setVaultImplementation(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setLiquidationAdapter(address)", + callers: [NORMAL, CRITICAL_GUARDIAN], + }, + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "setOracle(address)", callers: [NORMAL, CRITICAL_GUARDIAN] }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setProtocolShareReserve(address)", + callers: [NORMAL, CRITICAL_GUARDIAN], + }, + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "setComptroller(address)", callers: [NORMAL, CRITICAL_GUARDIAN] }, + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "setTreasury(address)", callers: [NORMAL, CRITICAL_GUARDIAN] }, + + // LiquidationAdapter + { + target: LIQUIDATION_ADAPTER, + fn: "setLiquidatorWhitelist(address,bool)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { + target: LIQUIDATION_ADAPTER, + fn: "setSettlerWhitelist(address,bool)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, + { target: LIQUIDATION_ADAPTER, fn: "setProtocolLiquidationShare(uint256)", callers: [NORMAL, FAST_TRACK, CRITICAL] }, + // NORMAL already holds setCloseFactor globally on mainnet. + { target: LIQUIDATION_ADAPTER, fn: "setCloseFactor(uint256)", callers: [FAST_TRACK, CRITICAL] }, + { + target: LIQUIDATION_ADAPTER, + fn: "sweepProtocolShareToReserve(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, CRITICAL_GUARDIAN], + }, +]; + +export const buildPermissions = (table: PermissionEntry[]): [string, string, string][] => + table.flatMap(({ target, fn, callers }) => callers.map(c => [target, fn, c] as [string, string, string])); + +export const PERMISSIONS: [string, string, string][] = buildPermissions(PERMISSION_ENTRIES); + +export const EXPECTED_PERMISSION_GRANTED_EVENTS = PERMISSIONS.length; + +export const vip627 = () => { + const meta = { + version: "v1", + title: "VIP-627 [BNB Chain] Activate Institutional Fixed Rate Vault System", + description: `#### Summary + +If passed, this VIP activates the Institutional Fixed Rate Vault system on BNB Chain and upgrades the Protocol Share Reserve to support it. The new system introduces fixed-rate, time-bound vaults intended for whitelisted institutional borrowers, with a dedicated liquidation flow separate from the existing core pool. + +#### Description + +The proposal performs the following on-chain actions: + +**1. Grant ACM permissions via the ACMCommandsAggregator** + +Permissions for the new InstitutionalVaultController and LiquidationAdapter contracts have been pre-loaded off-chain into the ACMCommandsAggregator (index ${ACM_AGGREGATOR_INDEX}). The VIP temporarily grants the aggregator the DEFAULT_ADMIN_ROLE on the AccessControlManager, executes the batch, and revokes the role in the same proposal. This grants role-based access (${EXPECTED_PERMISSION_GRANTED_EVENTS} permissions in total) over all administrative functions of both contracts to the Normal / Fast-track / Critical timelocks and, where appropriate, the Critical Guardian. + +- Vault lifecycle and operations (createVault, openVault, cancelVault, partialPauseVault, completePauseVault, unpauseVault, closeVault, sweep, approvePositionTransfer, revokePositionTransfer) — granted to all three timelocks and the Critical Guardian. +- Risk parameter setters (setLiquidationThreshold, setLiquidationIncentive, setLatePenaltyRate, setVaultImplementation) — granted to the three timelocks only. +- Plumbing setters (setLiquidationAdapter, setOracle, setProtocolShareReserve, setComptroller, setTreasury) — granted to the Normal Timelock and Critical Guardian. +- LiquidationAdapter controls (setLiquidatorWhitelist, setSettlerWhitelist, setProtocolLiquidationShare, setCloseFactor, sweepProtocolShareToReserve) — granted to the timelocks, with the whitelist and sweep functions also granted to the Critical Guardian. + +**2. Complete two-step ownership transfers** + +The InstitutionalVaultController, the LiquidationAdapter, and the InstitutionPositionToken were deployed with their Ownable2Step pending owner set to the Normal Timelock. The VIP calls acceptOwnership() on the controller and adapter, and acceptPositionTokenOwnership() on the controller (which in turn accepts ownership of the position-token NFT). + +**3. Wire the LiquidationAdapter into the controller** + +Call setLiquidationAdapter on the InstitutionalVaultController, pointing it at the newly deployed LiquidationAdapter. + +**4. Whitelist the Critical Guardian as the initial liquidator and settler** + +Whitelist the Critical Guardian on the LiquidationAdapter as both an authorized liquidator and an authorized settler, so that the dedicated liquidation flow can run under operational control while remaining governance-bounded. + +**5. Upgrade the ProtocolShareReserve implementation** + +Upgrade the ProtocolShareReserve proxy to a new implementation that recognises an additional income type produced by institutional-vault liquidations, so that protocol-share income flowing in from the LiquidationAdapter is routed and accounted for correctly. + +#### Security and additional considerations + +- The DEFAULT_ADMIN_ROLE grant to the ACMCommandsAggregator is scoped to this proposal: it is granted, used once to apply a pre-loaded permission batch, and revoked in the same transaction sequence. +- All sensitive risk-parameter changes (liquidation threshold, liquidation incentive, late-penalty rate, vault implementation) are restricted to timelock callers only and are not exposed to the Critical Guardian. +- The Critical Guardian initially fills the liquidator and settler roles on the LiquidationAdapter; additional whitelisted parties can be added later via subsequent VIPs. + +#### Deployed contracts (BNB Chain) + +- InstitutionalVaultController (proxy): ${INSTITUTIONAL_VAULT_CONTROLLER} +- LiquidationAdapter (proxy): ${LIQUIDATION_ADAPTER} +- InstitutionPositionToken: ${INSTITUTION_POSITION_TOKEN} +- ProtocolShareReserve (proxy): ${PROTOCOL_SHARE_RESERVE} +- New ProtocolShareReserve implementation: ${NEW_PSR_IMPLEMENTATION} +- ACMCommandsAggregator: ${ACM_AGGREGATOR} (batch index ${ACM_AGGREGATOR_INDEX})`, + forDescription: "I agree that Venus Protocol should proceed with this proposal", + againstDescription: "I do not think that Venus Protocol should proceed with this proposal", + abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", + }; + + return makeProposal( + [ + // Step 1 — Execute the ACM permission batch via the aggregator. + // Permissions are pre-loaded into the aggregator off-chain via addGrantPermissions.ts. + { + target: ACCESS_CONTROL_MANAGER, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [ACM_AGGREGATOR_INDEX], + }, + { + target: ACCESS_CONTROL_MANAGER, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + }, + + // Step 2 — Complete Ownable2Step transfers. + { target: INSTITUTIONAL_VAULT_CONTROLLER, signature: "acceptOwnership()", params: [] }, + { target: LIQUIDATION_ADAPTER, signature: "acceptOwnership()", params: [] }, + + // Step 3 — Wire adapter into controller and accept position-token ownership. + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + signature: "setLiquidationAdapter(address)", + params: [LIQUIDATION_ADAPTER], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + signature: "acceptPositionTokenOwnership()", + params: [], + }, + + // Step 4 — Whitelist dedicated liquidator/settler addresses on the adapter. + ...LIQUIDATOR_WHITELIST.map(account => ({ + target: LIQUIDATION_ADAPTER, + signature: "setLiquidatorWhitelist(address,bool)", + params: [account, true], + })), + ...SETTLER_WHITELIST.map(account => ({ + target: LIQUIDATION_ADAPTER, + signature: "setSettlerWhitelist(address,bool)", + params: [account, true], + })), + + // Step 5 — Upgrade the ProtocolShareReserve + { + target: PROXY_ADMIN, + signature: "upgrade(address,address)", + params: [PROTOCOL_SHARE_RESERVE, NEW_PSR_IMPLEMENTATION], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip627; diff --git a/vips/vip-627/bsctestnet-addendum.ts b/vips/vip-627/bsctestnet-addendum.ts new file mode 100644 index 000000000..363bb4760 --- /dev/null +++ b/vips/vip-627/bsctestnet-addendum.ts @@ -0,0 +1,244 @@ +import { NETWORK_ADDRESSES } from "src/networkAddresses"; +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +const { + NORMAL_TIMELOCK: NORMAL, + FAST_TRACK_TIMELOCK: FAST_TRACK, + CRITICAL_TIMELOCK: CRITICAL, + GUARDIAN, + ACCESS_CONTROL_MANAGER, +} = NETWORK_ADDRESSES.bsctestnet; + +export interface PermissionEntry { + target: string; + fn: string; + callers: string[]; +} + +// Redeployed addresses (TODO: replace once new testnet deployment is complete) +export const INSTITUTIONAL_VAULT_CONTROLLER = "0xf77dED2A00F94e33C392126238360D4642c16Ba2"; +export const LIQUIDATION_ADAPTER = "0x4b302b56315Ca16A0A4565108e62404496916491"; +export const INSTITUTION_POSITION_TOKEN = "0x71dA473257a96e975558C8edD8491AD0880EFCe5"; + +// ProtocolShareReserve upgrade (adds support for the institutional-vault liquidation income type). +export const PROTOCOL_SHARE_RESERVE = "0x25c7c7D6Bf710949fD7f03364E9BA19a1b3c10E3"; +export const PROXY_ADMIN = "0x7877ffd62649b6a1557b55d4c20fcbab17344c91"; +export const NEW_PSR_IMPLEMENTATION = "0x6eFa596c53E6A753DdA643e3e3FEcA1570879b7C"; + +// ACM aggregator (existing testnet deployment). +export const ACM_AGGREGATOR = "0xB59523628D92f914ec6624Be4281397E8aFD71EF"; +export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000"; +export const ACM_AGGREGATOR_INDEX = 3; + +// Liquidator/settler addresses whitelisted on the `LiquidationAdapter`. +// Guardian is whitelisted on testnet for operational convenience. +export const LIQUIDATOR_WHITELIST: string[] = [GUARDIAN]; +export const SETTLER_WHITELIST: string[] = [GUARDIAN]; + +export const PERMISSION_ENTRIES: PermissionEntry[] = [ + // InstitutionalVaultController + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "acceptPositionTokenOwnership()", callers: [NORMAL] }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "createVault(VaultConfig,InstitutionalConfig,RiskConfig,string,string)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "openVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "cancelVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "partialPauseVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "completePauseVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "unpauseVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "closeVault(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "sweep(address,address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "approvePositionTransfer(address,address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "revokePositionTransfer(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setLiquidationThreshold(address,uint256)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setLiquidationIncentive(address,uint256)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setLatePenaltyRate(address,uint256)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + fn: "setVaultImplementation(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL], + }, + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "setLiquidationAdapter(address)", callers: [NORMAL, GUARDIAN] }, + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "setOracle(address)", callers: [NORMAL, GUARDIAN] }, + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "setProtocolShareReserve(address)", callers: [NORMAL, GUARDIAN] }, + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "setComptroller(address)", callers: [NORMAL, GUARDIAN] }, + { target: INSTITUTIONAL_VAULT_CONTROLLER, fn: "setTreasury(address)", callers: [NORMAL, GUARDIAN] }, + + // LiquidationAdapter + { + target: LIQUIDATION_ADAPTER, + fn: "setLiquidatorWhitelist(address,bool)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: LIQUIDATION_ADAPTER, + fn: "setSettlerWhitelist(address,bool)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { + target: LIQUIDATION_ADAPTER, + fn: "setProtocolLiquidationShare(uint256)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, + { target: LIQUIDATION_ADAPTER, fn: "setCloseFactor(uint256)", callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN] }, + { + target: LIQUIDATION_ADAPTER, + fn: "sweepProtocolShareToReserve(address)", + callers: [NORMAL, FAST_TRACK, CRITICAL, GUARDIAN], + }, +]; + +export const buildPermissions = (table: PermissionEntry[]): [string, string, string][] => + table.flatMap(({ target, fn, callers }) => callers.map(c => [target, fn, c] as [string, string, string])); + +export const PERMISSIONS: [string, string, string][] = buildPermissions(PERMISSION_ENTRIES); + +export const EXPECTED_PERMISSION_GRANTED_EVENTS = PERMISSIONS.length; + +export const vip664TestnetAddendum = () => { + const meta = { + version: "v1", + title: "VIP-664 Addendum [BNB Chain Testnet] Configure redeployed Institutional Fixed Rate Vault System", + description: `#### Summary + +The Institutional Fixed Rate Vault contracts were redeployed on BNB Chain Testnet. This addendum +re-runs the configuration against the new contract addresses, following the same flow used in the +[VIP-664 BNB mainnet proposal](../bscmainnet.ts). Permissions are pre-loaded into the +\`ACMCommandsAggregator\` off-chain via \`addGrantPermissions.ts\`; the VIP only executes the batch. + +If passed, this VIP will: + +1. Execute the pre-loaded ACM permission batch (${EXPECTED_PERMISSION_GRANTED_EVENTS} total grants) via \`ACMCommandsAggregator\`: + - \`grantRole(DEFAULT_ADMIN_ROLE, aggregator)\` so the aggregator can apply grants + - \`executeGrantPermissions\` to apply all permissions atomically + - \`revokeRole(DEFAULT_ADMIN_ROLE, aggregator)\` to remove the elevated role +2. Accept ownership of \`InstitutionalVaultController\` and \`LiquidationAdapter\` (two-step Ownable2Step transfer initiated in deploy script). +3. Set the \`LiquidationAdapter\` on the controller via \`setLiquidationAdapter()\`. +4. Complete the two-step position token ownership transfer via \`acceptPositionTokenOwnership()\`. +5. Whitelist the Guardian as a liquidator and settler on the \`LiquidationAdapter\`. +6. Upgrade the \`ProtocolShareReserve\` proxy to a new implementation that supports the institutional-vault liquidation income type. + +#### Deployed Contracts (redeployed) + +- **InstitutionalVaultController** (proxy): ${INSTITUTIONAL_VAULT_CONTROLLER} +- **LiquidationAdapter** (proxy): ${LIQUIDATION_ADAPTER} +- **InstitutionPositionToken**: ${INSTITUTION_POSITION_TOKEN} +- **ProtocolShareReserve** (proxy): ${PROTOCOL_SHARE_RESERVE} +- **New ProtocolShareReserve implementation**: ${NEW_PSR_IMPLEMENTATION}`, + forDescription: "I agree that Venus Protocol should proceed with this proposal", + againstDescription: "I do not think that Venus Protocol should proceed with this proposal", + abstainDescription: "I am indifferent to whether Venus Protocol proceeds or not", + }; + + return makeProposal( + [ + // Step 1 — Execute the ACM permission batch via the aggregator. + // Permissions are pre-loaded into the aggregator off-chain via addGrantPermissions.ts. + { + target: ACCESS_CONTROL_MANAGER, + signature: "grantRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + }, + { + target: ACM_AGGREGATOR, + signature: "executeGrantPermissions(uint256)", + params: [ACM_AGGREGATOR_INDEX], + }, + { + target: ACCESS_CONTROL_MANAGER, + signature: "revokeRole(bytes32,address)", + params: [DEFAULT_ADMIN_ROLE, ACM_AGGREGATOR], + }, + + // Step 2 — Complete Ownable2Step transfers (initiated in deploy script). + { target: INSTITUTIONAL_VAULT_CONTROLLER, signature: "acceptOwnership()", params: [] }, + { target: LIQUIDATION_ADAPTER, signature: "acceptOwnership()", params: [] }, + + // Step 3 — Wire adapter into controller and accept position-token ownership. + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + signature: "setLiquidationAdapter(address)", + params: [LIQUIDATION_ADAPTER], + }, + { + target: INSTITUTIONAL_VAULT_CONTROLLER, + signature: "acceptPositionTokenOwnership()", + params: [], + }, + + // Step 4 — Whitelist dedicated liquidator/settler addresses on the adapter. + ...LIQUIDATOR_WHITELIST.map(account => ({ + target: LIQUIDATION_ADAPTER, + signature: "setLiquidatorWhitelist(address,bool)", + params: [account, true], + })), + ...SETTLER_WHITELIST.map(account => ({ + target: LIQUIDATION_ADAPTER, + signature: "setSettlerWhitelist(address,bool)", + params: [account, true], + })), + + // Step 5 — Upgrade the ProtocolShareReserve + { + target: PROXY_ADMIN, + signature: "upgrade(address,address)", + params: [PROTOCOL_SHARE_RESERVE, NEW_PSR_IMPLEMENTATION], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip664TestnetAddendum; diff --git a/vips/vip-664/bsctestnet.ts b/vips/vip-627/bsctestnet.ts similarity index 98% rename from vips/vip-664/bsctestnet.ts rename to vips/vip-627/bsctestnet.ts index 8dc121e56..ac8eabb42 100644 --- a/vips/vip-664/bsctestnet.ts +++ b/vips/vip-627/bsctestnet.ts @@ -105,10 +105,10 @@ export const PERMISSIONS: [string, string, string][] = [ ...ADAPTER_GUARDIAN_FUNCTIONS.map(sig => [LIQUIDATION_ADAPTER, sig, GUARDIAN] as [string, string, string]), ]; -export const vip664 = () => { +export const vip627 = () => { const meta = { version: "v1", - title: "VIP-664 [BNB Chain Testnet] Configure Institutional Fixed Rate Vault System", + title: "VIP-627 [BNB Chain Testnet] Configure Institutional Fixed Rate Vault System", description: `#### Summary If passed, this VIP will configure the Institutional Fixed Rate Vault system on BNB Chain Testnet: @@ -147,7 +147,7 @@ If passed, this VIP will configure the Institutional Fixed Rate Vault system on // ────────────────────────────────────────────────────────────────────── // Phase 1 — ACM permissions via Aggregator // ────────────────────────────────────────────────────────────────────── - // Permissions were pre-loaded into ACM Aggregator via addGrantPermissions.ts. + // Permissions were pre-loaded into ACM Aggregator. // Grant admin role, execute batched permissions, then revoke admin role. { @@ -220,4 +220,4 @@ If passed, this VIP will configure the Institutional Fixed Rate Vault system on ); }; -export default vip664; +export default vip627;