The function firsly calculates the amount of assets the user needs to provide for the contract to mint a given shares. Unfornately the previewMint call use a round-down calculation which might let the attacker deposit less than the corresponding amount needed.
You can take at a look at ERC4626.sol of OZ, they use the round-up when calculating the corresponding mint
Attack scenario
We shall assume the state of vault as follows:
totalSupply() = 200
totalAssets() = 100
The whole strategy as follows:
Attacker call mint(3, attacker_address, attacker_address)
He will get 3 shares and need to provide 3 * 100 / 200 = 1
Attacker keep calling mint(3, attacker_address, attacker_address)
He will get 3 shares and need to provide 3 * (100 + 1) / 203 = 1
Attacker keep calling mint(3, attacker_address, attacker_address)
He will get 3 shares and need to provide 3 * (100 + 2) / 206 = 1
Attacker call redeem(9, attacker_address, attacker_address)
He will get 9 * (100 + 3) / (200 + 9) = 4 asset token in return
In step 1 and step 2 and 3, attacker will pay totally 3 asset tokens, but when we look at step 4, attacker can get back 4 asset tokens. Attacker can keep doing this process many times to get as much tokens as he can.
Title
Wrong implementation of BaseVault.previewMint
Affected smart contract
https://github.com/Fujicracy/fuji-v2/blob/1b939ec84af137db430fc2aa1b4c6f15e5254003/packages/protocol/src/abstracts/BaseVault.sol#L265-L267
Description
Function
BaseVault.mint()
is implemented as follows:The function firsly calculates the amount of
assets
the user needs to provide for the contract to mint a given shares. Unfornately thepreviewMint
call use a round-down calculation which might let the attacker deposit less than the corresponding amount needed.You can take at a look at ERC4626.sol of OZ, they use the round-up when calculating the corresponding mint
Attack scenario
We shall assume the state of vault as follows:
The whole strategy as follows:
mint(3, attacker_address, attacker_address)
He will get 3 shares and need to provide3 * 100 / 200 = 1
mint(3, attacker_address, attacker_address)
He will get 3 shares and need to provide3 * (100 + 1) / 203 = 1
mint(3, attacker_address, attacker_address)
He will get 3 shares and need to provide3 * (100 + 2) / 206 = 1
redeem(9, attacker_address, attacker_address)
He will get9 * (100 + 3) / (200 + 9) = 4
asset token in returnIn step 1 and step 2 and 3, attacker will pay totally 3 asset tokens, but when we look at step 4, attacker can get back 4 asset tokens. Attacker can keep doing this process many times to get as much tokens as he can.
PR for the attack test: https://github.com/Fujicracy/fuji-v2/pull/300
Recommendation
Modify function
previewMint()
as follows: