Any tokens sent directly to the treasury (e.g., via transfer
, safeTransfer
) will be lost forever, as Treasury.sol
tracks balances internally and does not provide an option to withdraw tokens that are not sent through its deposit
function
Treasury.sol
manages the protocol's treasury funds with role-based access control. It contains a mapping(address => uint256) _balances
where the balances of certain tokens are tracked. Additionally, it has functions to deposit and withdraw tokens, which are defined as follows:
As can be seen, with every deposit — that is, with every withdrawal — the _balances
mapping is updated. The problem arises if ERC20 tokens are sent to the contract via ERC20 functions like transfer
or safeTransfer
(e.g., in FeeCollector.sol), because in that case, the _balances
mapping will not be updated. Since there is a subsequent check inside the withdraw
function (if (_balances[token] < amount) revert InsufficientBalance();)
, these tokens will not be withdrawable, meaning they are lost forever.
Add this test to the Treasury.test.js
High, since the tokens will be lost forever and there are multiple places in the system where tokens are sent directly via ERC20 functions
Manual review
There is no need to track the balances of each token in a separate mapping, since ERC20 tokens have a built-in balanceOf()
function that can be called to check the balance.
If you wanted to avoid donations and direct transfers, for whatever reason, and strictly want to use internal balance tracking, than you need to adjust the logic in all other places to use Treasury::deposit()
function instead of ERC20::transfer()
and ERC20::safeTransfer()
whenever you are sending tokens to the treasury.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.