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↗.