From eef333aaae12d336407095dbcab61a2462bff207 Mon Sep 17 00:00:00 2001 From: web3rover Date: Mon, 7 Oct 2024 13:58:06 +0400 Subject: [PATCH 1/3] fix: added vip for testnet and mainnet --- simulations/vip-381/abi/VTokenCorePool.json | 688 ++++++++++++++++++ simulations/vip-381/bscmainnet.ts | 57 ++ simulations/vip-381/bsctestnet.ts | 48 ++ src/vip-framework/abi/twoKinksIRM.json | 128 ++++ src/vip-framework/checks/interestRateModel.ts | 65 ++ vips/vip-381/bscmainnet.ts | 30 + vips/vip-381/bsctestnet.ts | 30 + 7 files changed, 1046 insertions(+) create mode 100644 simulations/vip-381/abi/VTokenCorePool.json create mode 100644 simulations/vip-381/bscmainnet.ts create mode 100644 simulations/vip-381/bsctestnet.ts create mode 100644 src/vip-framework/abi/twoKinksIRM.json create mode 100644 vips/vip-381/bscmainnet.ts create mode 100644 vips/vip-381/bsctestnet.ts diff --git a/simulations/vip-381/abi/VTokenCorePool.json b/simulations/vip-381/abi/VTokenCorePool.json new file mode 100644 index 000000000..c0187a7ca --- /dev/null +++ b/simulations/vip-381/abi/VTokenCorePool.json @@ -0,0 +1,688 @@ +[ + { + "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 payable", "name": "admin_", "type": "address" }, + { "internalType": "address", "name": "implementation_", "type": "address" }, + { "internalType": "bytes", "name": "becomeImplementationData", "type": "bytes" } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "cashPrior", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "interestAccumulated", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "borrowIndex", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "AccrueInterest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "borrowAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "accountBorrows", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "Borrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "error", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "info", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "detail", "type": "uint256" } + ], + "name": "Failure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "liquidator", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "repayAmount", "type": "uint256" }, + { "indexed": false, "internalType": "address", "name": "vTokenCollateral", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "LiquidateBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "minter", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "mintAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "mintTokens", "type": "uint256" } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldAdmin", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract ComptrollerInterface", + "name": "oldComptroller", + "type": "address" + }, + { "indexed": false, "internalType": "contract ComptrollerInterface", "name": "newComptroller", "type": "address" } + ], + "name": "NewComptroller", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldImplementation", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newImplementation", "type": "address" } + ], + "name": "NewImplementation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract InterestRateModel", + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract InterestRateModel", + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldPendingAdmin", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newPendingAdmin", "type": "address" } + ], + "name": "NewPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldReserveFactorMantissa", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newReserveFactorMantissa", "type": "uint256" } + ], + "name": "NewReserveFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "redeemer", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "redeemAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "redeemTokens", "type": "uint256" } + ], + "name": "Redeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "payer", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "repayAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "accountBorrows", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "RepayBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "benefactor", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "addAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newTotalReserves", "type": "uint256" } + ], + "name": "ReservesAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "admin", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "reduceAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newTotalReserves", "type": "uint256" } + ], + "name": "ReservesReduced", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { "payable": true, "stateMutability": "payable", "type": "fallback" }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "addAmount", "type": "uint256" }], + "name": "_addReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "reduceAmount", "type": "uint256" }], + "name": "_reduceReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract ComptrollerInterface", "name": "newComptroller", "type": "address" }], + "name": "_setComptroller", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "implementation_", "type": "address" }, + { "internalType": "bool", "name": "allowResign", "type": "bool" }, + { "internalType": "bytes", "name": "becomeImplementationData", "type": "bytes" } + ], + "name": "_setImplementation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract InterestRateModel", "name": "newInterestRateModel", "type": "address" }], + "name": "_setInterestRateModel", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address payable", "name": "newPendingAdmin", "type": "address" }], + "name": "_setPendingAdmin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "newReserveFactorMantissa", "type": "uint256" }], + "name": "_setReserveFactor", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [{ "internalType": "address payable", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], + "name": "balanceOfUnderlying", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "borrowAmount", "type": "uint256" }], + "name": "borrow", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "borrowBalanceCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "borrowBalanceStored", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [{ "internalType": "contract ComptrollerInterface", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }], + "name": "delegateToImplementation", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }], + "name": "delegateToViewImplementation", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getAccountSnapshot", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "implementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [{ "internalType": "contract InterestRateModel", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isVToken", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "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" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "mintAmount", "type": "uint256" }], + "name": "mint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [{ "internalType": "address payable", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "redeemTokens", "type": "uint256" }], + "name": "redeem", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "redeemAmount", "type": "uint256" }], + "name": "redeemUnderlying", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "repayAmount", "type": "uint256" }], + "name": "repayBorrow", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "repayAmount", "type": "uint256" } + ], + "name": "repayBorrowBehalf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "liquidator", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "seize", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "dst", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "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" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } +] diff --git a/simulations/vip-381/bscmainnet.ts b/simulations/vip-381/bscmainnet.ts new file mode 100644 index 000000000..ff9c5b5c5 --- /dev/null +++ b/simulations/vip-381/bscmainnet.ts @@ -0,0 +1,57 @@ +import { TransactionResponse } from "@ethersproject/providers"; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { expectEvents } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; +import { checkInterestRate, checkTwoKinksInterestRate } from "src/vip-framework/checks/interestRateModel"; + +import vip381, { IRM } from "../../vips/vip-381/bscmainnet"; +import VTOKEN_CORE_POOL_ABI from "./abi/VTokenCorePool.json"; + +const OLD_IRM = "0xDb8347b96c94Be24B9c077A4CDDAAD074F6480cf"; +const VBNB = "0xA07c5b74C9B40447a954e1466938b865b6BBea36"; + +forking(42904608, async () => { + const provider = ethers.provider; + + const vBNB = new ethers.Contract(VBNB, VTOKEN_CORE_POOL_ABI, provider); + + describe("Pre-VIP behaviour", async () => { + it("has expected interest rate model addresses", async () => { + expect(await vBNB.interestRateModel()).to.equal(OLD_IRM); + }); + + describe("old interest rate model parameters", async () => { + checkInterestRate(OLD_IRM, "vBNB", { + base: "0", + multiplier: "0.225", + jump: "6.8", + kink: "0.5", + }); + }); + }); + + testVip("VIP-381", await vip381(), { + callbackAfterExecution: async (txResponse: TransactionResponse) => { + await expectEvents(txResponse, [VTOKEN_CORE_POOL_ABI], ["NewMarketInterestRateModel"], [1]); + }, + }); + + describe("Post-VIP behavior", async () => { + it("has the new interest rate model addresses", async () => { + expect(await vBNB.interestRateModel()).to.equal(IRM); + }); + + describe("new interest rate model parameters", async () => { + checkTwoKinksInterestRate(IRM, "vBNB", { + base: "0", + multiplier: "0.225", + kink1: "0.4", + multiplier2: "0.5", + base2: "0.1", + kink2: "0.7", + jump: "6.8", + }); + }); + }); +}); diff --git a/simulations/vip-381/bsctestnet.ts b/simulations/vip-381/bsctestnet.ts new file mode 100644 index 000000000..e6ea467d8 --- /dev/null +++ b/simulations/vip-381/bsctestnet.ts @@ -0,0 +1,48 @@ +import { TransactionResponse } from "@ethersproject/providers"; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { expectEvents } from "src/utils"; +import { forking, testVip } from "src/vip-framework"; +import { checkTwoKinksInterestRate } from "src/vip-framework/checks/interestRateModel"; + +import vip381, { IRM } from "../../vips/vip-381/bsctestnet"; +import VTOKEN_CORE_POOL_ABI from "./abi/VTokenCorePool.json"; + +const OLD_IRM = "0x597F1eFCC8DD59598eD1944304814f60230BAe76"; +const VBNB = "0x2E7222e51c0f6e98610A1543Aa3836E092CDe62c"; + +forking(44524703, async () => { + const provider = ethers.provider; + + const vBNB = new ethers.Contract(VBNB, VTOKEN_CORE_POOL_ABI, provider); + + describe("Pre-VIP behaviour", async () => { + it("has expected interest rate model addresses", async () => { + expect(await vBNB.interestRateModel()).to.equal(OLD_IRM); + }); + }); + + testVip("VIP-381", await vip381(), { + callbackAfterExecution: async (txResponse: TransactionResponse) => { + await expectEvents(txResponse, [VTOKEN_CORE_POOL_ABI], ["NewMarketInterestRateModel"], [1]); + }, + }); + + describe("Post-VIP behavior", async () => { + it("has the new interest rate model addresses", async () => { + expect(await vBNB.interestRateModel()).to.equal(IRM); + }); + + describe("new interest rate model parameters", async () => { + checkTwoKinksInterestRate(IRM, "vBNB", { + base: "0", + multiplier: "0.225", + kink1: "0.4", + multiplier2: "0.5", + base2: "0.1", + kink2: "0.7", + jump: "6.8", + }); + }); + }); +}); diff --git a/src/vip-framework/abi/twoKinksIRM.json b/src/vip-framework/abi/twoKinksIRM.json new file mode 100644 index 000000000..e1eb77639 --- /dev/null +++ b/src/vip-framework/abi/twoKinksIRM.json @@ -0,0 +1,128 @@ +[ + { + "inputs": [ + { "internalType": "int256", "name": "baseRatePerYear_", "type": "int256" }, + { "internalType": "int256", "name": "multiplierPerYear_", "type": "int256" }, + { "internalType": "int256", "name": "kink1_", "type": "int256" }, + { "internalType": "int256", "name": "multiplier2PerYear_", "type": "int256" }, + { "internalType": "int256", "name": "baseRate2PerYear_", "type": "int256" }, + { "internalType": "int256", "name": "kink2_", "type": "int256" }, + { "internalType": "int256", "name": "jumpMultiplierPerYear_", "type": "int256" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "InvalidKink", "type": "error" }, + { "inputs": [], "name": "NegativeValueNotAllowed", "type": "error" }, + { + "inputs": [], + "name": "BASE_RATE_2_PER_BLOCK", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BASE_RATE_PER_BLOCK", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BLOCKS_PER_YEAR", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "JUMP_MULTIPLIER_PER_BLOCK", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "KINK_1", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "KINK_2", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MULTIPLIER_2_PER_BLOCK", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MULTIPLIER_PER_BLOCK", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RATE_1", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "RATE_2", + "outputs": [{ "internalType": "int256", "name": "", "type": "int256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "cash", "type": "uint256" }, + { "internalType": "uint256", "name": "borrows", "type": "uint256" }, + { "internalType": "uint256", "name": "reserves", "type": "uint256" } + ], + "name": "getBorrowRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "cash", "type": "uint256" }, + { "internalType": "uint256", "name": "borrows", "type": "uint256" }, + { "internalType": "uint256", "name": "reserves", "type": "uint256" }, + { "internalType": "uint256", "name": "reserveFactorMantissa", "type": "uint256" } + ], + "name": "getSupplyRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isInterestRateModel", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "cash", "type": "uint256" }, + { "internalType": "uint256", "name": "borrows", "type": "uint256" }, + { "internalType": "uint256", "name": "reserves", "type": "uint256" } + ], + "name": "utilizationRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "pure", + "type": "function" + } +] diff --git a/src/vip-framework/checks/interestRateModel.ts b/src/vip-framework/checks/interestRateModel.ts index 553ed864c..2366c9fd6 100644 --- a/src/vip-framework/checks/interestRateModel.ts +++ b/src/vip-framework/checks/interestRateModel.ts @@ -3,6 +3,7 @@ import { BigNumber, Contract, utils } from "ethers"; import { ethers } from "hardhat"; import RATE_MODEL_ABI from "../abi/il_rateModel.json"; +import TWO_KINKS_RATE_MODEL_ABI from "../abi/twoKinksIRM.json"; const DEFAULT_BLOCKS_PER_YEAR = BigNumber.from(10512000); @@ -53,3 +54,67 @@ export function checkInterestRate( } }); } + +export function checkTwoKinksInterestRate( + rateModelAddress: string, + symbol: string, + { + base, + multiplier, + kink1, + multiplier2, + base2, + kink2, + jump, + }: { + base: string; + multiplier: string; + kink1: string; + multiplier2: string; + base2: string; + kink2: string; + jump: string; + }, + blocksPerYear: BigNumber = DEFAULT_BLOCKS_PER_YEAR, +) { + describe(`${symbol} interest rate model`, () => { + let rateModel: Contract; + + before(async () => { + rateModel = await ethers.getContractAt(TWO_KINKS_RATE_MODEL_ABI, rateModelAddress); + }); + + it(`should have base = ${base}`, async () => { + const basePerBlock = utils.parseUnits(base, 18).div(blocksPerYear); + expect(await rateModel.BASE_RATE_PER_BLOCK()).to.equal(basePerBlock); + }); + + it(`should have multiplier = ${multiplier}`, async () => { + const multiplierPerBlock = utils.parseUnits(multiplier, 18).div(blocksPerYear); + expect(await rateModel.MULTIPLIER_PER_BLOCK()).to.equal(multiplierPerBlock); + }); + + it(`should have kink1 = ${kink1}`, async () => { + expect(await rateModel.KINK_1()).to.equal(utils.parseUnits(kink1, 18)); + }); + + it(`should have multiplier2 = ${multiplier2}`, async () => { + const multiplierPerBlock = utils.parseUnits(multiplier2, 18).div(blocksPerYear); + expect(await rateModel.MULTIPLIER_2_PER_BLOCK()).to.equal(multiplierPerBlock); + }); + + it(`should have base2 = ${base2}`, async () => { + const basePerBlock = utils.parseUnits(base2, 18).div(blocksPerYear); + expect(await rateModel.BASE_RATE_2_PER_BLOCK()).to.equal(basePerBlock); + }); + + it(`should have kink2 = ${kink2}`, async () => { + expect(await rateModel.KINK_2()).to.equal(utils.parseUnits(kink2, 18)); + }); + + it(`should have jump = ${jump}`, async () => { + const jumpPerBlock = utils.parseUnits(jump, 18).div(blocksPerYear); + expect(await rateModel.JUMP_MULTIPLIER_PER_BLOCK()).to.equal(jumpPerBlock); + }); + }); +} diff --git a/vips/vip-381/bscmainnet.ts b/vips/vip-381/bscmainnet.ts new file mode 100644 index 000000000..65c887847 --- /dev/null +++ b/vips/vip-381/bscmainnet.ts @@ -0,0 +1,30 @@ +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +export const IRM = "0xc9Be85a8851348f40A6f4773E0fAbC5459E38611"; +export const VBNB_ADMIN = "0x9A7890534d9d91d473F28cB97962d176e2B65f1d"; + +const vip381 = () => { + const meta = { + version: "v2", + title: "VIP-381", + description: ``, + 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( + [ + { + target: VBNB_ADMIN, + signature: "setInterestRateModel(address)", + params: [IRM], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip381; diff --git a/vips/vip-381/bsctestnet.ts b/vips/vip-381/bsctestnet.ts new file mode 100644 index 000000000..9a2af47ca --- /dev/null +++ b/vips/vip-381/bsctestnet.ts @@ -0,0 +1,30 @@ +import { ProposalType } from "src/types"; +import { makeProposal } from "src/utils"; + +export const IRM = "0x752B56f94c8dF2c3804c0Dd213Cf607FAa9D11b1"; +export const VBNB_ADMIN = "0x04109575c1dbB4ac2e59e60c783800ea10441BBe"; + +const vip381 = () => { + const meta = { + version: "v2", + title: "VIP-381", + description: ``, + 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( + [ + { + target: VBNB_ADMIN, + signature: "setInterestRateModel(address)", + params: [IRM], + }, + ], + meta, + ProposalType.REGULAR, + ); +}; + +export default vip381; From 0c57add8d58104273e060e89486fdd3a8793b9da Mon Sep 17 00:00:00 2001 From: web3rover Date: Mon, 7 Oct 2024 18:25:34 +0400 Subject: [PATCH 2/3] fix: use fast track timelock --- vips/vip-381/bscmainnet.ts | 2 +- vips/vip-381/bsctestnet.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vips/vip-381/bscmainnet.ts b/vips/vip-381/bscmainnet.ts index 65c887847..7c942423c 100644 --- a/vips/vip-381/bscmainnet.ts +++ b/vips/vip-381/bscmainnet.ts @@ -23,7 +23,7 @@ const vip381 = () => { }, ], meta, - ProposalType.REGULAR, + ProposalType.FAST_TRACK, ); }; diff --git a/vips/vip-381/bsctestnet.ts b/vips/vip-381/bsctestnet.ts index 9a2af47ca..a9a0078e2 100644 --- a/vips/vip-381/bsctestnet.ts +++ b/vips/vip-381/bsctestnet.ts @@ -23,7 +23,7 @@ const vip381 = () => { }, ], meta, - ProposalType.REGULAR, + ProposalType.FAST_TRACK, ); }; From 9c3b209aee694d0141d659c467fdb5817d2608e0 Mon Sep 17 00:00:00 2001 From: web3rover Date: Thu, 17 Oct 2024 13:55:11 +0400 Subject: [PATCH 3/3] fix: updated IRM address --- simulations/vip-381/bscmainnet.ts | 8 ++++---- simulations/vip-381/bsctestnet.ts | 10 +++++----- vips/vip-381/bscmainnet.ts | 2 +- vips/vip-381/bsctestnet.ts | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/simulations/vip-381/bscmainnet.ts b/simulations/vip-381/bscmainnet.ts index ff9c5b5c5..d1e6d4c39 100644 --- a/simulations/vip-381/bscmainnet.ts +++ b/simulations/vip-381/bscmainnet.ts @@ -11,7 +11,7 @@ import VTOKEN_CORE_POOL_ABI from "./abi/VTokenCorePool.json"; const OLD_IRM = "0xDb8347b96c94Be24B9c077A4CDDAAD074F6480cf"; const VBNB = "0xA07c5b74C9B40447a954e1466938b865b6BBea36"; -forking(42904608, async () => { +forking(43192903, async () => { const provider = ethers.provider; const vBNB = new ethers.Contract(VBNB, VTOKEN_CORE_POOL_ABI, provider); @@ -47,10 +47,10 @@ forking(42904608, async () => { base: "0", multiplier: "0.225", kink1: "0.4", - multiplier2: "0.5", - base2: "0.1", + multiplier2: "0.35", + base2: "0.21", kink2: "0.7", - jump: "6.8", + jump: "5", }); }); }); diff --git a/simulations/vip-381/bsctestnet.ts b/simulations/vip-381/bsctestnet.ts index e6ea467d8..84ed905e7 100644 --- a/simulations/vip-381/bsctestnet.ts +++ b/simulations/vip-381/bsctestnet.ts @@ -8,10 +8,10 @@ import { checkTwoKinksInterestRate } from "src/vip-framework/checks/interestRate import vip381, { IRM } from "../../vips/vip-381/bsctestnet"; import VTOKEN_CORE_POOL_ABI from "./abi/VTokenCorePool.json"; -const OLD_IRM = "0x597F1eFCC8DD59598eD1944304814f60230BAe76"; +const OLD_IRM = "0x752B56f94c8dF2c3804c0Dd213Cf607FAa9D11b1"; const VBNB = "0x2E7222e51c0f6e98610A1543Aa3836E092CDe62c"; -forking(44524703, async () => { +forking(44812630, async () => { const provider = ethers.provider; const vBNB = new ethers.Contract(VBNB, VTOKEN_CORE_POOL_ABI, provider); @@ -38,10 +38,10 @@ forking(44524703, async () => { base: "0", multiplier: "0.225", kink1: "0.4", - multiplier2: "0.5", - base2: "0.1", + multiplier2: "0.35", + base2: "0.21", kink2: "0.7", - jump: "6.8", + jump: "5", }); }); }); diff --git a/vips/vip-381/bscmainnet.ts b/vips/vip-381/bscmainnet.ts index 7c942423c..0f9e0291f 100644 --- a/vips/vip-381/bscmainnet.ts +++ b/vips/vip-381/bscmainnet.ts @@ -1,7 +1,7 @@ import { ProposalType } from "src/types"; import { makeProposal } from "src/utils"; -export const IRM = "0xc9Be85a8851348f40A6f4773E0fAbC5459E38611"; +export const IRM = "0xC682145a767ca98B743B895f1Bd2D4696bC9C2eC"; export const VBNB_ADMIN = "0x9A7890534d9d91d473F28cB97962d176e2B65f1d"; const vip381 = () => { diff --git a/vips/vip-381/bsctestnet.ts b/vips/vip-381/bsctestnet.ts index a9a0078e2..548a66c27 100644 --- a/vips/vip-381/bsctestnet.ts +++ b/vips/vip-381/bsctestnet.ts @@ -1,7 +1,7 @@ import { ProposalType } from "src/types"; import { makeProposal } from "src/utils"; -export const IRM = "0x752B56f94c8dF2c3804c0Dd213Cf607FAa9D11b1"; +export const IRM = "0x86954c6fCA6B464269Aa7011B143c4D93Dfa1146"; export const VBNB_ADMIN = "0x04109575c1dbB4ac2e59e60c783800ea10441BBe"; const vip381 = () => {