From 101e7dd85052fec4acd5339e1a29d14f5ecd8c67 Mon Sep 17 00:00:00 2001 From: Debugger022 Date: Mon, 6 Apr 2026 12:26:30 +0530 Subject: [PATCH 1/2] feat: add syncCash for isolated pool markets on non-BNB chains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VIP-601/VIP-602 granted permissions and called syncCash() on core pool markets only. This VIP completes the internalCash initialization for the remaining isolated pools on Ethereum (Curve, LST, Ethena — 15 VTokens) and Arbitrum One (LST pool — 3 VTokens). No beacon upgrade needed as VIP-602 already covered all VToken proxies on each network. --- simulations/vip-803/abi/ILComptroller.json | 2121 ++++++++++++++++++++ simulations/vip-803/abi/ILVToken.json | 2105 +++++++++++++++++++ simulations/vip-803/arbitrumone.ts | 56 + simulations/vip-803/ethereum.ts | 80 + vips/vip-803/addresses/arbitrumone.ts | 13 + vips/vip-803/addresses/ethereum.ts | 39 + vips/vip-803/bscmainnet.ts | 118 ++ 7 files changed, 4532 insertions(+) create mode 100644 simulations/vip-803/abi/ILComptroller.json create mode 100644 simulations/vip-803/abi/ILVToken.json create mode 100644 simulations/vip-803/arbitrumone.ts create mode 100644 simulations/vip-803/ethereum.ts create mode 100644 vips/vip-803/addresses/arbitrumone.ts create mode 100644 vips/vip-803/addresses/ethereum.ts create mode 100644 vips/vip-803/bscmainnet.ts diff --git a/simulations/vip-803/abi/ILComptroller.json b/simulations/vip-803/abi/ILComptroller.json new file mode 100644 index 000000000..d1801efd8 --- /dev/null +++ b/simulations/vip-803/abi/ILComptroller.json @@ -0,0 +1,2121 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "poolRegistry_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "enum Action", + "name": "action", + "type": "uint8" + } + ], + "name": "ActionPaused", + "type": "error" + }, + { + "inputs": [], + "name": "BorrowActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "BorrowCapExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "BorrowCapIsNotZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expectedLessThanOrEqualTo", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "CollateralExceedsThreshold", + "type": "error" + }, + { + "inputs": [], + "name": "CollateralFactorIsNotZero", + "type": "error" + }, + { + "inputs": [], + "name": "ComptrollerMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "DelegationStatusUnchanged", + "type": "error" + }, + { + "inputs": [], + "name": "EnterMarketActionNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "ExitMarketActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "collateralToSeize", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "availableCollateral", + "type": "uint256" + } + ], + "name": "InsufficientCollateral", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientLiquidity", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientShortfall", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidCollateralFactor", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidLiquidationThreshold", + "type": "error" + }, + { + "inputs": [], + "name": "LiquidateActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "MarketAlreadyListed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "MarketNotCollateral", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "MarketNotListed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "loopsLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "requiredLoops", + "type": "uint256" + } + ], + "name": "MaxLoopsLimitExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expectedGreaterThan", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actual", + "type": "uint256" + } + ], + "name": "MinimalCollateralViolated", + "type": "error" + }, + { + "inputs": [], + "name": "MintActionNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "NonzeroBorrowBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "PriceError", + "type": "error" + }, + { + "inputs": [], + "name": "RedeemActionNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "RepayActionNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "SeizeActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "SnapshotError", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "SupplyCapExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "SupplyCapIsNotZero", + "type": "error" + }, + { + "inputs": [], + "name": "TooMuchRepay", + "type": "error" + }, + { + "inputs": [], + "name": "TransferActionNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "calledContract", + "type": "address" + }, + { + "internalType": "string", + "name": "methodSignature", + "type": "string" + } + ], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expectedSender", + "type": "address" + }, + { + "internalType": "address", + "name": "actualSender", + "type": "address" + } + ], + "name": "UnexpectedSender", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum Action", + "name": "action", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bool", + "name": "pauseState", + "type": "bool" + } + ], + "name": "ActionPausedMarket", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "approver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "DelegateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "IsForcedLiquidationEnabledUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "MarketSupported", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "MarketUnlisted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldMaxLoopsLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newmaxLoopsLimit", + "type": "uint256" + } + ], + "name": "MaxLoopsLimitUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlManager", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlManager", + "type": "address" + } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newBorrowCap", + "type": "uint256" + } + ], + "name": "NewBorrowCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "oldLiquidationThresholdMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newLiquidationThresholdMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationThreshold", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldMinLiquidatableCollateral", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newMinLiquidatableCollateral", + "type": "uint256" + } + ], + "name": "NewMinLiquidatableCollateral", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract ResilientOracleInterface", + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract ResilientOracleInterface", + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IPrime", + "name": "oldPrimeToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IPrime", + "name": "newPrimeToken", + "type": "address" + } + ], + "name": "NewPrimeToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "rewardsDistributor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "rewardToken", + "type": "address" + } + ], + "name": "NewRewardsDistributor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newSupplyCap", + "type": "uint256" + } + ], + "name": "NewSupplyCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "internalType": "contract VToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + }, + { + "internalType": "enum Action", + "name": "action", + "type": "uint8" + } + ], + "name": "actionPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract RewardsDistributor", + "name": "_rewardsDistributor", + "type": "address" + } + ], + "name": "addRewardsDistributor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "allMarkets", + "outputs": [ + { + "internalType": "contract VToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "approvedDelegates", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "borrowCaps", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "vTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "shortfall", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAllMarkets", + "outputs": [ + { + "internalType": "contract VToken[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "internalType": "contract VToken[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getBorrowingPower", + "outputs": [ + { + "internalType": "uint256", + "name": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "shortfall", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenModify", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "getHypotheticalAccountLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "shortfall", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRewardDistributors", + "outputs": [ + { + "internalType": "contract RewardsDistributor[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + } + ], + "name": "getRewardsByMarket", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "rewardToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "supplySpeed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowSpeed", + "type": "uint256" + } + ], + "internalType": "struct ComptrollerStorage.RewardSpeeds[]", + "name": "rewardSpeeds", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "healAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "loopLimit", + "type": "uint256" + }, + { + "internalType": "address", + "name": "accessControlManager", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isForcedLiquidationEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "isMarketListed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract VToken", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "contract VToken", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "internalType": "struct ComptrollerStorage.LiquidationOrder[]", + "name": "orders", + "type": "tuple[]" + } + ], + "name": "liquidateAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokensToSeize", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "internalType": "bool", + "name": "isListed", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "collateralFactorMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "liquidationThresholdMantissa", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLoopsLimit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minLiquidatableCollateral", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualMintAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "oracle", + "outputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "poolRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "preBorrowHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "skipLiquidityCheck", + "type": "bool" + } + ], + "name": "preLiquidateHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "preMintHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "preRedeemHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + } + ], + "name": "preRepayHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "seizerContract", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + } + ], + "name": "preSeizeHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "preTransferHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "prime", + "outputs": [ + { + "internalType": "contract IPrime", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "actualRepayAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "marketsList", + "type": "address[]" + }, + { + "internalType": "enum Action[]", + "name": "actionsList", + "type": "uint8[]" + }, + { + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "setActionsPaused", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "setCloseFactor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "newCollateralFactorMantissa", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "newLiquidationThresholdMantissa", + "type": "uint256" + } + ], + "name": "setCollateralFactor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vTokenBorrowed", + "type": "address" + }, + { + "internalType": "bool", + "name": "enable", + "type": "bool" + } + ], + "name": "setForcedLiquidation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "setLiquidationIncentive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newBorrowCaps", + "type": "uint256[]" + } + ], + "name": "setMarketBorrowCaps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken[]", + "name": "vTokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "newSupplyCaps", + "type": "uint256[]" + } + ], + "name": "setMarketSupplyCaps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "setMaxLoopsLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newMinLiquidatableCollateral", + "type": "uint256" + } + ], + "name": "setMinLiquidatableCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ResilientOracleInterface", + "name": "newOracle", + "type": "address" + } + ], + "name": "setPriceOracle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IPrime", + "name": "_prime", + "type": "address" + } + ], + "name": "setPrimeToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "supplyCaps", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract VToken", + "name": "vToken", + "type": "address" + } + ], + "name": "supportMarket", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vToken", + "type": "address" + }, + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "market", + "type": "address" + } + ], + "name": "unlistMarket", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "updateDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "updatePrices", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/simulations/vip-803/abi/ILVToken.json b/simulations/vip-803/abi/ILVToken.json new file mode 100644 index 000000000..c039d2ef1 --- /dev/null +++ b/simulations/vip-803/abi/ILVToken.json @@ -0,0 +1,2105 @@ +[ + { + "inputs": [ + { + "internalType": "bool", + "name": "timeBased_", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "blocksPerYear_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxBorrowRateMantissa_", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "actualAddAmount", + "type": "uint256" + } + ], + "name": "AddReservesFactorFreshCheck", + "type": "error" + }, + { + "inputs": [], + "name": "BorrowCashNotAvailable", + "type": "error" + }, + { + "inputs": [], + "name": "BorrowFreshnessCheck", + "type": "error" + }, + { + "inputs": [], + "name": "DelegateNotApproved", + "type": "error" + }, + { + "inputs": [], + "name": "ForceLiquidateBorrowUnauthorized", + "type": "error" + }, + { + "inputs": [], + "name": "HealBorrowUnauthorized", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidBlocksPerYear", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTimeBasedConfiguration", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "errorCode", + "type": "uint256" + } + ], + "name": "LiquidateAccrueCollateralInterestFailed", + "type": "error" + }, + { + "inputs": [], + "name": "LiquidateCloseAmountIsUintMax", + "type": "error" + }, + { + "inputs": [], + "name": "LiquidateCloseAmountIsZero", + "type": "error" + }, + { + "inputs": [], + "name": "LiquidateCollateralFreshnessCheck", + "type": "error" + }, + { + "inputs": [], + "name": "LiquidateFreshnessCheck", + "type": "error" + }, + { + "inputs": [], + "name": "LiquidateLiquidatorIsBorrower", + "type": "error" + }, + { + "inputs": [], + "name": "LiquidateSeizeLiquidatorIsBorrower", + "type": "error" + }, + { + "inputs": [], + "name": "MintFreshnessCheck", + "type": "error" + }, + { + "inputs": [], + "name": "ProtocolSeizeShareTooBig", + "type": "error" + }, + { + "inputs": [], + "name": "RedeemFreshnessCheck", + "type": "error" + }, + { + "inputs": [], + "name": "RedeemTransferOutNotPossible", + "type": "error" + }, + { + "inputs": [], + "name": "ReduceReservesCashNotAvailable", + "type": "error" + }, + { + "inputs": [], + "name": "ReduceReservesCashValidation", + "type": "error" + }, + { + "inputs": [], + "name": "ReduceReservesFreshCheck", + "type": "error" + }, + { + "inputs": [], + "name": "RepayBorrowFreshnessCheck", + "type": "error" + }, + { + "inputs": [], + "name": "SetInterestRateModelFreshCheck", + "type": "error" + }, + { + "inputs": [], + "name": "SetReserveFactorBoundsCheck", + "type": "error" + }, + { + "inputs": [], + "name": "SetReserveFactorFreshCheck", + "type": "error" + }, + { + "inputs": [], + "name": "TransferNotAllowed", + "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": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "cashPrior", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "badDebtDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "badDebtOld", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "badDebtNew", + "type": "uint256" + } + ], + "name": "BadDebtIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "badDebtOld", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "badDebtNew", + "type": "uint256" + } + ], + "name": "BadDebtRecovered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldInternalCash", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newInternalCash", + "type": "uint256" + } + ], + "name": "CashSynced", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "HealBorrow", + "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": "liquidator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "vTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mintTokens", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "accountBalance", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "oldAccessControlManager", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAccessControlManager", + "type": "address" + } + ], + "name": "NewAccessControlManager", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract ComptrollerInterface", + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract ComptrollerInterface", + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract InterestRateModel", + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract InterestRateModel", + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldProtocolSeizeShareMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newProtocolSeizeShareMantissa", + "type": "uint256" + } + ], + "name": "NewProtocolSeizeShare", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldProtocolShareReserve", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newProtocolShareReserve", + "type": "address" + } + ], + "name": "NewProtocolShareReserve", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldReduceReservesBlockOrTimestampDelta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newReduceReservesBlockOrTimestampDelta", + "type": "uint256" + } + ], + "name": "NewReduceReservesBlockDelta", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldShortfall", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newShortfall", + "type": "address" + } + ], + "name": "NewShortfallContract", + "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": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProtocolSeize", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "accountBalance", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "benefactor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "addAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "protocolShareReserve", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "SpreadReservesReduced", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SweepToken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "NO_ERROR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "accessControlManager", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "addAmount", + "type": "uint256" + } + ], + "name": "addReserves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "badDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "recoveredAmount_", + "type": "uint256" + } + ], + "name": "badDebtRecovered", + "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": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "blocksOrSecondsPerYear", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowBehalf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "internalType": "contract ComptrollerInterface", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + }, + { + "internalType": "contract VTokenInterface", + "name": "vTokenCollateral", + "type": "address" + }, + { + "internalType": "bool", + "name": "skipLiquidityCheck", + "type": "bool" + } + ], + "name": "forceLiquidateBorrow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "error", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "vTokenBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "borrowBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exchangeRate", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBlockNumberOrTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "healBorrow", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "underlying_", + "type": "address" + }, + { + "internalType": "contract ComptrollerInterface", + "name": "comptroller_", + "type": "address" + }, + { + "internalType": "contract InterestRateModel", + "name": "interestRateModel_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + }, + { + "internalType": "address", + "name": "admin_", + "type": "address" + }, + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "shortfall", + "type": "address" + }, + { + "internalType": "address payable", + "name": "protocolShareReserve", + "type": "address" + } + ], + "internalType": "struct VTokenInterface.RiskManagementInit", + "name": "riskManagement", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "reserveFactorMantissa_", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "internalType": "contract InterestRateModel", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "internalCash", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isTimeBased", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isVToken", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + }, + { + "internalType": "contract VTokenInterface", + "name": "vTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "internalType": "uint256", + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintBehalf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "protocolSeizeShareMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "protocolShareReserve", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemBehalf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlyingBehalf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "reduceReserves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "reduceReservesBlockDelta", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "reduceReservesBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "liquidator", + "type": "address" + }, + { + "internalType": "address", + "name": "borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "accessControlManager_", + "type": "address" + } + ], + "name": "setAccessControlManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract InterestRateModel", + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "setInterestRateModel", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newProtocolSeizeShareMantissa_", + "type": "uint256" + } + ], + "name": "setProtocolSeizeShare", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "protocolShareReserve_", + "type": "address" + } + ], + "name": "setProtocolShareReserve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newReduceReservesBlockOrTimestampDelta", + "type": "uint256" + } + ], + "name": "setReduceReservesBlockDelta", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "setReserveFactor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "shortfall_", + "type": "address" + } + ], + "name": "setShortfallContract", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "shortfall", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20Upgradeable", + "name": "token", + "type": "address" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "syncCash", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "src", + "type": "address" + }, + { + "internalType": "address", + "name": "dst", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "underlying", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-803/arbitrumone.ts b/simulations/vip-803/arbitrumone.ts new file mode 100644 index 000000000..bc0a697b7 --- /dev/null +++ b/simulations/vip-803/arbitrumone.ts @@ -0,0 +1,56 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import { ARBITRUMONE_ISOLATED_VTOKENS, ARBITRUMONE_LST_COMPTROLLER } from "../../vips/vip-803/addresses/arbitrumone"; +import vip803 from "../../vips/vip-803/bscmainnet"; +import COMPTROLLER_ABI from "./abi/ILComptroller.json"; +import VTOKEN_ABI from "./abi/ILVToken.json"; + +const BLOCK_NUMBER = 449553978; + +const ERC20_ABI = ["function balanceOf(address) view returns (uint256)"]; + +forking(BLOCK_NUMBER, async () => { + const provider = ethers.provider; + + describe("Pre-VIP behaviour", () => { + it("LST pool should have the expected isolated vtokens", async () => { + const comptroller = new ethers.Contract(ARBITRUMONE_LST_COMPTROLLER, COMPTROLLER_ABI, provider); + const allMarkets: string[] = (await comptroller.getAllMarkets()).map((m: string) => m.toLowerCase()); + for (const vToken of ARBITRUMONE_ISOLATED_VTOKENS) { + expect(allMarkets).to.include(vToken.toLowerCase()); + } + }); + }); + + testForkedNetworkVipCommands( + "VIP-803 Grant syncCash permissions and call syncCash on isolated pools", + await vip803(), + ); + + describe("Post-VIP behaviour", () => { + for (const vTokenAddress of ARBITRUMONE_ISOLATED_VTOKENS) { + describe(`VToken ${vTokenAddress}`, () => { + let vToken: Contract; + + before(async () => { + vToken = new ethers.Contract(vTokenAddress, VTOKEN_ABI, provider); + }); + + it("should have internalCash equal to underlying token balance", async () => { + const internalCash = await vToken.internalCash(); + const underlyingAddress = await vToken.underlying(); + const underlyingToken = new ethers.Contract(underlyingAddress, ERC20_ABI, provider); + const underlyingBalance = await underlyingToken.balanceOf(vTokenAddress); + expect(internalCash).to.equal(underlyingBalance); + }); + + it("should allow accrueInterest to succeed", async () => { + await expect(vToken.callStatic.accrueInterest()).to.not.be.reverted; + }); + }); + } + }); +}); diff --git a/simulations/vip-803/ethereum.ts b/simulations/vip-803/ethereum.ts new file mode 100644 index 000000000..de4269993 --- /dev/null +++ b/simulations/vip-803/ethereum.ts @@ -0,0 +1,80 @@ +import { expect } from "chai"; +import { Contract } from "ethers"; +import { ethers } from "hardhat"; +import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; + +import { + ETHEREUM_CURVE_COMPTROLLER, + ETHEREUM_CURVE_VTOKENS, + ETHEREUM_ETHENA_COMPTROLLER, + ETHEREUM_ETHENA_VTOKENS, + ETHEREUM_ISOLATED_VTOKENS, + ETHEREUM_LST_COMPTROLLER, + ETHEREUM_LST_VTOKENS, +} from "../../vips/vip-803/addresses/ethereum"; +import vip803 from "../../vips/vip-803/bscmainnet"; +import COMPTROLLER_ABI from "./abi/ILComptroller.json"; +import VTOKEN_ABI from "./abi/ILVToken.json"; + +const BLOCK_NUMBER = 24818762; + +const ERC20_ABI = ["function balanceOf(address) view returns (uint256)"]; + +forking(BLOCK_NUMBER, async () => { + const provider = ethers.provider; + + describe("Pre-VIP behaviour", () => { + it("Curve pool should have the expected isolated vtokens", async () => { + const comptroller = new ethers.Contract(ETHEREUM_CURVE_COMPTROLLER, COMPTROLLER_ABI, provider); + const allMarkets: string[] = (await comptroller.getAllMarkets()).map((m: string) => m.toLowerCase()); + for (const vToken of ETHEREUM_CURVE_VTOKENS) { + expect(allMarkets).to.include(vToken.toLowerCase()); + } + }); + + it("LST pool should have the expected isolated vtokens", async () => { + const comptroller = new ethers.Contract(ETHEREUM_LST_COMPTROLLER, COMPTROLLER_ABI, provider); + const allMarkets: string[] = (await comptroller.getAllMarkets()).map((m: string) => m.toLowerCase()); + for (const vToken of ETHEREUM_LST_VTOKENS) { + expect(allMarkets).to.include(vToken.toLowerCase()); + } + }); + + it("Ethena pool should have the expected isolated vtokens", async () => { + const comptroller = new ethers.Contract(ETHEREUM_ETHENA_COMPTROLLER, COMPTROLLER_ABI, provider); + const allMarkets: string[] = (await comptroller.getAllMarkets()).map((m: string) => m.toLowerCase()); + for (const vToken of ETHEREUM_ETHENA_VTOKENS) { + expect(allMarkets).to.include(vToken.toLowerCase()); + } + }); + }); + + testForkedNetworkVipCommands( + "VIP-803 Grant syncCash permissions and call syncCash on isolated pools", + await vip803(), + ); + + describe("Post-VIP behaviour", () => { + for (const vTokenAddress of ETHEREUM_ISOLATED_VTOKENS) { + describe(`VToken ${vTokenAddress}`, () => { + let vToken: Contract; + + before(async () => { + vToken = new ethers.Contract(vTokenAddress, VTOKEN_ABI, provider); + }); + + it("should have internalCash equal to underlying token balance", async () => { + const internalCash = await vToken.internalCash(); + const underlyingAddress = await vToken.underlying(); + const underlyingToken = new ethers.Contract(underlyingAddress, ERC20_ABI, provider); + const underlyingBalance = await underlyingToken.balanceOf(vTokenAddress); + expect(internalCash).to.equal(underlyingBalance); + }); + + it("should allow accrueInterest to succeed", async () => { + await expect(vToken.callStatic.accrueInterest()).to.not.be.reverted; + }); + }); + } + }); +}); diff --git a/vips/vip-803/addresses/arbitrumone.ts b/vips/vip-803/addresses/arbitrumone.ts new file mode 100644 index 000000000..7eb78a904 --- /dev/null +++ b/vips/vip-803/addresses/arbitrumone.ts @@ -0,0 +1,13 @@ +import { LzChainId } from "src/types"; + +export const ARBITRUMONE_ACM = "0xD9dD18EB0cf10CbA837677f28A8F9Bda4bc2b157"; +export const ARBITRUMONE_NORMAL_TIMELOCK = "0x4b94589Cc23F618687790036726f744D602c4017"; +export const ARBITRUMONE_DST_CHAIN_ID = LzChainId.arbitrumone; + +export const ARBITRUMONE_LST_COMPTROLLER = "0x52bAB1aF7Ff770551BD05b9FC2329a0Bf5E23F16"; + +export const ARBITRUMONE_ISOLATED_VTOKENS = [ + "0x39D6d13Ea59548637104E40e729E4aABE27FE106", // vWETH_LiquidStakedETH + "0x246a35E79a3a0618535A469aDaF5091cAA9f7E88", // vweETH_LiquidStakedETH + "0x9df6B5132135f14719696bBAe3C54BAb272fDb16", // vwstETH_LiquidStakedETH +]; diff --git a/vips/vip-803/addresses/ethereum.ts b/vips/vip-803/addresses/ethereum.ts new file mode 100644 index 000000000..73f71df91 --- /dev/null +++ b/vips/vip-803/addresses/ethereum.ts @@ -0,0 +1,39 @@ +import { LzChainId } from "src/types"; + +export const ETHEREUM_ACM = "0x230058da2D23eb8836EC5DB7037ef7250c56E25E"; +export const ETHEREUM_NORMAL_TIMELOCK = "0xd969E79406c35E80750aAae061D402Aab9325714"; +export const ETHEREUM_DST_CHAIN_ID = LzChainId.ethereum; + +export const ETHEREUM_CURVE_COMPTROLLER = "0x67aA3eCc5831a65A5Ba7be76BED3B5dc7DB60796"; +export const ETHEREUM_LST_COMPTROLLER = "0xF522cd0360EF8c2FF48B648d53EA1717Ec0F3Ac3"; +export const ETHEREUM_ETHENA_COMPTROLLER = "0x562d2b6FF1dbf5f63E233662416782318cC081E4"; + +export const ETHEREUM_CURVE_VTOKENS = [ + "0x2d499800239C4CD3012473Cb1EAE33562F0A6933", // vcrvUSD_Curve + "0x30aD10Bd5Be62CAb37863C2BfcC6E8fb4fD85BDa", // vCRV_Curve +]; + +export const ETHEREUM_LST_VTOKENS = [ + "0xA854D35664c658280fFf27B6eDC6C4195c3229B3", // vezETH_LiquidStakedETH + "0x76697f8eaeA4bE01C678376aAb97498Ee8f80D5C", // vPT-weETH-26DEC2024_LiquidStakedETH + "0xDB6C345f864883a8F4cae87852Ac342589E76D1B", // vrsETH_LiquidStakedETH + "0xF9E9Fe17C00a8B96a8ac20c4E344C8688D7b947E", // vsfrxETH_LiquidStakedETH + "0xc82780Db1257C788F262FBbDA960B3706Dfdcaf2", // vWETH_LiquidStakedETH + "0x4a240F0ee138697726C8a3E43eFE6Ac3593432CB", // vwstETH_LiquidStakedETH + "0xb4933AF59868986316Ed37fa865C829Eba2df0C7", // vweETH_LiquidStakedETH + "0xEF26C64bC06A8dE4CA5D31f119835f9A1d9433b9", // vweETHs_LiquidStakedETH + "0xE0ee5dDeBFe0abe0a4Af50299D68b74Cec31668e", // vpufETH_LiquidStakedETH +]; + +export const ETHEREUM_ETHENA_VTOKENS = [ + "0x62D9E2010Cff87Bae05B91d5E04605ef864ABc3B", // vPT_USDe_27MAR2025_Ethena + "0xCca202a95E8096315E3F19E46e19E1b326634889", // vPT_sUSDE_27MAR2025_Ethena + "0xa8e7f9473635a5CB79646f14356a9Fc394CA111A", // vUSDC_Ethena + "0x0792b9c60C728C1D2Fd6665b3D7A08762a9b28e0", // vsUSDe_Ethena +]; + +export const ETHEREUM_ISOLATED_VTOKENS = [ + ...ETHEREUM_CURVE_VTOKENS, + ...ETHEREUM_LST_VTOKENS, + ...ETHEREUM_ETHENA_VTOKENS, +]; diff --git a/vips/vip-803/bscmainnet.ts b/vips/vip-803/bscmainnet.ts new file mode 100644 index 000000000..daca355ab --- /dev/null +++ b/vips/vip-803/bscmainnet.ts @@ -0,0 +1,118 @@ +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +import { + ARBITRUMONE_ACM, + ARBITRUMONE_DST_CHAIN_ID, + ARBITRUMONE_ISOLATED_VTOKENS, + ARBITRUMONE_NORMAL_TIMELOCK, +} from "./addresses/arbitrumone"; +import { + ETHEREUM_ACM, + ETHEREUM_DST_CHAIN_ID, + ETHEREUM_ISOLATED_VTOKENS, + ETHEREUM_NORMAL_TIMELOCK, +} from "./addresses/ethereum"; + +interface NetworkConfig { + name: string; + acm: string; + normalTimelock: string; + dstChainId: number; + isolatedVTokens: string[]; +} + +const NETWORKS: NetworkConfig[] = [ + { + name: "Ethereum", + acm: ETHEREUM_ACM, + normalTimelock: ETHEREUM_NORMAL_TIMELOCK, + dstChainId: ETHEREUM_DST_CHAIN_ID, + isolatedVTokens: ETHEREUM_ISOLATED_VTOKENS, + }, + { + name: "Arbitrum", + acm: ARBITRUMONE_ACM, + normalTimelock: ARBITRUMONE_NORMAL_TIMELOCK, + dstChainId: ARBITRUMONE_DST_CHAIN_ID, + isolatedVTokens: ARBITRUMONE_ISOLATED_VTOKENS, + }, +]; + +export const vip803 = () => { + const meta = { + version: "v2", + title: "VIP-803 [Non-BNB Chain] syncCash for Isolated Pool Markets", + description: `Following VIP-601 and VIP-602, which granted permissions and called syncCash() on all core pool markets across the seven non-BNB Chain Venus deployments, this VIP completes the internalCash initialization by targeting the remaining isolated pool markets on Ethereum and Arbitrum One. + +The root cause of the VToken inflation attack vulnerability is that _getCashPrior() previously returned IERC20(underlying).balanceOf(address(this)), allowing any party to artificially inflate the reported cash — and therefore the exchange rate — by transferring tokens directly to a VToken contract without minting shares. + +The fix (deployed in VIP-602) replaced this with an internalCash storage variable. The VToken beacon upgrade in VIP-602 applies to all VToken proxies on each network (both core and isolated pools), so isolated pool VTokens already have the new implementation. However, syncCash() was only called for core pool markets. Isolated pool markets still have internalCash uninitialized at zero. + +#### Changes + +**1. Grant syncCash() permission to the Normal Timelock for each isolated pool VToken on Ethereum and Arbitrum One** + +- **Function**: AccessControlManager.giveCallPermission(vToken, "syncCash()", normalTimelock) +- **Networks**: Ethereum Mainnet (15 VTokens across Curve, Liquid Staked ETH, and Ethena pools), Arbitrum One (3 VTokens in the Liquid Staked ETH pool) + +**2. Initialize internalCash via syncCash() on all isolated pool markets** + +- **Function**: syncCash() +- **Caller**: ACM-authorized governance timelock (after permission granted in step 1) +- **Effect**: Sets internalCash to the current real underlying balance, completing the security patch for all isolated pool VToken markets + +#### Affected Pools + +**Ethereum Mainnet:** +- Curve Pool (2 VTokens): vcrvUSD, vCRV +- Liquid Staked ETH Pool (9 VTokens): vezETH, vPT-weETH-26DEC2024, vrsETH, vsfrxETH, vWETH, vwstETH, vweETH, vweETHs, vpufETH +- Ethena Pool (4 VTokens): vPT_USDe_27MAR2025, vPT_sUSDE_27MAR2025, vUSDC, vsUSDe + +**Arbitrum One:** +- Liquid Staked ETH Pool (3 VTokens): vWETH, vweETH, vwstETH + +#### Summary + +If approved, this VIP will: +- Grant syncCash() call permissions to the Normal Timelock for all 15 Ethereum isolated pool VToken markets and all 3 Arbitrum One isolated pool VToken markets +- Call syncCash() on each market to initialize internalCash to the real underlying balance, completing the VToken inflation attack patch across all Venus isolated pool deployments on non-BNB chains + +#### References + +- GitHub PR (Isolated Pools patch): [https://github.com/VenusProtocol/isolated-pools/pull/551](https://github.com/VenusProtocol/isolated-pools/pull/551) +- VIP-601 (permission grant for core pools): governance proposal #601 +- VIP-602 (beacon upgrade + syncCash for core pools): governance proposal #602 + +**Voting options** +- For - I agree that Venus Protocol should proceed with this proposal +- Against - I do not think that Venus Protocol should proceed with this proposal +- Abstain - I am indifferent to whether Venus Protocol proceeds or not`, + 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( + NETWORKS.flatMap(({ acm, normalTimelock, dstChainId, isolatedVTokens }) => [ + // Grant syncCash() permission to the Normal Timelock for each isolated pool VToken + ...isolatedVTokens.map(vToken => ({ + target: acm, + signature: "giveCallPermission(address,string,address)", + params: [vToken, "syncCash()", normalTimelock], + dstChainId, + })), + // Call syncCash on each isolated pool VToken to initialize internalCash + ...isolatedVTokens.map(vToken => ({ + target: vToken, + signature: "syncCash()", + params: [], + dstChainId, + })), + ]), + meta, + ProposalType.REGULAR, + ); +}; + +export default vip803; From 7ca0ba7ed942ee11f17a630abd1beff8bef3dcc7 Mon Sep 17 00:00:00 2001 From: Fred Date: Fri, 10 Apr 2026 07:45:39 +0000 Subject: [PATCH 2/2] chore: prepare VIP-609 for proposal --- .../abi/ILComptroller.json | 0 .../{vip-803 => vip-609}/abi/ILVToken.json | 0 .../{vip-803 => vip-609}/arbitrumone.ts | 8 +- simulations/{vip-803 => vip-609}/ethereum.ts | 8 +- .../addresses/arbitrumone.ts | 0 .../addresses/ethereum.ts | 0 vips/vip-609/bscmainnet.ts | 121 ++++++++++++++++++ vips/vip-803/bscmainnet.ts | 118 ----------------- 8 files changed, 129 insertions(+), 126 deletions(-) rename simulations/{vip-803 => vip-609}/abi/ILComptroller.json (100%) rename simulations/{vip-803 => vip-609}/abi/ILVToken.json (100%) rename simulations/{vip-803 => vip-609}/arbitrumone.ts (91%) rename simulations/{vip-803 => vip-609}/ethereum.ts (94%) rename vips/{vip-803 => vip-609}/addresses/arbitrumone.ts (100%) rename vips/{vip-803 => vip-609}/addresses/ethereum.ts (100%) create mode 100644 vips/vip-609/bscmainnet.ts delete mode 100644 vips/vip-803/bscmainnet.ts diff --git a/simulations/vip-803/abi/ILComptroller.json b/simulations/vip-609/abi/ILComptroller.json similarity index 100% rename from simulations/vip-803/abi/ILComptroller.json rename to simulations/vip-609/abi/ILComptroller.json diff --git a/simulations/vip-803/abi/ILVToken.json b/simulations/vip-609/abi/ILVToken.json similarity index 100% rename from simulations/vip-803/abi/ILVToken.json rename to simulations/vip-609/abi/ILVToken.json diff --git a/simulations/vip-803/arbitrumone.ts b/simulations/vip-609/arbitrumone.ts similarity index 91% rename from simulations/vip-803/arbitrumone.ts rename to simulations/vip-609/arbitrumone.ts index bc0a697b7..9faf8d400 100644 --- a/simulations/vip-803/arbitrumone.ts +++ b/simulations/vip-609/arbitrumone.ts @@ -3,8 +3,8 @@ import { Contract } from "ethers"; import { ethers } from "hardhat"; import { forking, testForkedNetworkVipCommands } from "src/vip-framework"; -import { ARBITRUMONE_ISOLATED_VTOKENS, ARBITRUMONE_LST_COMPTROLLER } from "../../vips/vip-803/addresses/arbitrumone"; -import vip803 from "../../vips/vip-803/bscmainnet"; +import { ARBITRUMONE_ISOLATED_VTOKENS, ARBITRUMONE_LST_COMPTROLLER } from "../../vips/vip-609/addresses/arbitrumone"; +import vip609 from "../../vips/vip-609/bscmainnet"; import COMPTROLLER_ABI from "./abi/ILComptroller.json"; import VTOKEN_ABI from "./abi/ILVToken.json"; @@ -26,8 +26,8 @@ forking(BLOCK_NUMBER, async () => { }); testForkedNetworkVipCommands( - "VIP-803 Grant syncCash permissions and call syncCash on isolated pools", - await vip803(), + "VIP-609 Grant syncCash permissions and call syncCash on isolated pools", + await vip609(), ); describe("Post-VIP behaviour", () => { diff --git a/simulations/vip-803/ethereum.ts b/simulations/vip-609/ethereum.ts similarity index 94% rename from simulations/vip-803/ethereum.ts rename to simulations/vip-609/ethereum.ts index de4269993..8213142e2 100644 --- a/simulations/vip-803/ethereum.ts +++ b/simulations/vip-609/ethereum.ts @@ -11,8 +11,8 @@ import { ETHEREUM_ISOLATED_VTOKENS, ETHEREUM_LST_COMPTROLLER, ETHEREUM_LST_VTOKENS, -} from "../../vips/vip-803/addresses/ethereum"; -import vip803 from "../../vips/vip-803/bscmainnet"; +} from "../../vips/vip-609/addresses/ethereum"; +import vip609 from "../../vips/vip-609/bscmainnet"; import COMPTROLLER_ABI from "./abi/ILComptroller.json"; import VTOKEN_ABI from "./abi/ILVToken.json"; @@ -50,8 +50,8 @@ forking(BLOCK_NUMBER, async () => { }); testForkedNetworkVipCommands( - "VIP-803 Grant syncCash permissions and call syncCash on isolated pools", - await vip803(), + "VIP-609 Grant syncCash permissions and call syncCash on isolated pools", + await vip609(), ); describe("Post-VIP behaviour", () => { diff --git a/vips/vip-803/addresses/arbitrumone.ts b/vips/vip-609/addresses/arbitrumone.ts similarity index 100% rename from vips/vip-803/addresses/arbitrumone.ts rename to vips/vip-609/addresses/arbitrumone.ts diff --git a/vips/vip-803/addresses/ethereum.ts b/vips/vip-609/addresses/ethereum.ts similarity index 100% rename from vips/vip-803/addresses/ethereum.ts rename to vips/vip-609/addresses/ethereum.ts diff --git a/vips/vip-609/bscmainnet.ts b/vips/vip-609/bscmainnet.ts new file mode 100644 index 000000000..03468da11 --- /dev/null +++ b/vips/vip-609/bscmainnet.ts @@ -0,0 +1,121 @@ +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +import { + ARBITRUMONE_ACM, + ARBITRUMONE_DST_CHAIN_ID, + ARBITRUMONE_ISOLATED_VTOKENS, + ARBITRUMONE_NORMAL_TIMELOCK, +} from "./addresses/arbitrumone"; +import { + ETHEREUM_ACM, + ETHEREUM_DST_CHAIN_ID, + ETHEREUM_ISOLATED_VTOKENS, + ETHEREUM_NORMAL_TIMELOCK, +} from "./addresses/ethereum"; + +interface NetworkConfig { + name: string; + acm: string; + normalTimelock: string; + dstChainId: number; + isolatedVTokens: string[]; +} + +const NETWORKS: NetworkConfig[] = [ + { + name: "Ethereum", + acm: ETHEREUM_ACM, + normalTimelock: ETHEREUM_NORMAL_TIMELOCK, + dstChainId: ETHEREUM_DST_CHAIN_ID, + isolatedVTokens: ETHEREUM_ISOLATED_VTOKENS, + }, + { + name: "Arbitrum", + acm: ARBITRUMONE_ACM, + normalTimelock: ARBITRUMONE_NORMAL_TIMELOCK, + dstChainId: ARBITRUMONE_DST_CHAIN_ID, + isolatedVTokens: ARBITRUMONE_ISOLATED_VTOKENS, + }, +]; + +export const vip609 = () => { + const meta = { + version: "v2", + title: "VIP-609 [Ethereum & Arbitrum One] Complete syncCash Initialization for Isolated Pool Markets", + description: `This proposal completes the VToken inflation attack fix initiated by VIP-601 and VIP-602 by calling syncCash() on all remaining isolated pool markets on Ethereum and Arbitrum One. VIP-601 and VIP-602 patched the vulnerability by upgrading the VToken beacon and initializing internalCash via syncCash(), but only for core pool markets across the 7 non-BNB chains. Isolated pool markets on Ethereum and Arbitrum One were not covered by those proposals and require syncCash() to be called to bring internalCash in line with each VToken's actual underlying token balance. + +No beacon upgrade is required. VIP-602's beacon upgrade applies to all VToken proxies on each network, as core and isolated pools share the same beacon. This VIP only grants syncCash() permission to the Normal Timelock via the Access Control Manager (ACM) and calls syncCash() for each outstanding isolated pool VToken. + +This is a maintenance-only action targeting deprecated isolated pool markets — it introduces no new features and has no impact on existing services or user funds. + +#### Proposed Changes + +1. **Ethereum — Grant syncCash() Permission and Initialize 15 Isolated Pool VTokens** +For each of the 15 isolated pool VTokens across the Curve Pool, Liquid Staked ETH Pool, and Ethena Pool on Ethereum: + +Then, for each VToken: +- **Contract**: Access Control Manager +- **Function**: giveCallPermission(address,string,address) +- **Parameters**: VToken address, "syncCash()", Normal Timelock address +- **Effect**: Grants the Normal Timelock permission to call syncCash() on each isolated pool VToken +- **Function**: syncCash() +- **Effect**: Sets internalCash = underlyingToken.balanceOf(vToken) for each of the 15 VTokens + +2. **Arbitrum One — Grant syncCash() Permission and Initialize 3 Isolated Pool VTokens** +For each of the 3 isolated pool VTokens in the Liquid Staked ETH Pool on Arbitrum One: + +Then, for each VToken: +- **Contract**: Access Control Manager +- **Function**: giveCallPermission(address,string,address) +- **Parameters**: VToken address, "syncCash()", Normal Timelock address +- **Effect**: Grants the Normal Timelock permission to call syncCash() on each isolated pool VToken +- **Function**: syncCash() +- **Effect**: Sets internalCash = underlyingToken.balanceOf(vToken) for each of the 3 VTokens + +#### Summary + +If approved, this VIP will: +- Call syncCash() on **15 Ethereum isolated pool VTokens** across the Curve, Liquid Staked ETH, and Ethena pools +- Call syncCash() on **3 Arbitrum One isolated pool VTokens** in the Liquid Staked ETH pool +- Fully initialize internalCash for all remaining isolated pool markets on non-BNB chains +- Complete the VToken inflation attack remediation started by VIP-601 and VIP-602 + +#### References + +- GitHub PR: [https://github.com/VenusProtocol/vips/pull/693](https://github.com/VenusProtocol/vips/pull/693) +- Related VIPs: VIP-601, VIP-602 + +#### Voting options + +- For - Execute this proposal +- Against - Do not execute this proposal +- Abstain - Indifferent to execution`, + forDescription: "Execute this proposal", + againstDescription: "Do not execute this proposal", + abstainDescription: "Indifferent to execution", + }; + + return makeProposal( + NETWORKS.flatMap(({ acm, normalTimelock, dstChainId, isolatedVTokens }) => [ + // Grant syncCash() permission to the Normal Timelock for each isolated pool VToken + ...isolatedVTokens.map(vToken => ({ + target: acm, + signature: "giveCallPermission(address,string,address)", + params: [vToken, "syncCash()", normalTimelock], + dstChainId, + })), + // Call syncCash on each isolated pool VToken to initialize internalCash + ...isolatedVTokens.map(vToken => ({ + target: vToken, + signature: "syncCash()", + params: [], + dstChainId, + })), + ]), + meta, + ProposalType.REGULAR, + ); +}; + +export default vip609; diff --git a/vips/vip-803/bscmainnet.ts b/vips/vip-803/bscmainnet.ts deleted file mode 100644 index daca355ab..000000000 --- a/vips/vip-803/bscmainnet.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { ProposalType } from "src/types"; -import { makeProposal } from "src/utils"; - -import { - ARBITRUMONE_ACM, - ARBITRUMONE_DST_CHAIN_ID, - ARBITRUMONE_ISOLATED_VTOKENS, - ARBITRUMONE_NORMAL_TIMELOCK, -} from "./addresses/arbitrumone"; -import { - ETHEREUM_ACM, - ETHEREUM_DST_CHAIN_ID, - ETHEREUM_ISOLATED_VTOKENS, - ETHEREUM_NORMAL_TIMELOCK, -} from "./addresses/ethereum"; - -interface NetworkConfig { - name: string; - acm: string; - normalTimelock: string; - dstChainId: number; - isolatedVTokens: string[]; -} - -const NETWORKS: NetworkConfig[] = [ - { - name: "Ethereum", - acm: ETHEREUM_ACM, - normalTimelock: ETHEREUM_NORMAL_TIMELOCK, - dstChainId: ETHEREUM_DST_CHAIN_ID, - isolatedVTokens: ETHEREUM_ISOLATED_VTOKENS, - }, - { - name: "Arbitrum", - acm: ARBITRUMONE_ACM, - normalTimelock: ARBITRUMONE_NORMAL_TIMELOCK, - dstChainId: ARBITRUMONE_DST_CHAIN_ID, - isolatedVTokens: ARBITRUMONE_ISOLATED_VTOKENS, - }, -]; - -export const vip803 = () => { - const meta = { - version: "v2", - title: "VIP-803 [Non-BNB Chain] syncCash for Isolated Pool Markets", - description: `Following VIP-601 and VIP-602, which granted permissions and called syncCash() on all core pool markets across the seven non-BNB Chain Venus deployments, this VIP completes the internalCash initialization by targeting the remaining isolated pool markets on Ethereum and Arbitrum One. - -The root cause of the VToken inflation attack vulnerability is that _getCashPrior() previously returned IERC20(underlying).balanceOf(address(this)), allowing any party to artificially inflate the reported cash — and therefore the exchange rate — by transferring tokens directly to a VToken contract without minting shares. - -The fix (deployed in VIP-602) replaced this with an internalCash storage variable. The VToken beacon upgrade in VIP-602 applies to all VToken proxies on each network (both core and isolated pools), so isolated pool VTokens already have the new implementation. However, syncCash() was only called for core pool markets. Isolated pool markets still have internalCash uninitialized at zero. - -#### Changes - -**1. Grant syncCash() permission to the Normal Timelock for each isolated pool VToken on Ethereum and Arbitrum One** - -- **Function**: AccessControlManager.giveCallPermission(vToken, "syncCash()", normalTimelock) -- **Networks**: Ethereum Mainnet (15 VTokens across Curve, Liquid Staked ETH, and Ethena pools), Arbitrum One (3 VTokens in the Liquid Staked ETH pool) - -**2. Initialize internalCash via syncCash() on all isolated pool markets** - -- **Function**: syncCash() -- **Caller**: ACM-authorized governance timelock (after permission granted in step 1) -- **Effect**: Sets internalCash to the current real underlying balance, completing the security patch for all isolated pool VToken markets - -#### Affected Pools - -**Ethereum Mainnet:** -- Curve Pool (2 VTokens): vcrvUSD, vCRV -- Liquid Staked ETH Pool (9 VTokens): vezETH, vPT-weETH-26DEC2024, vrsETH, vsfrxETH, vWETH, vwstETH, vweETH, vweETHs, vpufETH -- Ethena Pool (4 VTokens): vPT_USDe_27MAR2025, vPT_sUSDE_27MAR2025, vUSDC, vsUSDe - -**Arbitrum One:** -- Liquid Staked ETH Pool (3 VTokens): vWETH, vweETH, vwstETH - -#### Summary - -If approved, this VIP will: -- Grant syncCash() call permissions to the Normal Timelock for all 15 Ethereum isolated pool VToken markets and all 3 Arbitrum One isolated pool VToken markets -- Call syncCash() on each market to initialize internalCash to the real underlying balance, completing the VToken inflation attack patch across all Venus isolated pool deployments on non-BNB chains - -#### References - -- GitHub PR (Isolated Pools patch): [https://github.com/VenusProtocol/isolated-pools/pull/551](https://github.com/VenusProtocol/isolated-pools/pull/551) -- VIP-601 (permission grant for core pools): governance proposal #601 -- VIP-602 (beacon upgrade + syncCash for core pools): governance proposal #602 - -**Voting options** -- For - I agree that Venus Protocol should proceed with this proposal -- Against - I do not think that Venus Protocol should proceed with this proposal -- Abstain - I am indifferent to whether Venus Protocol proceeds or not`, - 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( - NETWORKS.flatMap(({ acm, normalTimelock, dstChainId, isolatedVTokens }) => [ - // Grant syncCash() permission to the Normal Timelock for each isolated pool VToken - ...isolatedVTokens.map(vToken => ({ - target: acm, - signature: "giveCallPermission(address,string,address)", - params: [vToken, "syncCash()", normalTimelock], - dstChainId, - })), - // Call syncCash on each isolated pool VToken to initialize internalCash - ...isolatedVTokens.map(vToken => ({ - target: vToken, - signature: "syncCash()", - params: [], - dstChainId, - })), - ]), - meta, - ProposalType.REGULAR, - ); -}; - -export default vip803;