Referrer rebates must not decrease totalRewards
Description
When a trade is opened, if the trader has set their referral code, the referrer would get a rebate. This rebate is added as rebates in the function applyReferralOpen when a trade is opened. Additionally, part of the remaining fee, after the rebate, is allocated as rewards in the vault manager.
function handleDevGovFees(
address _trader,
uint _pairIndex,
uint _leveragedPositionSize,
bool _usdc,
bool _fullFee,
bool _buy
) external override onlyTrading returns (uint feeAfterRebate) {
//...
feeAfterRebate = applyReferralOpen(_trader, fee, _leveragedPositionSize);
uint vaultAllocation =
(feeAfterRebate * (100 - _callbacks.vaultFeeP())) / 100;
uint govFees = (feeAfterRebate * _callbacks.vaultFeeP()) / 100 / 2;
if (_usdc) usdc.transfer(address(vaultManager), vaultAllocation);
vaultManager.allocateRewards(vaultAllocation);
//...
}
function applyReferralOpen(
address _trader,
uint _fees,
uint _leveragedPosition
) public override onlyTrading returns (uint) {
(uint traderFeePostDiscount, address referrer, uint referrerRebate) =
referral.traderReferralDiscount(_trader, _fees);
if (referrer != address(0)) {
rebates[referrer] += referrerRebate;
emit TradeReferred(
_trader,
referrer,
_leveragedPosition,
traderFeePostDiscount,
_fees - traderFeePostDiscount,
referrerRebate
);
return traderFeePostDiscount - referrerRebate;
}
return _fees;
}When the trade is closed, the function applyReferralClose returns the referrerRebate, which is then subtracted from totalRewards in the function sendReferrerRebateToStorage as shown:
function _unregisterTrade(
ITradingStorage.Trade memory _trade,
int _percentProfit,
uint _collateral,
uint _feeAmountToken, // executor reward
uint _lpFeeToken,
uint _tier
) private returns (uint usdcSentToTrader) {
//Scoping Local Variables to avoid stack too deep
uint totalFees;
{
(uint feeAfterRebate, uint referrerRebate) =
storageT.applyReferralClose(
_trade.trader,
_lpFeeToken,
_trade.initialPosToken.mul(_trade.leverage)
);
//...
if (referrerRebate > 0) {
storageT.vaultManager()
.sendReferrerRebateToStorage(referrerRebate);
}
}
}function sendReferrerRebateToStorage(uint _amount)
external override onlyCallbacks {
require(_amount > 0, "NO_REWARDS_ALLOCATED");
require(totalRewards >= _amount, "UNDERFLOW_DETECTED");
totalRewards -= _amount;
IERC20(junior.asset()).transfer(address(storageT), _amount);
emit ReferralRebateAwarded(_amount);
}As the rewards do not include the referral rebate amount, these should not be subtracted from totalRewards.
Impact
The totalRewards distributed will be less than the total rewards available in the vault manager.
Recommendations
We recommend not subtracting the referral rebate from totalRewards.
Remediation
This issue has been acknowledged by Avantis Labs, Inc., and a fix was implemented in commit 6e335dc2↗.