Tadle

Tadle
DeFi
30,000 USDC
View results
Submission Details
Severity: high
Valid

Referrer Self-Referral Vulnerability in `PreMarkets::createTaker` Function

Description

In the PreMarkets::createTaker function, there is a potential vulnerability where the msg.sender (the user initiating the transaction) can act as their own referrer. This creates a scenario where users can exploit the referral system by referring themselves, thereby earning referral rewards without actually bringing in new participants. This behavior undermines the intended purpose of the referral program, which is to incentivize users to attract new participants to the platform.

function createTaker(address _offer, uint256 _points) external payable {
/**
* @dev offer must be virgin
* @dev points must be greater than 0
* @dev total points must be greater than used points plus _points
*/
if (_points == 0x0) {
revert Errors.AmountIsZero();
}
OfferInfo storage offerInfo = offerInfoMap[_offer];
MakerInfo storage makerInfo = makerInfoMap[offerInfo.maker];
if (offerInfo.offerStatus != OfferStatus.Virgin) {
revert InvalidOfferStatus();
}
if (offerInfo.points < _points + offerInfo.usedPoints) {
revert NotEnoughPoints(offerInfo.points, offerInfo.usedPoints, _points);
}
/// @dev market place must be online
ISystemConfig systemConfig = tadleFactory.getSystemConfig();
{
MarketPlaceInfo memory marketPlaceInfo = systemConfig.getMarketPlaceInfo(makerInfo.marketPlace);
marketPlaceInfo.checkMarketPlaceStatus(block.timestamp, MarketPlaceStatus.Online);
}
@>>>> ReferralInfo memory referralInfo = systemConfig.getReferralInfo(_msgSender());
uint256 platformFeeRate = systemConfig.getPlatformFeeRate(_msgSender());
/// @dev generate stock address
address stockAddr = GenerateAddress.generateStockAddress(offerId);
if (stockInfoMap[stockAddr].authority != address(0x0)) {
revert StockAlreadyExist();
}
/// @dev Transfer token from user to capital pool as collateral
uint256 depositAmount = _points.mulDiv(offerInfo.amount, offerInfo.points, Math.Rounding.Ceil);
uint256 platformFee = depositAmount.mulDiv(platformFeeRate, Constants.PLATFORM_FEE_DECIMAL_SCALER);
uint256 tradeTax = depositAmount.mulDiv(makerInfo.eachTradeTax, Constants.EACH_TRADE_TAX_DECIMAL_SCALER);
ITokenManager tokenManager = tadleFactory.getTokenManager();
_depositTokenWhenCreateTaker(platformFee, depositAmount, tradeTax, makerInfo, offerInfo, tokenManager);
offerInfo.usedPoints = offerInfo.usedPoints + _points;
/// @dev update stock info
stockInfoMap[stockAddr] = StockInfo({
id: offerId,
stockStatus: StockStatus.Initialized,
stockType: offerInfo.offerType == OfferType.Ask ? StockType.Bid : StockType.Ask,
authority: _msgSender(),
maker: offerInfo.maker,
preOffer: _offer,
points: _points,
amount: depositAmount,
offer: address(0x0)
});
offerId = offerId + 1;
uint256 remainingPlatformFee =
_updateReferralBonus(platformFee, depositAmount, stockAddr, makerInfo, referralInfo, tokenManager);
makerInfo.platformFee = makerInfo.platformFee + remainingPlatformFee;
_updateTokenBalanceWhenCreateTaker(_offer, tradeTax, depositAmount, offerInfo, makerInfo, tokenManager);
/// @dev emit CreateTaker
emit CreateTaker(_offer, msg.sender, stockAddr, _points, depositAmount, tradeTax, remainingPlatformFee);
}

Impact

Users may exploit the referral system by creating multiple accounts or using the same account to refer themselves, leading to an unearned accumulation of rewards. The platform may incur financial losses due to the payout of undeserved referral rewards, affecting the platform's sustainability and financial health.

Tools Used

