Lucene search

K
code423n4Code4renaCODE423N4:2022-10-PALADIN-FINDINGS-ISSUES-235
HistoryOct 30, 2022 - 12:00 a.m.

Fees charged from entire theoretical pledge amount instead of actual pledge amount

2022-10-3000:00:00
Code4rena
github.com
10
security issue
upfront fees
unfair collection

Lines of code

Vulnerability details

Description

Paladin receives a 5% cut from Boost purchases, as documented on the website

“Warden takes a 5% fee on Boost purchases, and 5% on Quest incentives. However, there are various pricing tiers for Quest creators. Contact the Paladin team for more info.”

Here’s how fee calculation looks at createPledge function:

vars.totalRewardAmount = (rewardPerVote * vars.votesDifference * vars.duration) / UNIT;
vars.feeAmount = (vars.totalRewardAmount * protocalFeeRatio) / MAX_PCT ;
if(vars.totalRewardAmount > maxTotalRewardAmount) revert Errors.IncorrectMaxTotalRewardAmount();
if(vars.feeAmount > maxFeeAmount) revert Errors.IncorrectMaxFeeAmount();
// Pull all the rewards in this contract
IERC20(rewardToken).safeTransferFrom(creator, address(this), vars.totalRewardAmount);
// And transfer the fees from the Pledge creator to the Chest contract
IERC20(rewardToken).safeTransferFrom(creator, chestAddress, vars.feeAmount);

The issue is that the fee is taken up front, assuming totalRewardAmount will actually be rewarded by the pledge. In practice, the rewards actually utilized can be anywhere from zero to totalRewardAmount. Indeed, reward will only be totalRewardAmount if, in the entire period from pledge creation to pledge expiry, the desired targetVotes will be fulfilled, which is extremly unlikely.

As a result, if pledge expires with no pledgers, protocol will still take 5%. This behavior is both unfair and against the docs, as it’s not “Paladin receives a 5% cut from Boost purchases”.

Impact

Paladin fee collection assumes pledges will be matched immediately and fully, which is not realistic. Therefore far too much fees are collected at user’s expense.

Proof of Concept

  1. Bob creates a pledge, with target = 200, current balance = 100, rewardVotes = 10, remaining time = 1 week.
  2. Protocol collects (200 - 100) * 10 * WEEK_SECONDS * 5% fees
  3. A week passed, rewards were not attractive enough to bring pledgers.
  4. After expiry, Bob calls retrievePledgeRewards() and gets 100 * 10 * WEEK_SECONDS back, but 5% of the fees still went to chestAddress.

Tools Used

Manual audit

Recommended Mitigation Steps

Fee collection should be done after the pledge completes, in one of the close functions or in a newly created pull function for owner to collect fees. Otherwise, it is a completely unfair system.


The text was updated successfully, but these errors were encountered:

All reactions