Relevant GitHub Links
https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/SystemConfig.sol#L41-L80
Vulnerability Details
RefferalInfo feature is implemented incorrectly:
It allows everyone except referrer to change ReferrerInfo which allows other users to reduce referrerRate
and increase authorityRate
to get bigger funds refund.
Referral feature can use only referrer which fully breaks the purpose of referral system.
Lets take a look at code in PreMarkets.createTaker()
where referrer system is used:
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());
In this line we are getting info for referrer (referrer and referral bonus). Code call SystemConfig.getReferralInfo()
with _referrer
argument being msg.sender
which is not correct as msg.sender
should be a referral. Now let's take a look where this referralInfo
is used PreMarkets_updateReferralBonus():
uint256 referrerReferralBonus = platformFee.mulDiv(
referralInfo.referrerRate,
Constants.REFERRAL_RATE_DECIMAL_SCALER,
Math.Rounding.Floor
);
* @dev update referrer referral bonus
* @dev update authority referral bonus
*/
tokenManager.addTokenBalance(
TokenBalanceType.ReferralBonus,
referralInfo.referrer,
makerInfo.tokenAddress,
referrerReferralBonus
);
uint256 authorityReferralBonus = platformFee.mulDiv(
referralInfo.authorityRate,
Constants.REFERRAL_RATE_DECIMAL_SCALER,
Math.Rounding.Floor
);
tokenManager.addTokenBalance(
TokenBalanceType.ReferralBonus,
_msgSender(),
makerInfo.tokenAddress,
authorityReferralBonus
);
As said earlier msg.sender
is referrer because it gets referrer data using SystemConfig.getReferralInfo()
. In the code snippet above we see updating fees for referralInfo.referrer
and _msgSender()
which is incorrect because as was said earlier msg.sender
is also referrer. So that's how only referrer can use referrer bonus but referral can not possibly have any referral bonus.
Impact
With incorrectly implemented referrer system there would be no incentivize for referrer to invite other users to use this platform instead of others which directly reduces the profit from commissions for protocol.
Recommended Mitigation Steps
Create additional mapping to store which user is connected to which referrer and allow only referrer to change referrer info:
SystemConfigStorage
:
@@ -31,6 +31,9 @@ contract SystemConfigStorage is UpgradeableStorage {
/// @dev user refferral info, detail see ReferralInfo.
mapping(address => ReferralInfo) public referralInfoMap;
+ /// @dev mapping to store information about which user is connected to which referrer
+ mapping(address user => address referrer) public referrerMap;
+
/// @dev marketPlace info, detail see MarketPlaceInfo.
mapping(address => MarketPlaceInfo) public marketPlaceInfoMap;
@@ -38,5 +41,5 @@ contract SystemConfigStorage is UpgradeableStorage {
/// variables without shifting down storage in the inheritance chain.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
/// start from slot 56, end at slot 149
- uint256[94] private __gap;
+ uint256[93] private __gap;
}
SystemConfig
:
@@ -30,6 +30,16 @@ contract SystemConfig is SystemConfigStorage, Rescuable, ISystemConfig {
baseReferralRate = _baseReferralRate;
}
+ /**
+ * @dev can be called only by owner so user can not change referrer
+ */
+ function updateReferralInfo(
+ address _referrer,
+ address _referral
+ ) external onlyOwner {
+ referrerMap[_referrer] = _referral;
+ }
+
/**
* @notice Update referrer setting
* @param _referrer Referrer address
@@ -43,7 +53,7 @@ contract SystemConfig is SystemConfigStorage, Rescuable, ISystemConfig {
uint256 _referrerRate,
uint256 _authorityRate
) external {
- if (_msgSender() == _referrer) {
+ if (_msgSender() != _referrer) {
revert InvalidReferrer(_referrer);
}
@@ -225,11 +235,12 @@ contract SystemConfig is SystemConfigStorage, Rescuable, ISystemConfig {
return userPlatformFeeRate[_user];
}
- /// @dev Get referral info by referrer
+ /// @dev Get referrer info by referral
function getReferralInfo(
- address _referrer
+ address _referral
) external view returns (ReferralInfo memory) {
- return referralInfoMap[_referrer];
+ address referrer = referrerMap[_referral];
+ return referralInfoMap[referrer];
}