Tadle

Tadle
DeFi
30,000 USDC
View results
Submission Details
Severity: medium
Invalid

Offer can be created without market token address;

Summary

Offers can be for a market that does not have token address and without matching market token if market has.

Vulnerability Details

https://github.com/Cyfrin/2024-08-tadle/blob/main/src/core/SystemConfig.sol#L90C4-L109C6
https://github.com/Cyfrin/2024-08-tadle/blob/main/src/core/PreMarkets.sol#L39-L157

In SystemConfig.sol::createMarketPlace function, when a market is created it becomes online that makes it available to createOffer.
But it does initialize market token address. Because of this offers can be created with the token that does not have market.

function createMarketPlace(
string calldata _marketPlaceName,
bool _fixedratio
) external onlyOwner {
...
...
marketPlaceInfo.status = MarketPlaceStatus.Online; // e status becomes online
marketPlaceInfo.fixedratio = _fixedratio;
// @audit does not initialize token address
emit CreateMarketPlaceInfo(_marketPlaceName, marketPlace, _fixedratio);
}

And In the PreMarkets.sol::createOffer function it does not check that the offer we are creating for the token it matches to market's token address;

function createOffer(CreateOfferParams calldata params) external payable {
...
/// @dev market place must be online
ISystemConfig systemConfig = tadleFactory.getSystemConfig();
MarketPlaceInfo memory marketPlaceInfo = systemConfig
.getMarketPlaceInfo(params.marketPlace);
marketPlaceInfo.checkMarketPlaceStatus( // @sus its check only market status which is possible without token address
block.timestamp,
MarketPlaceStatus.Online
);
/// @dev update maker info
makerInfoMap[makerAddr] = MakerInfo({
offerSettleType: params.offerSettleType,
authority: _msgSender(),
marketPlace: params.marketPlace,
tokenAddress: params.tokenAddress, // @audit offers created with wrong token
originOffer: offerAddr,
platformFee: 0,
eachTradeTax: params.eachTradeTax
});
/// @dev update offer info
offerInfoMap[offerAddr] = OfferInfo({
id: offerId,
authority: _msgSender(),
maker: makerAddr,
offerStatus: OfferStatus.Virgin,
offerType: params.offerType,
points: params.points,
amount: params.amount,
collateralRate: params.collateralRate,
abortOfferStatus: AbortOfferStatus.Initialized,
usedPoints: 0,
tradeTax: 0,
settledPoints: 0,
settledPointTokenAmount: 0,
settledCollateralAmount: 0
});
/// @dev update stock info
stockInfoMap[stockAddr] = StockInfo({
id: offerId,
stockStatus: StockStatus.Initialized,
stockType: params.offerType == OfferType.Ask
? StockType.Bid
: StockType.Ask,
authority: _msgSender(),
maker: makerAddr,
preOffer: address(0x0),
offer: offerAddr,
points: params.points,
amount: params.amount
});
}

Impact

Offers created with Market which does not have token address.

Tools Used

Foundry

Recommendations

Add these codes in existing code.

function createMarketPlace(
string calldata _marketPlaceName,
bool _fixedratio,
```diff
+ address _tokenAddress
```
) external onlyOwner {
...
...
marketPlaceInfo.status = MarketPlaceStatus.Online; // e status becomes online
marketPlaceInfo.fixedratio = _fixedratio;
```diff
+ marketPlaceInfo.tokenAddress = _tokenAddress;
```
emit CreateMarketPlaceInfo(_marketPlaceName, marketPlace, _fixedratio);
}
function createOffer(CreateOfferParams calldata params) external payable {
if (params.points == 0x0 || params.amount == 0x0) {
revert Errors.AmountIsZero();
}
```diff
+ if (params.tokenAddress == address(0)){
revert ZeroTokenAddress()
}
```
if (params.eachTradeTax > Constants.EACH_TRADE_TAX_DECIMAL_SCALER) {
revert InvalidEachTradeTaxRate();
}
if (params.collateralRate < Constants.COLLATERAL_RATE_DECIMAL_SCALER) {
revert InvalidCollateralRate();
}
ISystemConfig systemConfig = tadleFactory.getSystemConfig();
MarketPlaceInfo memory marketPlaceInfo = systemConfig
.getMarketPlaceInfo(params.marketPlace);
marketPlaceInfo.checkMarketPlaceStatus(
block.timestamp,
MarketPlaceStatus.Online
);
```diff
+ if (params.tokenAddress != marketPlaceInfo.tokenAddress) {
+ revert MismatchedToken();
}
```
/// @dev update maker info
makerInfoMap[makerAddr] = MakerInfo({
offerSettleType: params.offerSettleType,
authority: _msgSender(),
marketPlace: params.marketPlace,
tokenAddress: params.tokenAddress, // @audit offers created with wrong token
originOffer: offerAddr,
platformFee: 0,
eachTradeTax: params.eachTradeTax
});
/// @dev update offer info
offerInfoMap[offerAddr] = OfferInfo({
id: offerId,
authority: _msgSender(),
maker: makerAddr,
offerStatus: OfferStatus.Virgin,
offerType: params.offerType,
points: params.points,
amount: params.amount,
collateralRate: params.collateralRate,
abortOfferStatus: AbortOfferStatus.Initialized,
usedPoints: 0,
tradeTax: 0,
settledPoints: 0,
settledPointTokenAmount: 0,
settledCollateralAmount: 0
});
/// @dev update stock info
stockInfoMap[stockAddr] = StockInfo({
id: offerId,
stockStatus: StockStatus.Initialized,
stockType: params.offerType == OfferType.Ask
? StockType.Bid
: StockType.Ask,
authority: _msgSender(),
maker: makerAddr,
preOffer: address(0x0),
offer: offerAddr,
points: params.points,
amount: params.amount
});
}
Updates

Lead Judging Commences

0xnevi Lead Judge
11 months ago
0xnevi Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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