You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The donate_admin_fees function doesn't donate or transfer any fees. Instead, it updates the contract's internal balances array to reflect the total balance of each token held by the contract. This implementation could lead to incorrect accounting within the pool, potentially affecting operations that rely on these balance values.
Attack Scenario\
The pool has 1000 USDC of user-provided liquidity.
Over time, the pool has accumulated 50 USDC in admin fees.
The balances array for USDC shows 1000 USDC (only user liquidity).
The pool now treats 1050 USDC as the total liquidity.
Liquidity providers who deposit after this point will be diluted, as they're buying into a share of the pool that includes the admin fees.
Users withdrawing liquidity will receive a proportion of the admin fees they're not entitled to.
also in addition
An owner could call this function strategically before making a large deposit, effectively "buying" a share of the admin fees at no cost.
Vice versa, they could call it before a large withdrawal, extracting more value than they're entitled to.
The function incorrectly assumes that updating the balances array to the total contract balance is equivalent to "donating" admin fees. In reality, this action merges distinct accounting categories (user liquidity and admin fees) that should remain separate.
Attachments
Proof of Concept (PoC) File
function donate_admin_fees() external onlyOwner {
for (uint256 i = 0; i < N_COINS; i++) {
if (coins[i] == ROSE_ADDRESS) {
balances[i] = address(this).balance;
} else {
balances[i] = IERC20(coins[i]).balanceOf(address(this));
}
}
emit DonateAdminFees();
}
Revised Code File (Optional)
uint256[N_COINS] private adminFees;
uint256 public totalSupply; // Total supply of LP tokens
++Rest of the Code++
function donate_admin_fees() external onlyOwner {
for (uint256 i = 0; i < N_COINS; i++) {
uint256 currentBalance;
if (coins[i] == ROSE_ADDRESS) {
currentBalance = address(this).balance;
} else {
currentBalance = IERC20(coins[i]).balanceOf(address(this));
}
uint256 fee = currentBalance - balances[i];
if (fee > 0) {
adminFees[i] += fee;
balances[i] = currentBalance;
}
}
if (totalSupply > 0) {
for (uint256 i = 0; i < N_COINS; i++) {
if (adminFees[i] > 0) {
balances[i] += adminFees[i];
emit AdminFeeDonated(i, adminFees[i]);
adminFees[i] = 0;
}
}
}
emit DonateAdminFees();
}
event AdminFeeDonated(uint256 indexed coinIndex, uint256 amount);
the fix helps with the following:
correctly identifies and separates admin fees from the main pool balances.
it "donates" the admin fees by adding them to the pool's liquidity, which benefits all liquidity providers proportionally.
maintains accurate accounting of the pool's balances.
The text was updated successfully, but these errors were encountered:
Github username: @00xWizard
Twitter username: 00xWizard
Submission hash (on-chain): 0x05ef4795fa3e8bbca00768ddff5d4afc40d88e24dc5dba3448686d27c124dda8
Severity: high
Description:
Description
The
donate_admin_fees
function doesn't donate or transfer any fees. Instead, it updates the contract's internal balances array to reflect the total balance of each token held by the contract. This implementation could lead to incorrect accounting within the pool, potentially affecting operations that rely on these balance values.Attack Scenario\
also in addition
The function incorrectly assumes that updating the balances array to the total contract balance is equivalent to "donating" admin fees. In reality, this action merges distinct accounting categories (user liquidity and admin fees) that should remain separate.
Attachments
the fix helps with the following:
The text was updated successfully, but these errors were encountered: