Summary
The UpliftOnlyExample contract contains a critical fee calculation error where fees are overcharged by a factor of 1e18 due to missing decimal normalization when calculating fees with feePerLP
Vulnerability Details
if (feeDataArray[i].amount <= localData.amountLeft) {
uint256 depositAmount = feeDataArray[i].amount;
localData.feeAmount += (depositAmount * feePerLP);
}
else {
localData.feeAmount += (feePerLP * localData.amountLeft);
}
uint256 feePerLP;
if (localData.lpTokenDepositValueChange > 0) {
feePerLP =
(uint256(localData.lpTokenDepositValueChange) * (uint256(feeDataArray[i].upliftFeeBps) * 1e18)) /
10000;
}
else {
@> feePerLP = (uint256(minWithdrawalFeeBps) * 1e18) / 10000;
}
if (feeDataArray[i].amount <= localData.amountLeft) {
uint256 depositAmount = feeDataArray[i].amount;
@> localData.feeAmount += (depositAmount * feePerLP);
localData.amountLeft -= feeDataArray[i].amount;
lpNFT.burn(feeDataArray[i].tokenID);
delete feeDataArray[i];
feeDataArray.pop();
if (localData.amountLeft == 0) {
break;
}
} else {
feeDataArray[i].amount -= localData.amountLeft;
@> localData.feeAmount += (feePerLP * localData.amountLeft);
break;
}
}
Coded Scenario POC
feePerLP = 0.1e18;
amount = 1000 tokens;
amountLeft = 2000 tokens;
depositAmount = 1000;
fee = depositAmount * feePerLP
= 1000 * 100000000000000000
= 100000000000000000000
amountLeft = 500;
fee = feePerLP * amountLeft
= 100000000000000000 * 500
= 50000000000000000000
correct_fee1 = (depositAmount * feePerLP) / 1e18
= (1000 * 100000000000000000) / 1000000000000000000
= 100 tokens
correct_fee2 = (feePerLP * amountLeft) / 1e18
= (100000000000000000 * 500) / 1000000000000000000
= 50 tokens
Impact
If transactions succeed, users lose significantly more funds than intended
Tools Used
Chisel, Github
Recommendations
if (feeDataArray[i].amount <= localData.amountLeft) {
uint256 depositAmount = feeDataArray[i].amount;
localData.feeAmount += (depositAmount * feePerLP) / 1e18;
}
else {
localData.feeAmount += (feePerLP * localData.amountLeft) / 1e18;
}