Tadle

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

Maker can receive makerRefund even if turbo mode, resulting in protocol loss.

Summary

In Turbo Mode, the original seller deposits crypto as collateral, enabling subsequent traders to buy and sell points without additional collateral. Upon settlement, the original seller transfers tokens to all remaining buyers. Additionally, the original seller earns a maker bonus on every subsequent trade made from their original offer.

Vulnerability Details

If seller is not original one, he does not deposit additional collateral, so he should not receive maker refund during settlementPeriod.

function settleAskMaker(address _offer, uint256 _settledPoints) external { // @audit all functions are working when marketPlace is offline
__SNIP__
uint256 makerRefundAmount;
if (_settledPoints == offerInfo.usedPoints) {
if (offerInfo.offerStatus == OfferStatus.Virgin) {
@> makerRefundAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
offerInfo.amount,
true,
Math.Rounding.Floor
);
} else {
@> uint256 usedAmount = offerInfo.amount.mulDiv(
offerInfo.usedPoints,
offerInfo.points,
Math.Rounding.Floor
);
makerRefundAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
usedAmount,
true,
Math.Rounding.Floor
);
}
tokenManager.addTokenBalance(
TokenBalanceType.SalesRevenue, // @audit remainingCash
_msgSender(),
makerInfo.tokenAddress,
makerRefundAmount
);
}
IPerMarkets perMarkets = tadleFactory.getPerMarkets();
perMarkets.settledAskOffer(
_offer,
_settledPoints,
settledPointTokenAmount
);
emit SettleAskMaker(
makerInfo.marketPlace,
offerInfo.maker,
_offer,
_msgSender(),
_settledPoints,
settledPointTokenAmount,
makerRefundAmount
);
}

As you can see in above code, implementation doesn't check if OfferSettleType (owner) of offer is Turbo or not.

Owner of listOffer can receive refunds, but this is not deposited before.

Impact

Protocol loses refund amount for each listOffer, and breaks accounting system.

Tools Used

Manual review

Recommendations

function settleAskMaker(address _offer, uint256 _settledPoints) external { // @audit all functions are working when marketPlace is offline
__SNIP__
uint256 makerRefundAmount;
- if (_settledPoints == offerInfo.usedPoints) {
+ if (_settledPoints == offerInfo.usedPoints && makerInfo.offerSettleType == OfferSettleType.Protected) {
if (offerInfo.offerStatus == OfferStatus.Virgin) {
makerRefundAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
offerInfo.amount,
true,
Math.Rounding.Floor
);
} else {
uint256 usedAmount = offerInfo.amount.mulDiv(
offerInfo.usedPoints,
offerInfo.points,
Math.Rounding.Floor
);
makerRefundAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
usedAmount,
true,
Math.Rounding.Floor
);
}
tokenManager.addTokenBalance(
TokenBalanceType.SalesRevenue, // @audit remainingCash
_msgSender(),
makerInfo.tokenAddress,
makerRefundAmount
);
}
IPerMarkets perMarkets = tadleFactory.getPerMarkets();
perMarkets.settledAskOffer(
_offer,
_settledPoints,
settledPointTokenAmount
);
emit SettleAskMaker(
makerInfo.marketPlace,
offerInfo.maker,
_offer,
_msgSender(),
_settledPoints,
settledPointTokenAmount,
makerRefundAmount
);
}
Updates

Lead Judging Commences

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

finding-Premarkets-listOffer-turbo-settleAskMaker-exploit-settlement

Valid high severity, this allows resellers listing offers via `listOffer/relistOffer` to game the system. Based on the inherent design of Turbo mode not requiring takers making ask offers for the original maker offer to deposit collateral, the wrong refund of collateral to takers even when they did not deposit collateral due to turbo mode during settleAskMaker allows possible draining of pools.

Support

FAQs

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