Skip to content

Commit

Permalink
Public method to recover individual assets"
Browse files Browse the repository at this point in the history
  • Loading branch information
aalavandhan committed Apr 18, 2023
1 parent 42e7a19 commit c3c9a86
Show file tree
Hide file tree
Showing 3 changed files with 340 additions and 43 deletions.
3 changes: 3 additions & 0 deletions spot-contracts/contracts/_interfaces/IVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ interface IVault {
/// @notice Recovers deployed funds.
function recover() external;

/// @notice Recovers a given deployed asset.
function recover(IERC20Upgradeable token) external;

/// @notice Deposits the underlying asset from {msg.sender} into the vault and mints notes.
/// @param amount The amount tokens to be deposited into the vault.
/// @return The amount of notes.
Expand Down
90 changes: 60 additions & 30 deletions spot-contracts/contracts/vaults/RolloverVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -164,18 +164,28 @@ contract RolloverVault is
/// @inheritdoc IVault
/// @dev Its safer to call `recover` before `deploy` so the full available balance can be deployed.
/// Reverts if there are no funds to deploy.
function deploy() public nonReentrant whenNotPaused {
function deploy() public override nonReentrant whenNotPaused {
TrancheData memory td = _tranche(perp.getDepositBond());
if (_rollover(perp, td) == 0) {
revert NoDeployment();
}
}

/// @inheritdoc IVault
function recover() public nonReentrant whenNotPaused {
function recover() public override nonReentrant whenNotPaused {
_redeemTranches();
}

/// @inheritdoc IVault
/// @dev Reverts when attempting to recover a tranche which is not part of the deployed list.
/// In the case of immature redemption, this method will recover other sibling tranches as well.
function recover(IERC20Upgradeable token) external override nonReentrant whenNotPaused {
if (!_deployed.contains(address(token))) {
revert UnexpectedAsset(token);
}
_redeemTranche(ITranche(address(token)));
}

/// @inheritdoc IVault
function deposit(uint256 amount) external override nonReentrant whenNotPaused returns (uint256) {
uint256 totalSupply_ = totalSupply();
Expand Down Expand Up @@ -283,6 +293,7 @@ contract RolloverVault is
// Private write methods

/// @dev Deposits underlying balance into the provided bond and receives tranche tokens in return.
/// And performs some book-keeping to keep track of the vault's assets.
function _tranche(IBondController bond) private returns (TrancheData memory) {
// Get bond's tranche data
TrancheData memory td = bond.getTrancheData();
Expand All @@ -309,6 +320,7 @@ contract RolloverVault is
}

/// @dev Rolls over freshly tranched tokens from the given bond for older tranches (close to maturity) from perp.
/// And performs some book-keeping to keep track of the vault's assets.
/// @return The amount of perps rolled over.
function _rollover(IPerpetualTranche perp_, TrancheData memory td) private returns (uint256) {
// NOTE: The first element of the list is the mature tranche,
Expand Down Expand Up @@ -385,37 +397,12 @@ contract RolloverVault is
return totalPerpRolledOver;
}

/// @notice Redeems the deployed tranche tokens for the underlying asset.
/// @dev Redeems all deployed tranches for the underlying asset and
/// performs internal book-keeping to keep track of the vault assets.
function _redeemTranches() private {
uint256 deployedCount_ = _deployed.length();
if (deployedCount_ <= 0) {
return;
}

for (uint256 i = 0; i < deployedCount_; i++) {
ITranche tranche = ITranche(_deployed.at(i));
IBondController bond = IBondController(tranche.bond());

// if bond has matured, redeem the tranche token
if (bond.timeToMaturity() <= 0) {
if (!bond.isMature()) {
bond.mature();
}
bond.redeemMature(address(tranche), tranche.balanceOf(address(this)));
}
// else redeem using proportional balances, redeems all tranches part of the bond
else {
TrancheData memory td;
uint256[] memory trancheAmts;
(td, trancheAmts) = bond.computeRedeemableTrancheAmounts(address(this));

// NOTE: It is guaranteed that if one tranche amount is zero, all amounts are zeros.
if (trancheAmts[0] == 0) {
continue;
}

bond.redeem(trancheAmts);
}
_execTrancheRedemption(ITranche(_deployed.at(i)));
}

// sync holdings
Expand All @@ -428,6 +415,49 @@ contract RolloverVault is
_syncAsset(underlying);
}

/// @dev Redeems the given tranche for the underlying asset and
/// performs internal book-keeping to keep track of the vault assets.
function _redeemTranche(ITranche tranche) private {
_execTrancheRedemption(tranche);

// sync holdings
// We traverse in reverse order here as well, as immature redemptions
// might remove many assets from the deployed list.
for (uint256 i = _deployed.length(); i > 0; i--) {
_syncDeployedAsset(IERC20Upgradeable(_deployed.at(i - 1)));
}
_syncAsset(underlying);
}

/// @dev Low level method that redeems the given deployed tranche tokens for the underlying asset.
/// When the tranche is not up for redemption, its a no-op.
/// This function should NOT be called directly, use `_redeemTranches` or `_redeemTranche`
/// which wrap this function with the internal book-keeping necessary to keep track of the vault's assets.
function _execTrancheRedemption(ITranche tranche) private {
IBondController bond = IBondController(tranche.bond());

// if bond has matured, redeem the tranche token
if (bond.timeToMaturity() <= 0) {
if (!bond.isMature()) {
bond.mature();
}
bond.redeemMature(address(tranche), tranche.balanceOf(address(this)));
}
// else redeem using proportional balances, redeems all tranches part of the bond
else {
TrancheData memory td;
uint256[] memory trancheAmts;
(td, trancheAmts) = bond.computeRedeemableTrancheAmounts(address(this));

// NOTE: It is guaranteed that if one tranche amount is zero, all amounts are zeros.
if (trancheAmts[0] == 0) {
return;
}

bond.redeem(trancheAmts);
}
}

/// @dev Logs the token balance held by the vault.
/// @return The Vault's token balance.
function _syncAsset(IERC20Upgradeable token) private returns (uint256) {
Expand Down
Loading

0 comments on commit c3c9a86

Please sign in to comment.