Summary
The PerMarkets::createOffer
function currently includes a validation check to ensure that the collateralRate
parameter is at least 100% by comparing it against a constant (Constants.COLLATERAL_RATE_DECIMAL_SCALER
). However, the documentation specifies that the collateralRate must be greater than 100% * @dev collateralRate must be more than 100%, decimal scaler is 10000
.
Vulnerability Details
The current implementation only enforces that the collateralRate is not less than 100%, which means a collateralRate equal to 100% would be incorrectly accepted.
function createOffer(CreateOfferParams calldata params) external payable {
* @dev points and amount must be greater than 0
* @dev eachTradeTax must be less than 100%, decimal scaler is 10000
* @dev collateralRate must be more than 100%, decimal scaler is 10000
*/
if (params.points == 0x0 || params.amount == 0x0) {
revert Errors.AmountIsZero();
}
if (params.eachTradeTax > Constants.EACH_TRADE_TAX_DECIMAL_SCALER) {
revert InvalidEachTradeTaxRate();
}
@>> if (params.collateralRate < Constants.COLLATERAL_RATE_DECIMAL_SCALER) {
revert InvalidCollateralRate();
}
POC
function test_ask_offer_turbo_usdc() public {
vm.startPrank(user);
preMarktes.createOffer(
CreateOfferParams(
marketPlace,
address(mockUSDCToken),
1000,
0.01 * 1e18,
@>> 10000,
300,
OfferType.Ask,
OfferSettleType.Turbo
)
);
address offerAddr = GenerateAddress.generateOfferAddress(0);
preMarktes.createTaker(offerAddr, 500);
address stock1Addr = GenerateAddress.generateStockAddress(1);
preMarktes.listOffer(stock1Addr, 0.006 * 1e18, 10000);
address offer1Addr = GenerateAddress.generateOfferAddress(1);
preMarktes.closeOffer(stock1Addr, offer1Addr);
preMarktes.relistOffer(stock1Addr, offer1Addr);
vm.stopPrank();
vm.prank(user1);
systemConfig.updateMarket(
"Backpack",
address(mockPointToken),
0.01 * 1e18,
block.timestamp - 1,
3600
);
vm.startPrank(user);
mockPointToken.approve(address(tokenManager), 10000 * 10 ** 18);
deliveryPlace.settleAskMaker(offerAddr, 500);
deliveryPlace.closeBidTaker(stock1Addr);
vm.stopPrank();
}
Ran 1 test for test/PreMarkets.t.sol:PreMarketsTest
[PASS] test_ask_offer_turbo_usdc() (gas: 1356543)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.13ms (1.68ms CPU time)
Impact
Allowing a collateralRate
of exactly 100% when the system requires it to be strictly greater than 100% could lead to inadequate collateralization.
Tools Used
Manual Review
Recommendations
Update the validation logic to enforce that the collateralRate must be strictly greater than 100%. The condition should be modified as follows:
- if (params.collateralRate < Constants.COLLATERAL_RATE_DECIMAL_SCALER) {
+ if (params.collateralRate <= Constants.COLLATERAL_RATE_DECIMAL_SCALER) {
revert InvalidCollateralRate();
}