Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: low
Valid

ReferrerRate can't be updated by `SystemConfig::updateReferrerInfo()`, eventual loss of reward given to the referrer

Summary

SystemConfig::updateReferrerInfo() reverts causing eventual loss of rewards given to the referrer

Vulnerability Details

The testUpdateReferrerInfo function in the following contract is designed to test the initialization of uint256 basePlatformFeeRate = 5_000; and uint256 baseReferralRate = 300_000;, as well as the update of referrerRate using SystemConfig::updateReferrerInfo().

During the test, SystemConfig::updateReferrerInfo() reverts with the error [Revert] InvalidRate(300030 [3e5], 0, 300000 [3e5]). This error occurs because the function fails to meet the following condition:

if (_referrerRate + _authorityRate != totalRate) {
revert InvalidRate(_referrerRate, _authorityRate, totalRate);
}

uint256 _referrerRate = 300030;
uint256 _authorityRate = 0;
uint256 totalRate = 300000;

The problem seems to lie in the method used to calculate the total rate:
uint256 totalRate = baseReferralRate + referralExtraRate;
Currently, the calculation uses referralExtraRate instead of considering newReferrerRate and newAuthorityRate . It should be adjusted to:
uint256 totalRate = baseReferralRate + newReferrerRate + newAuthorityRate

Copy and paste the following contract into a new file within the test directory.
Then, execute the test using the following command: forge test --mt testUpdateReferrerInfo -vvv
Ensure that you have a Foundry project initialized before running this command.

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.13;
import { Test, console} from 'lib/forge-std/src/Test.sol';
import { SystemConfigStorage } from "src/storage/SystemConfigStorage.sol";
import {ISystemConfig, ReferralInfo, MarketPlaceInfo, MarketPlaceStatus} from "src/interfaces/ISystemConfig.sol";
import { SystemConfig } from 'src/core/systemConfig.sol';
import {CapitalPool} from "../src/core/CapitalPool.sol";
import {TokenManager} from "../src/core/TokenManager.sol";
import {PreMarktes} from "../src/core/PreMarkets.sol";
import {DeliveryPlace} from "../src/core/DeliveryPlace.sol";
import {TadleFactory} from "../src/factory/TadleFactory.sol";
import {OfferStatus, StockStatus, AbortOfferStatus, OfferType, StockType, OfferSettleType} from "../src/storage/OfferStatus.sol";
import {IPerMarkets, OfferInfo, StockInfo, MakerInfo, CreateOfferParams} from "../src/interfaces/IPerMarkets.sol";
import {TokenBalanceType, ITokenManager} from "../src/interfaces/ITokenManager.sol";
import {GenerateAddress} from "../src/libraries/GenerateAddress.sol";
import {MockERC20Token} from "./mocks/MockERC20Token.sol";
import {WETH9} from "./mocks/WETH9.sol";
import {UpgradeableProxy} from "../src/proxy/UpgradeableProxy.sol";
contract SystemConfigTest is Test {
SystemConfig systemConfig;
CapitalPool capitalPool;
TokenManager tokenManager;
PreMarktes preMarktes;
DeliveryPlace deliveryPlace;
address marketPlace;
WETH9 weth9;
MockERC20Token mockUSDCToken;
MockERC20Token mockPointToken;
address user = vm.addr(1);
address user1 = vm.addr(2);
address user2 = vm.addr(3);
address user3 = vm.addr(4);
uint256 basePlatformFeeRate = 5_000;
uint256 baseReferralRate = 300_000;
bytes4 private constant INITIALIZE_OWNERSHIP_SELECTOR =
bytes4(keccak256(bytes("initializeOwnership(address)")));
function setUp() public {
//deploy mocks
weth9 = new WETH9();
TadleFactory tadleFactory = new TadleFactory(user1);
mockUSDCToken = new MockERC20Token();
mockPointToken = new MockERC20Token();
SystemConfig systemConfigLogic = new SystemConfig();
CapitalPool capitalPoolLogic = new CapitalPool();
TokenManager tokenManagerLogic = new TokenManager();
PreMarktes preMarktesLogic = new PreMarktes();
DeliveryPlace deliveryPlaceLogic = new DeliveryPlace();
bytes memory deploy_data = abi.encodeWithSelector(
INITIALIZE_OWNERSHIP_SELECTOR,
user1
);
vm.startPrank(user1);
address systemConfigProxy = tadleFactory.deployUpgradeableProxy(
1,
address(systemConfigLogic),
bytes(deploy_data)
);
address preMarktesProxy = tadleFactory.deployUpgradeableProxy(
2,
address(preMarktesLogic),
bytes(deploy_data)
);
address deliveryPlaceProxy = tadleFactory.deployUpgradeableProxy(
3,
address(deliveryPlaceLogic),
bytes(deploy_data)
);
address capitalPoolProxy = tadleFactory.deployUpgradeableProxy(
4,
address(capitalPoolLogic),
bytes(deploy_data)
);
address tokenManagerProxy = tadleFactory.deployUpgradeableProxy(
5,
address(tokenManagerLogic),
bytes(deploy_data)
);
vm.stopPrank();
// attach logic
systemConfig = SystemConfig(systemConfigProxy);
capitalPool = CapitalPool(capitalPoolProxy);
tokenManager = TokenManager(tokenManagerProxy);
preMarktes = PreMarktes(preMarktesProxy);
deliveryPlace = DeliveryPlace(deliveryPlaceProxy);
vm.startPrank(user1);
// initialize
systemConfig.initialize(basePlatformFeeRate, baseReferralRate);
tokenManager.initialize(address(weth9));
address[] memory tokenAddressList = new address[](2);
tokenAddressList[0] = address(mockUSDCToken);
tokenAddressList[1] = address(weth9);
tokenManager.updateTokenWhiteListed(tokenAddressList, true);
// create market place
systemConfig.createMarketPlace("Backpack", false);
vm.stopPrank();
deal(address(mockUSDCToken), user, 100000000 * 10 ** 18);
deal(address(mockPointToken), user, 100000000 * 10 ** 18);
deal(user, 100000000 * 10 ** 18);
deal(address(mockUSDCToken), user1, 100000000 * 10 ** 18);
deal(address(mockUSDCToken), user2, 100000000 * 10 ** 18);
deal(address(mockUSDCToken), user3, 100000000 * 10 ** 18);
deal(address(mockPointToken), user2, 100000000 * 10 ** 18);
marketPlace = GenerateAddress.generateMarketPlaceAddress("Backpack");
vm.warp(1719826275);
vm.prank(user);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
vm.startPrank(user2);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
mockPointToken.approve(address(tokenManager), type(uint256).max);
vm.stopPrank();
}
function testUpdateReferrerInfo() public {
uint256 baseReferralRateInitialized = systemConfig.getBaseReferralRate();
uint256 basePlateformFeeRate = systemConfig.getPlatformFeeRate(user1);
assertEq(basePlatformFeeRate, 5_000);
assertEq(baseReferralRate, 300_000);
console.log("baseReferralRateInitialized", baseReferralRateInitialized);
console.log("basePlateformFeeRate", basePlateformFeeRate);
ReferralInfo memory referralInfo = systemConfig.getReferralInfo(user1);
address referrer = referralInfo.referrer;
uint256 referrerRate = referralInfo.referrerRate;
uint256 authorityRate = referralInfo.authorityRate;
console.log("referrer", referrer);
console.log("referrerRate", referrerRate);
console.log("authorityRate", authorityRate);
address newReferrer = makeAddr("newReferrer");
uint256 newReferrerRate = (baseReferralRate + 30)
uint256 newAuthorityRate = 0;
systemConfig.updateReferrerInfo(newReferrer, newReferrerRate, newAuthorityRate);
assertTrue(newReferrer == systemConfig.getReferralInfo(newReferrer).referrer, "newReferrer is not equal");
assertTrue(newReferrerRate == systemConfig.getReferralInfo(newReferrer).referrerRate, "newReferrerRate is not equal");
assertTrue(newAuthorityRate == systemConfig.getReferralInfo(newReferrer).authorityRate, "newAuthorityRate is not equal");
}
}

Impact

Eventual loss of rewards given to the referrer and inability to update referral rate.

Tools Used

Manual review

Recommendations

Instead of using uint256 totalRate = baseReferralRate + referralExtraRate;
you should adjust it to: uint256 totalRate = baseReferralRate + newReferrerRate + newAuthorityRate

Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-SystemConfig-updateReferrerInfo-wrong-referral-rate-combined-check

Valid medium, specific valid inputs by admin will still cause revert in updates to referral info due to incorrect totalRate computation and checks implemented. Note: Downgrade to low severity: This is a valid issue that highlights a valid inconsistency in the docs. In the docs, it was mentioned in the steps that referral rates can be adjusted up to a maximum of 30% as seen in [Step 4. ](https://tadle.gitbook.io/tadle/tadle-incentives-program/referral-program/create-and-manage-referral)but as of now, the minimum refferal rate is 30%. However, since refferals are entirely optional, if a minimum 30% refferal rate is established and the user deems it as too high, he can simply choose not to perform the refferal. Hence, I believe low severity to be appropriate.

Appeal created

0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-SystemConfig-updateReferrerInfo-wrong-referral-rate-combined-check

Valid medium, specific valid inputs by admin will still cause revert in updates to referral info due to incorrect totalRate computation and checks implemented. Note: Downgrade to low severity: This is a valid issue that highlights a valid inconsistency in the docs. In the docs, it was mentioned in the steps that referral rates can be adjusted up to a maximum of 30% as seen in [Step 4. ](https://tadle.gitbook.io/tadle/tadle-incentives-program/referral-program/create-and-manage-referral)but as of now, the minimum refferal rate is 30%. However, since refferals are entirely optional, if a minimum 30% refferal rate is established and the user deems it as too high, he can simply choose not to perform the refferal. Hence, I believe low severity to be appropriate.

Support

FAQs

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

Give us feedback!