Skip to content

Commit

Permalink
fix: buy debt
Browse files Browse the repository at this point in the history
  • Loading branch information
Schlagonia committed Aug 24, 2023
1 parent 1e6bc67 commit adcc160
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 22 deletions.
35 changes: 18 additions & 17 deletions contracts/VaultV3.vy
Original file line number Diff line number Diff line change
Expand Up @@ -1390,9 +1390,8 @@ def buy_debt(strategy: address, amount: uint256):
@dev This should only ever be used in an emergency in place
of force revoking a strategy in order to not report a loss.
It allows the DEBT_PURCHASER role to buy the strategies debt
for an equal amount of `asset`. It's important to note that
this does rely on the strategies `convertToShares` function to
determine the amount of shares to buy.
for an equal amount of `asset`.
@param strategy The strategy to buy the debt for
@param amount The amount of debt to buy from the vault.
"""
Expand All @@ -1401,35 +1400,37 @@ def buy_debt(strategy: address, amount: uint256):

# Cache the current debt.
current_debt: uint256 = self.strategies[strategy].current_debt

_amount: uint256 = amount

assert current_debt > 0, "nothing to buy"
assert amount > 0, "nothing to buy with"
assert _amount > 0, "nothing to buy with"

if _amount > current_debt:
_amount = current_debt

# Get the current shares value for the amount.
shares: uint256 = IStrategy(strategy).convertToShares(amount)
# We get the proportion of the debt that is being bought and
# transfer the equivalant shares. We assume this is being used
# due to strategy issues so won't rely on its conversion rates.
shares: uint256 = IStrategy(strategy).balanceOf(self) * _amount / current_debt

assert shares > 0, "can't buy 0"
assert shares <= IStrategy(strategy).balanceOf(self), "not enough shares"
self._erc20_safe_transfer_from(ASSET.address, msg.sender, self, amount)
# Adjust if needed to not underflow on math
bought: uint256 = min(current_debt, amount)
self._erc20_safe_transfer_from(ASSET.address, msg.sender, self, _amount)
# Lower strategy debt
self.strategies[strategy].current_debt -= bought
self.strategies[strategy].current_debt -= _amount
# lower total debt
self.total_debt -= bought
self.total_debt -= _amount
# Increase total idle
self.total_idle += bought
self.total_idle += _amount
# log debt change
log DebtUpdated(strategy, current_debt, current_debt - bought)
log DebtUpdated(strategy, current_debt, current_debt - _amount)
# Transfer the strategies shares out.
self._erc20_safe_transfer(strategy, msg.sender, shares)
log DebtPurchased(strategy, bought)
log DebtPurchased(strategy, _amount)
## STRATEGY MANAGEMENT ##
@external
Expand Down
56 changes: 51 additions & 5 deletions tests/unit/vault/test_buy_debt.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def test_buy_debt__no_amount__reverts(
vault.buy_debt(strategy, 0, sender=gov)


def test_buy_debt__to_many_shares__reverts(
def test_buy_debt__more_than_available__withdraws_current_debt(
gov,
asset,
vault,
Expand All @@ -94,8 +94,30 @@ def test_buy_debt__to_many_shares__reverts(
asset.mint(gov.address, amount, sender=gov)
asset.approve(vault.address, amount, sender=gov)

with ape.reverts("not enough shares"):
vault.buy_debt(strategy, amount * 2, sender=gov)
before_balance = asset.balanceOf(gov)
before_shares = strategy.balanceOf(gov)

tx = vault.buy_debt(strategy, amount * 2, sender=gov)

logs = list(tx.decode_logs(vault.DebtPurchased))[0]

assert logs.strategy == strategy.address
assert logs.amount == amount

logs = list(tx.decode_logs(vault.DebtUpdated))

assert len(logs) == 1
assert logs[0].strategy == strategy.address
assert logs[0].current_debt == amount
assert logs[0].new_debt == 0

assert vault.totalIdle() == amount
assert vault.totalDebt() == 0
assert vault.pricePerShare() == 10 ** asset.decimals()
assert vault.strategies(strategy)["current_debt"] == 0
# assert shares got moved
assert asset.balanceOf(gov) == before_balance - amount
assert strategy.balanceOf(gov) == before_shares + amount


def test_buy_debt__full_debt(
Expand All @@ -120,7 +142,19 @@ def test_buy_debt__full_debt(
before_balance = asset.balanceOf(gov)
before_shares = strategy.balanceOf(gov)

vault.buy_debt(strategy, amount, sender=gov)
tx = vault.buy_debt(strategy, amount, sender=gov)

logs = list(tx.decode_logs(vault.DebtPurchased))[0]

assert logs.strategy == strategy.address
assert logs.amount == amount

logs = list(tx.decode_logs(vault.DebtUpdated))

assert len(logs) == 1
assert logs[0].strategy == strategy.address
assert logs[0].current_debt == amount
assert logs[0].new_debt == 0

assert vault.totalIdle() == amount
assert vault.totalDebt() == 0
Expand Down Expand Up @@ -155,7 +189,19 @@ def test_buy_debt__half_debt(
before_balance = asset.balanceOf(gov)
before_shares = strategy.balanceOf(gov)

vault.buy_debt(strategy, to_buy, sender=gov)
tx = vault.buy_debt(strategy, to_buy, sender=gov)

logs = list(tx.decode_logs(vault.DebtPurchased))[0]

assert logs.strategy == strategy.address
assert logs.amount == to_buy

logs = list(tx.decode_logs(vault.DebtUpdated))

assert len(logs) == 1
assert logs[0].strategy == strategy.address
assert logs[0].current_debt == amount
assert logs[0].new_debt == amount - to_buy

assert vault.totalIdle() == to_buy
assert vault.totalDebt() == amount - to_buy
Expand Down

0 comments on commit adcc160

Please sign in to comment.