The worst scenario is a denial of service in case there is already an amount of the output token in the contract. It is easily achieved by transferring tokens to the contract.
then it will lead to denial of service of joinTokenSingle because the actual balance at the end of the function will be greater than _joinTokenStruct.outputAmount so the transaction would revert.
Proof of concept
An attacker can transfer basket tokens to SingleTokenJoin contract, after that, no one will be able to use it.
Let's assume the attacker transferred one basket token, then a users tries to use joinTokenSingle.
in the following line, the basket will send _joinTokenStruct.outputAmount to address(this):
https://github.com/code-423n4/2021-12-amun/blob/main/contracts/basket/contracts/singleJoinExit/SingleTokenJoinV2.sol#L122
after that, outputToken.balanceOf(address(this)) will be _joinTokenStruct.outputAmount + 1. because the attacker transferred one token.
therefore the require statement will fail and the transaction will revert:
Handle
certora
Vulnerability details
https://github.com/code-423n4/2021-12-amun/blob/main/contracts/basket/contracts/singleJoinExit/SingleTokenJoin.sol#L135 the balance of
outputToken
is checked to be exactly_joinTokenStruct.outputAmount
.It is not recommeded and it's better to use
>=
Impact
The worst scenario is a denial of service in case there is already an amount of the output token in the contract. It is easily achieved by transferring tokens to the contract. then it will lead to denial of service of joinTokenSingle because the actual balance at the end of the function will be greater than _joinTokenStruct.outputAmount so the transaction would revert.
Proof of concept
An attacker can transfer basket tokens to SingleTokenJoin contract, after that, no one will be able to use it. Let's assume the attacker transferred one basket token, then a users tries to use
joinTokenSingle
. in the following line, the basket will send_joinTokenStruct.outputAmount
toaddress(this)
: https://github.com/code-423n4/2021-12-amun/blob/main/contracts/basket/contracts/singleJoinExit/SingleTokenJoinV2.sol#L122 after that,outputToken.balanceOf(address(this))
will be_joinTokenStruct.outputAmount + 1
. because the attacker transferred one token. therefore the require statement will fail and the transaction will revert:this can never be changed and the contract will stay in a state of denial of service forever.
Recommended Mitigation Steps
change to
This issue is also in: https://github.com/code-423n4/2021-12-amun/blob/main/contracts/basket/contracts/singleJoinExit/SingleTokenJoinV2.sol#L130