If the underlying asset for a vault is a fee-on-transfer ERC20 token then the actual amount received by the contract could be less than the value of tokenIdOrAmount of the vault.
If the contract does not have enough tokens to cover the difference then the exercise and withdraw functions would not work since the safeTransfer function at the end of exercise and withdraw would revert due to an insufficient balance.
This could lead to vault owners being unable to access their funds until the contract has enough tokens and option holders might be unable to exercise their option before it expires, leading to lost funds.
Proof of Concept
Unable to withdraw:
Create a vault using a fee-on-transfer token as the underlying asset. For this instance, the Cally.sol contract holds none of these tokens before the initial transfer into the contract.
At the end of createVault, the amount of vault.tokenIdOrAmount tokens is transferred from the owner of the vault to the Cally.sol contract.
After the transfer, the contract has a balance less than vault.tokenIdOrAmount of the tokens.
When trying to withdraw the tokens, after calling initiateWithdraw, the withdraw function reverts when the safeTransfer function is called.
Unable to exercise:
Buy an option from a vault with fee-on-transfer ERC20 tokens as the underlying asset.
When calling exercise, the safeTransfer at the end of the function will fail if the contract does not have enough tokens. The option holder will not be able to exercise the option.
Recommended Mitigation Steps
Consider checking the contract's balance before and after ERC20 transfers in createVault. The vault.tokenIdOrAmount could be set to the difference of the balances.
Lines of code
Cally.sol#L158-L201 Cally.sol#L258-L297 Cally.sol#L318-L346
Vulnerability details
Impact
If the underlying asset for a vault is a fee-on-transfer ERC20 token then the actual amount received by the contract could be less than the value of
tokenIdOrAmount
of the vault.If the contract does not have enough tokens to cover the difference then the
exercise
andwithdraw
functions would not work since the safeTransfer function at the end ofexercise
andwithdraw
would revert due to an insufficient balance.This could lead to vault owners being unable to access their funds until the contract has enough tokens and option holders might be unable to exercise their option before it expires, leading to lost funds.
Proof of Concept
Unable to withdraw:
Cally.sol
contract holds none of these tokens before the initial transfer into the contract.createVault
, the amount ofvault.tokenIdOrAmount
tokens is transferred from the owner of the vault to theCally.sol
contract.vault.tokenIdOrAmount
of the tokens.initiateWithdraw
, thewithdraw
function reverts when the safeTransfer function is called.Unable to exercise:
exercise
, the safeTransfer at the end of the function will fail if the contract does not have enough tokens. The option holder will not be able to exercise the option.Recommended Mitigation Steps
Consider checking the contract's balance before and after ERC20 transfers in
createVault
. Thevault.tokenIdOrAmount
could be set to the difference of the balances.