Manual Review

Recommendations

To mitigate this vulnerability, implement a check in the PreMarkets::createTaker function to ensure that msg.sender cannot be the same as the referrer. This can be done by adding the following condition:

function createTaker(address _offer, uint256 _points) external payable {
/**
* @dev offer must be virgin
* @dev points must be greater than 0
* @dev total points must be greater than used points plus _points
*/
if (_points == 0x0) {
revert Errors.AmountIsZero();
}
OfferInfo storage offerInfo = offerInfoMap[_offer];
MakerInfo storage makerInfo = makerInfoMap[offerInfo.maker];
if (offerInfo.offerStatus != OfferStatus.Virgin) {
revert InvalidOfferStatus();
}
if (offerInfo.points < _points + offerInfo.usedPoints) {
revert NotEnoughPoints(offerInfo.points, offerInfo.usedPoints, _points);
}
/// @dev market place must be online
ISystemConfig systemConfig = tadleFactory.getSystemConfig();
{
MarketPlaceInfo memory marketPlaceInfo = systemConfig.getMarketPlaceInfo(makerInfo.marketPlace);
marketPlaceInfo.checkMarketPlaceStatus(block.timestamp, MarketPlaceStatus.Online);
}
+ if (_msgSender() == referralInfo.referrer) {
+ revert InvalidReferrer();
+ }
ReferralInfo memory referralInfo = systemConfig.getReferralInfo(_msgSender());
uint256 platformFeeRate = systemConfig.getPlatformFeeRate(_msgSender());
/// @dev generate stock address
address stockAddr = GenerateAddress.generateStockAddress(offerId);
if (stockInfoMap[stockAddr].authority != address(0x0)) {
revert StockAlreadyExist();
}
/// @dev Transfer token from user to capital pool as collateral
uint256 depositAmount = _points.mulDiv(offerInfo.amount, offerInfo.points, Math.Rounding.Ceil);
uint256 platformFee = depositAmount.mulDiv(platformFeeRate, Constants.PLATFORM_FEE_DECIMAL_SCALER);
uint256 tradeTax = depositAmount.mulDiv(makerInfo.eachTradeTax, Constants.EACH_TRADE_TAX_DECIMAL_SCALER);
ITokenManager tokenManager = tadleFactory.getTokenManager();
_depositTokenWhenCreateTaker(platformFee, depositAmount, tradeTax, makerInfo, offerInfo, tokenManager);
offerInfo.usedPoints = offerInfo.usedPoints + _points;
/// @dev update stock info
stockInfoMap[stockAddr] = StockInfo({
id: offerId,
stockStatus: StockStatus.Initialized,
stockType: offerInfo.offerType == OfferType.Ask ? StockType.Bid : StockType.Ask,
authority: _msgSender(),
maker: offerInfo.maker,
preOffer: _offer,
points: _points,
amount: depositAmount,
offer: address(0x0)
});
offerId = offerId + 1;
uint256 remainingPlatformFee =
_updateReferralBonus(platformFee, depositAmount, stockAddr, makerInfo, referralInfo, tokenManager);
makerInfo.platformFee = makerInfo.platformFee + remainingPlatformFee;
_updateTokenBalanceWhenCreateTaker(_offer, tradeTax, depositAmount, offerInfo, makerInfo, tokenManager);
/// @dev emit CreateTaker
emit CreateTaker(_offer, msg.sender, stockAddr, _points, depositAmount, tradeTax, remainingPlatformFee);
}
Updates

Lead Judging Commences

0xnevi Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-SystemConfig-updateReferrerInfo-msgSender

Valid high severity. There are two impacts here due to the wrong setting of the `refferalInfoMap` mapping. 1. Wrong refferal info is always set, so the refferal will always be delegated to the refferer address instead of the caller 2. Anybody can arbitrarily change the referrer and referrer rate of any user, resulting in gaming of the refferal system I prefer #1500 description the most, be cause it seems to be the only issue although without a poc to fully describe all of the possible impacts

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.