Skip to content

Commit

Permalink
fix: VPB-03 maximum should depend on chain and whether the contracts …
Browse files Browse the repository at this point in the history
…are time or block-based
  • Loading branch information
Debugger022 committed Jan 10, 2024
1 parent 88265c3 commit ee4c083
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 21 deletions.
14 changes: 13 additions & 1 deletion contracts/VToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ contract VToken is

uint256 internal constant DEFAULT_PROTOCOL_SEIZE_SHARE_MANTISSA = 5e16; // 5%

// Maximum fraction of interest that can be set aside for reserves
uint256 internal constant MAX_RESERVE_FACTOR_MANTISSA = 1e18;

// Maximum borrow rate that can ever be applied (.0005% / slot(block or second))
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
uint256 internal immutable MAX_BORROW_RATE_MANTISSA;

/**
* Reentrancy Guard **
*/
Expand All @@ -72,9 +79,14 @@ contract VToken is
* @param blocksPerYear_ The number of blocks per year
* @custom:oz-upgrades-unsafe-allow constructor
*/
constructor(bool timeBased_, uint256 blocksPerYear_) TimeManagerV8(timeBased_, blocksPerYear_) {
constructor(
bool timeBased_,
uint256 blocksPerYear_,
uint256 maxBorrowRateMantissa_
) TimeManagerV8(timeBased_, blocksPerYear_) {
// Note that the contract is upgradeable. Use initialize() or reinitializers
// to set the state variables.
MAX_BORROW_RATE_MANTISSA = maxBorrowRateMantissa_;
_disableInitializers();
}

Expand Down
6 changes: 0 additions & 6 deletions contracts/VTokenInterfaces.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,6 @@ contract VTokenStorage {
*/
address payable public protocolShareReserve;

// Maximum borrow rate that can ever be applied (.0005% / slot(block or second))
uint256 internal constant MAX_BORROW_RATE_MANTISSA = 0.0005e16;

// Maximum fraction of interest that can be set aside for reserves
uint256 internal constant MAX_RESERVE_FACTOR_MANTISSA = 1e18;

/**
* @notice Contract which oversees inter-vToken operations
*/
Expand Down
6 changes: 5 additions & 1 deletion contracts/test/UpgradedVToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ contract UpgradedVToken is VToken {
* @param blocksPerYear_ The number of blocks per year
* @custom:oz-upgrades-unsafe-allow constructor
*/
constructor(bool timeBased_, uint256 blocksPerYear_) VToken(timeBased_, blocksPerYear_) {
constructor(
bool timeBased_,
uint256 blocksPerYear_,
uint256 maxBorrowRateMantissa_
) VToken(timeBased_, blocksPerYear_, maxBorrowRateMantissa_) {
// Note that the contract is upgradeable. Use initialize() or reinitializers
// to set the state variables.
_disableInitializers();
Expand Down
8 changes: 6 additions & 2 deletions contracts/test/VTokenHarness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ contract VTokenHarness is VToken {
* @param blocksPerYear_ The number of blocks per year
* @custom:oz-upgrades-unsafe-allow constructor
*/
constructor(bool timeBased_, uint256 blocksPerYear_) VToken(timeBased_, blocksPerYear_) {
constructor(
bool timeBased_,
uint256 blocksPerYear_,
uint256 maxBorrowRateMantissa_
) VToken(timeBased_, blocksPerYear_, maxBorrowRateMantissa_) {
// Note that the contract is upgradeable. Use initialize() or reinitializers
// to set the state variables.
_disableInitializers();
Expand Down Expand Up @@ -118,7 +122,7 @@ contract VTokenHarness is VToken {
return (snapshot.principal, snapshot.interestIndex);
}

function getBorrowRateMaxMantissa() external pure returns (uint256) {
function getBorrowRateMaxMantissa() external view returns (uint256) {
return MAX_BORROW_RATE_MANTISSA;
}

Expand Down
3 changes: 2 additions & 1 deletion deploy/009-deploy-vtokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { tokensConfig, poolConfig, preconfiguredAddresses } = await getConfig(hre.network.name);

const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.network.name);
const maxBorrowRateMantissa = BigNumber.from(0.0005e16);

const accessControlManagerAddress = await toAddress(
preconfiguredAddresses.AccessControlManager || "AccessControlManager",
Expand All @@ -31,7 +32,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const vTokenImpl: DeployResult = await deploy("VTokenImpl", {
contract: "VToken",
from: deployer,
args: [isTimeBased, blocksPerYear],
args: [isTimeBased, blocksPerYear, maxBorrowRateMantissa],
log: true,
autoMine: true,
});
Expand Down
3 changes: 2 additions & 1 deletion deploy/016-deploy-beacon-implementations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.network.name);

const poolRegistry = await ethers.getContract("PoolRegistry");
const maxBorrowRateMantissa = ethers.BigNumber.from(0.0005e16);

// Comptroller Implementation
await deploy("ComptrollerImpl", {
Expand All @@ -27,7 +28,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
await deploy("VTokenImpl", {
contract: "VToken",
from: deployer,
args: [isTimeBased, blocksPerYear],
args: [isTimeBased, blocksPerYear, maxBorrowRateMantissa],
log: true,
autoMine: true,
});
Expand Down
4 changes: 3 additions & 1 deletion tests/hardhat/Rewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ async function rewardsFixture(isTimeBased: boolean) {
const btcPrice = "21000.34";
const daiPrice = "1";

const maxBorrowRateMantissa = ethers.BigNumber.from(0.0005e16);

fakePriceOracle.getUnderlyingPrice.returns((args: any) => {
if (vDAI && vWBTC) {
if (args[0] === vDAI.address) {
Expand Down Expand Up @@ -104,7 +106,7 @@ async function rewardsFixture(isTimeBased: boolean) {

// Deploy VTokens
const RewardsDistributor = await ethers.getContractFactory("RewardsDistributor");
const vTokenBeacon = await deployVTokenBeacon(undefined, isTimeBased, blocksPerYear);
const vTokenBeacon = await deployVTokenBeacon(undefined, maxBorrowRateMantissa, isTimeBased, blocksPerYear);
vWBTC = await makeVToken({
underlying: mockWBTC,
comptroller: comptrollerProxy,
Expand Down
16 changes: 10 additions & 6 deletions tests/hardhat/Shortfall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ async function shortfallFixture() {
mockBUSD = await MockBUSD.deploy("BUSD", "BUSD", 18);
await mockBUSD.faucet(convertToUnit(100000, 18));

const maxBorrowRateMantissa = ethers.BigNumber.from(0.0005e16);

const AccessControlManagerFactor = await ethers.getContractFactory("AccessControlManager");
accessControlManager = await AccessControlManagerFactor.deploy();
fakeRiskFund = await smock.fake<IRiskFund>("IRiskFund");
Expand Down Expand Up @@ -104,9 +106,9 @@ async function shortfallFixture() {
});

const VToken = await smock.mock<VToken__factory>("VToken");
vDAI = await VToken.deploy(isTimeBased, blocksPerYear);
vWBTC = await VToken.deploy(isTimeBased, blocksPerYear);
vFloki = await VToken.deploy(isTimeBased, blocksPerYear);
vDAI = await VToken.deploy(isTimeBased, blocksPerYear, maxBorrowRateMantissa);
vWBTC = await VToken.deploy(isTimeBased, blocksPerYear, maxBorrowRateMantissa);
vFloki = await VToken.deploy(isTimeBased, blocksPerYear, maxBorrowRateMantissa);

await vWBTC.setVariable("decimals", 8);
vDAI.decimals.returns(18);
Expand Down Expand Up @@ -189,6 +191,8 @@ async function timeBasedhortfallFixture() {
waitForFirstBidder = 300;
nextBidderBlockOrTimestampLimit = 300;

const maxBorrowRateMantissa = ethers.BigNumber.from(0.0005e16);

const MockBUSD = await ethers.getContractFactory("MockToken");
mockBUSD = await MockBUSD.deploy("BUSD", "BUSD", 18);
await mockBUSD.faucet(convertToUnit(100000, 18));
Expand Down Expand Up @@ -236,9 +240,9 @@ async function timeBasedhortfallFixture() {
});

const VToken = await smock.mock<VToken__factory>("VToken");
vDAI = await VToken.deploy(isTimeBased, blocksPerYear);
vWBTC = await VToken.deploy(isTimeBased, blocksPerYear);
vFloki = await VToken.deploy(isTimeBased, blocksPerYear);
vDAI = await VToken.deploy(isTimeBased, blocksPerYear, maxBorrowRateMantissa);
vWBTC = await VToken.deploy(isTimeBased, blocksPerYear, maxBorrowRateMantissa);
vFloki = await VToken.deploy(isTimeBased, blocksPerYear, maxBorrowRateMantissa);

await vWBTC.setVariable("decimals", 8);
vDAI.decimals.returns(18);
Expand Down
4 changes: 3 additions & 1 deletion tests/hardhat/UpgradedVToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@ for (const isTimeBased of [false, true]) {
});

it("Upgrade the vToken contract", async function () {
const maxBorrowRateMantissa = ethers.BigNumber.from(0.0005e16);

const vToken = await ethers.getContractFactory("UpgradedVToken");
const vTokenDeploy = await vToken.deploy(isTimeBased, slotsPerYear);
const vTokenDeploy = await vToken.deploy(isTimeBased, slotsPerYear, maxBorrowRateMantissa);

await vTokenDeploy.deployed();

Expand Down
6 changes: 5 additions & 1 deletion tests/hardhat/util/TokenTestHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ interface VTokenParameters {
beacon: UpgradeableBeacon;
isTimeBased: boolean;
blocksPerYear: BigNumberish;
maxBorrowRateMantissa: BigNumberish;
}

const getNameAndSymbol = async (underlying: AddressOrContract): Promise<[string, string]> => {
Expand Down Expand Up @@ -74,12 +75,13 @@ export type AnyVTokenFactory = VTokenHarness__factory | VToken__factory;

export const deployVTokenBeacon = async <VTokenFactory extends AnyVTokenFactory = VToken__factory>(
{ kind }: { kind: string } = { kind: "VToken" },
maxBorrowRateMantissa: BigNumberish = BigNumber.from(0.0005e16),
isTimeBased: boolean = false,
blocksPerYear: BigNumberish = BSC_BLOCKS_PER_YEAR,
): Promise<UpgradeableBeacon> => {
const VToken = await ethers.getContractFactory<VTokenFactory>(kind);
const vTokenBeacon = (await upgrades.deployBeacon(VToken, {
constructorArgs: [isTimeBased, blocksPerYear],
constructorArgs: [isTimeBased, blocksPerYear, maxBorrowRateMantissa],
})) as UpgradeableBeacon;
return vTokenBeacon;
};
Expand All @@ -106,10 +108,12 @@ const deployVTokenDependencies = async <VTokenFactory extends AnyVTokenFactory =
shortfall: params.shortfall || (await smock.fake("Shortfall")),
protocolShareReserve: params.protocolShareReserve || (await smock.fake("ProtocolShareReserve")),
reserveFactorMantissa: params.reserveFactorMantissa || parseUnits("0.3", 18),
maxBorrowRateMantissa: params.maxBorrowRateMantissa || BigNumber.from(0.0005e16),
beacon:
params.beacon ||
(await deployVTokenBeacon<VTokenFactory>(
{ kind },
params.maxBorrowRateMantissa || BigNumber.from(0.0005e16),
params.isTimeBased || false,
params.blocksPerYear === undefined ? BSC_BLOCKS_PER_YEAR : params.blocksPerYear,
)),
Expand Down

0 comments on commit ee4c083

Please sign in to comment.