Skip to content

Commit

Permalink
fix: deposit flow (#209)
Browse files Browse the repository at this point in the history
* forge install: openzeppelin-contracts

v4.9.5

* chore: oz sub module

* test: fix foundry tests

* fix: deposit flow

* fix: zero total assets

* fix: flow

* test: full loss

* chore: comment

* test: add invariants

* fix: comments

* fix: user msg sender

* fix: comments

* fix: comment
  • Loading branch information
Schlagonia authored Sep 19, 2024
1 parent 1c68d3e commit 42afe0c
Show file tree
Hide file tree
Showing 8 changed files with 729 additions and 83 deletions.
105 changes: 26 additions & 79 deletions contracts/VaultV3.vy
Original file line number Diff line number Diff line change
Expand Up @@ -462,16 +462,17 @@ def _convert_to_shares(assets: uint256, rounding: Rounding) -> uint256:
return assets

total_supply: uint256 = self._total_supply()

# if total_supply is 0, price_per_share is 1
if total_supply == 0:
return assets

total_assets: uint256 = self._total_assets()

# if total_Supply > 0 but total_assets == 0, price_per_share = 0
if total_assets == 0:
# if total_assets and total_supply is 0, price_per_share is 1
if total_supply == 0:
return assets
else:
# Else if total_supply > 0 price_per_share is 0
return 0

return 0

numerator: uint256 = assets * total_supply
shares: uint256 = numerator / total_assets
if rounding == Rounding.ROUND_UP and numerator % total_assets != 0:
Expand Down Expand Up @@ -504,31 +505,6 @@ def _issue_shares(shares: uint256, recipient: address):

log Transfer(empty(address), recipient, shares)

@internal
def _issue_shares_for_amount(amount: uint256, recipient: address) -> uint256:
"""
Issues shares that are worth 'amount' in the underlying token (asset).
WARNING: this takes into account that any new assets have been summed
to total_assets (otherwise pps will go down).
"""
total_supply: uint256 = self._total_supply()
total_assets: uint256 = self._total_assets()
new_shares: uint256 = 0

# If no supply PPS = 1.
if total_supply == 0:
new_shares = amount
elif total_assets > amount:
new_shares = amount * total_supply / (total_assets - amount)

# We don't make the function revert
if new_shares == 0:
return 0

self._issue_shares(new_shares, recipient)

return new_shares

## ERC4626 ##
@view
@internal
Expand Down Expand Up @@ -662,52 +638,16 @@ def _max_withdraw(
return max_assets

@internal
def _deposit(sender: address, recipient: address, assets: uint256) -> uint256:
def _deposit(recipient: address, assets: uint256, shares: uint256):
"""
Used for `deposit` calls to transfer the amount of `asset` to the vault,
issue the corresponding shares to the `recipient` and update all needed
Used for `deposit` and `mint` calls to transfer the amount of `asset` to the vault,
issue the corresponding `shares` to the `recipient` and update all needed
vault accounting.
"""
assert self.shutdown == False # dev: shutdown

amount: uint256 = assets
# Deposit all if sent with max uint
if amount == max_value(uint256):
amount = ERC20(self.asset).balanceOf(msg.sender)

assert amount <= self._max_deposit(recipient), "exceed deposit limit"

# Transfer the tokens to the vault first.
self._erc20_safe_transfer_from(self.asset, msg.sender, self, amount)
# Record the change in total assets.
self.total_idle += amount

# Issue the corresponding shares for amount.
shares: uint256 = self._issue_shares_for_amount(amount, recipient)

assert shares > 0, "cannot mint zero"

log Deposit(sender, recipient, amount, shares)

if self.auto_allocate:
self._update_debt(self.default_queue[0], max_value(uint256), 0)

return shares

@internal
def _mint(sender: address, recipient: address, shares: uint256) -> uint256:
"""
Used for `mint` calls to issue the corresponding shares to the `recipient`,
transfer the amount of `asset` to the vault, and update all needed vault
accounting.
"""
assert self.shutdown == False # dev: shutdown
# Get corresponding amount of assets.
assets: uint256 = self._convert_to_assets(shares, Rounding.ROUND_UP)

assert assets > 0, "cannot deposit zero"
assert assets <= self._max_deposit(recipient), "exceed deposit limit"

assert assets > 0, "cannot deposit zero"
assert shares > 0, "cannot mint zero"

# Transfer the tokens to the vault first.
self._erc20_safe_transfer_from(self.asset, msg.sender, self, assets)
# Record the change in total assets.
Expand All @@ -716,13 +656,11 @@ def _mint(sender: address, recipient: address, shares: uint256) -> uint256:
# Issue the corresponding shares for assets.
self._issue_shares(shares, recipient)

log Deposit(sender, recipient, assets, shares)
log Deposit(msg.sender, recipient, assets, shares)

if self.auto_allocate:
self._update_debt(self.default_queue[0], max_value(uint256), 0)

return assets

@view
@internal
def _assess_share_of_unrealised_losses(strategy: address, strategy_current_debt: uint256, assets_needed: uint256) -> uint256:
Expand Down Expand Up @@ -1849,7 +1787,14 @@ def deposit(assets: uint256, receiver: address) -> uint256:
@param receiver The address to receive the shares.
@return The amount of shares minted.
"""
return self._deposit(msg.sender, receiver, assets)
amount: uint256 = assets
# Deposit all if sent with max uint
if amount == max_value(uint256):
amount = ERC20(self.asset).balanceOf(msg.sender)

shares: uint256 = self._convert_to_shares(amount, Rounding.ROUND_DOWN)
self._deposit(receiver, amount, shares)
return shares

@external
@nonreentrant("lock")
Expand All @@ -1860,7 +1805,9 @@ def mint(shares: uint256, receiver: address) -> uint256:
@param receiver The address to receive the shares.
@return The amount of assets deposited.
"""
return self._mint(msg.sender, receiver, shares)
assets: uint256 = self._convert_to_assets(shares, Rounding.ROUND_UP)
self._deposit(receiver, assets, shares)
return assets

@external
@nonreentrant("lock")
Expand Down
4 changes: 2 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ remappings = [
]
fs_permissions = [{ access = "read", path = "./"}]

match_contract = "VaultERC4626StdTest"
#match_path = "./foundry_tests/tests/*"
#match_contract = "VaultERC4626StdTest"
match_path = "./foundry_tests/tests/*"
ffi = true

[fuzz]
Expand Down
Loading

0 comments on commit 42afe0c

Please sign in to comment.