Incorrect PreDeposit reward
Description
In PreDeposit, each user should be able to claim a proportion of the deposit based on their individual contribution. However, the claim
function does not work proportionally. This is because the userBondShare
and userLeverageShare
are calculated based on the contract's current balance, not on the initial bondAmount
and leverageAmount
, which represent the total amount of tokens at the start. As the contract's balance decreases with each user's claim, users who claim later receive fewer tokens.
function claim() external nonReentrant whenNotPaused {
// ...
uint256 userBondShare = (bondToken.balanceOf(address(this)) * userBalance) / reserveAmount;
uint256 userLeverageShare = (leverageToken.balanceOf(address(this)) * userBalance) / reserveAmount;
// ...
if (userBondShare > 0) {
bondToken.transfer(msg.sender, userBondShare);
}
// ...
}
Impact
From the second claimant onward, they receive a smaller, incorrect amount that does not match the partial calculation.
The following proof-of-concept script demonstrates that the second claimant receives a smaller amount than the first claimant:
function testAuditPreDepositClaimIncorrect() public {
// Setup initial deposit
vm.startPrank(user1);
reserveToken.approve(address(preDeposit), DEPOSIT_AMOUNT);
preDeposit.deposit(DEPOSIT_AMOUNT);
vm.stopPrank();
vm.startPrank(user2);
reserveToken.approve(address(preDeposit), DEPOSIT_AMOUNT);
preDeposit.deposit(DEPOSIT_AMOUNT);
vm.stopPrank();
// Create pool
vm.startPrank(governance);
preDeposit.setBondAndLeverageAmount(BOND_AMOUNT, LEVERAGE_AMOUNT);
vm.warp(block.timestamp + 8 days); // After deposit period
poolFactory.grantRole(poolFactory.GOV_ROLE(), address(preDeposit));
preDeposit.createPool();
vm.stopPrank();
// Claim tokens
address bondToken = address(Pool(preDeposit.pool()).bondToken());
uint256 user1_preDeposit_balance = preDeposit.balances(user1);
uint256 user2_preDeposit_balance = preDeposit.balances(user2);
console.log("user1 preDeposit balance: ", user1_preDeposit_balance);
console.log("user2 preDeposit balance: ", user2_preDeposit_balance);
vm.prank(user1);
preDeposit.claim();
vm.prank(user2);
preDeposit.claim();
uint256 user1_bond_share = BondToken(bondToken).balanceOf(user1);
uint256 user2_bond_share = BondToken(bondToken).balanceOf(user2);
assertNotEq(user1_bond_share, user2_bond_share);
console.log("user1 bond share: ", user1_bond_share);
console.log("user2 bond share: ", user2_bond_share);
}
The following text is the result of the proof-of-concept script:
[PASS] testAuditPreDepositClaimIncorrect() (gas: 1771121)
Logs:
user1 preDeposit balance: 10000000000000000000
user2 preDeposit balance: 10000000000000000000
user1 bond share: 25000000000000000000
user2 bond share: 12500000000000000000
Recommendations
Use the initial balance for the share calculation, not the current contract balance.
Remediation
This issue has been acknowledged by Plaza Finance, and a fix was implemented in commit d8af0d68↗.