Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions spot-contracts/contracts/_interfaces/IVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ error UnauthorizedTransferOut(IERC20Upgradeable token);
/// @notice Expected vault assets to be deployed.
error NoDeployment();

/// @notice Expected the number of vault assets deployed to be under the limit.
error DeployedCountOverLimit();

/*
* @title IVault
*
Expand Down
11 changes: 7 additions & 4 deletions spot-contracts/contracts/vaults/RolloverVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/

import { TrancheData, TrancheHelpers, BondHelpers } from "../_utils/BondHelpers.sol";
import { IERC20Upgradeable, IPerpetualTranche, IBondIssuer, IBondController, ITranche } from "../_interfaces/IPerpetualTranche.sol";
import { IVault, UnexpectedAsset, UnauthorizedTransferOut, NoDeployment } from "../_interfaces/IVault.sol";

// TODO: add mint cap
// TODO: limit size of vault assets
import { IVault, UnexpectedAsset, UnauthorizedTransferOut, NoDeployment, DeployedCountOverLimit } from "../_interfaces/IVault.sol";

/// @notice Storage array access out of bounds.
error OutOfBounds();
Expand Down Expand Up @@ -75,6 +72,9 @@ contract RolloverVault is
uint8 private constant PERP_PRICE_DECIMALS = 8;
uint256 private constant PERP_UNIT_PRICE = (10**PERP_PRICE_DECIMALS);

/// @dev The maximum number of deployed assets that can be held in this vault at any given time.
uint256 public constant MAX_DEPLOYED_COUNT = 47;

//--------------------------------------------------------------------------
// ASSETS
//
Expand Down Expand Up @@ -446,6 +446,9 @@ contract RolloverVault is
if (balance > 0 && !isHeld) {
// Inserts new token into the deployed assets list.
_deployed.add(address(token));
if (_deployed.length() > MAX_DEPLOYED_COUNT) {
revert DeployedCountOverLimit();
}
}

if (balance == 0 && isHeld) {
Expand Down
38 changes: 38 additions & 0 deletions spot-contracts/test/vaults/RolloverVault_deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1056,4 +1056,42 @@ describe("RolloverVault", function () {
});
});
});

describe("deploy limit", function () {
async function setupDeployment() {
const curBondIn = await bondAt(await perp.callStatic.getDepositBond());
await advancePerpQueueToRollover(perp, curBondIn);
const newBondIn = await bondAt(await perp.callStatic.getDepositBond());
const newTranchesIn = await getTranches(newBondIn);
await pricingStrategy.computeTranchePrice
.whenCalledWith(newTranchesIn[0].address)
.returns(toPriceFixedPtAmt("1"));
await discountStrategy.computeTrancheDiscount
.whenCalledWith(newTranchesIn[0].address)
.returns(toDiscountFixedPtAmt("1"));
await collateralToken.transfer(vault.address, toFixedPtAmt("10"));
}

beforeEach(async function () {
for (let i = 0; i < 23; i++) {
await setupDeployment();
await vault.deploy();
}
});

it("should revert after limit is reached", async function () {
expect(await vault.deployedCount()).to.eq(46);
await setupDeployment();
await expect(vault.deploy()).to.be.revertedWith("DeployedCountOverLimit");
});
it("redemption should be within gas limit", async function () {
await collateralToken.approve(vault.address, toFixedPtAmt("10"));
await vault.deposit(toFixedPtAmt("10"));
await expect(vault.redeem(await vault.balanceOf(await deployer.getAddress()))).not.to.be.reverted;
});

it("recovery should be within gas limit", async function () {
await expect(vault.recover()).not.to.be.reverted;
});
});
});