Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: medium
Invalid

Timestamp Manipulation Leading to Incorrect Marketplace Status

Summary

The MarketPlaceLibraries contract is vulnerable to timestamp manipulation by miners, which can lead to incorrect marketplace status transitions. Additionally, the contract does not validate the tge (time of generation event) value, which can result in unexpected behavior when tge is zero.

Vulnerability Details

https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/libraries/MarketPlaceLibraries.sol#L1-L68

1.Timestamp Manipulation:

  • Issue: The contract relies on block.timestamp to determine the marketplace status. Miners can manipulate block.timestamp within a small range to influence the status transition.

2.Condition tge Zero:

  • Issue: When tge is zero, the contract returns the marketplace status directly without further validation, potentially leading to unexpected behavior.

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../src/libraries/MarketPlaceLibraries.sol";
import {MarketPlaceInfo, MarketPlaceStatus} from "../src/interfaces/ISystemConfig.sol";
contract MarketPlaceLibrariesTest is Test {
using MarketPlaceLibraries for MarketPlaceInfo;
MarketPlaceInfo marketPlaceInfo;
function setUp() public {
marketPlaceInfo = MarketPlaceInfo({
fixedratio: false,
status: MarketPlaceStatus.Online,
tokenAddress: address(0),
tokenPerPoint: 0,
tge: block.timestamp,
settlementPeriod: 1000
});
}
function testManipulateBlockTimestamp() public {
// Step 1: Miner sees block.timestamp near the end of settlementPeriod
vm.warp(block.timestamp + marketPlaceInfo.settlementPeriod - 10);
assertEq(uint256(MarketPlaceLibraries.getMarketPlaceStatus(block.timestamp, marketPlaceInfo)), uint256(MarketPlaceStatus.AskSettling));
// Step 2: Miner adds a few seconds to block.timestamp
vm.warp(block.timestamp + 20);
// Step 3: Function should return BidSettling
assertEq(uint256(MarketPlaceLibraries.getMarketPlaceStatus(block.timestamp, marketPlaceInfo)), uint256(MarketPlaceStatus.BidSettling));
}
function testTgeZero() public {
// Step 1: MarketPlaceInfo has tge set to 0
marketPlaceInfo.tge = 0;
// Step 2: Call getMarketPlaceStatus with a valid block.timestamp
MarketPlaceStatus status = MarketPlaceLibraries.getMarketPlaceStatus(block.timestamp, marketPlaceInfo);
// Step 3: Function should return MarketPlaceInfo.status directly
assertEq(uint256(status), uint256(marketPlaceInfo.status));
}
}

forge test --match-path test/MarketPlaceLibrariesTest.t.sol
[⠊] Compiling...
[⠢] Compiling 1 files with Solc 0.8.26
[⠆] Solc 0.8.26 finished in 1.08s
Compiler run successful!

Ran 2 tests for test/MarketPlaceLibrariesTest.t.sol:MarketPlaceLibrariesTest
[PASS] testManipulateBlockTimestamp() (gas: 14735)
[PASS] testTgeZero() (gas: 10471)
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.06ms (382.20µs CPU time)

Ran 1 test suite in 8.63ms (1.06ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)

Impact

  • Miners can manipulate the block.timestamp to change the marketplace status from AskSettling to BidSettling or vice versa, potentially gaining unfair advantages in the marketplace.

  • If tge is not properly initialized, the marketplace status may not reflect the actual state, leading to incorrect behavior in the marketplace operations.

Tools Used

  • Manual Review

  • Foundry

Recommendations

  • Add a buffer time to reduce the impact of small timestamp manipulations.

if (_blockTimestamp > _marketPlaceInfo.tge + _marketPlaceInfo.settlementPeriod + 10) {
return MarketPlaceStatus.BidSettling;
}
  • Use a more robust time-check mechanism, such as a combination of block numbers and timestamps, to reduce reliance on block.timestamp.

  • Ensure tge is properly initialized and validated before being used in status determination.

require(_marketPlaceInfo.tge > 0, "Invalid TGE value");
  • Validate other parameters in MarketPlaceInfo to ensure they are within expected ranges.

require(_marketPlaceInfo.settlementPeriod > 0, "Invalid settlement period");

Implementation

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.13;
import {MarketPlaceInfo, MarketPlaceStatus} from "../interfaces/ISystemConfig.sol";
library MarketPlaceLibraries {
function getMarketPlaceStatus(
uint256 _blockTimestamp,
MarketPlaceInfo memory _marketPlaceInfo
) internal pure returns (MarketPlaceStatus _status) {
require(_marketPlaceInfo.tge > 0, "Invalid TGE value");
require(_marketPlaceInfo.settlementPeriod > 0, "Invalid settlement period");
if (_marketPlaceInfo.status == MarketPlaceStatus.Offline) {
return MarketPlaceStatus.Offline;
}
/// @dev settle not active
if (_marketPlaceInfo.tge == 0) {
return _marketPlaceInfo.status;
}
if (
_blockTimestamp >
_marketPlaceInfo.tge + _marketPlaceInfo.settlementPeriod + 10
) {
return MarketPlaceStatus.BidSettling;
}
if (_blockTimestamp > _marketPlaceInfo.tge) {
return MarketPlaceStatus.AskSettling;
}
return _marketPlaceInfo.status;
}
function checkMarketPlaceStatus(
MarketPlaceInfo memory _marketPlaceInfo,
uint256 _blockTimestamp,
MarketPlaceStatus _status
) internal pure {
MarketPlaceStatus status = getMarketPlaceStatus(
_blockTimestamp,
_marketPlaceInfo
);
if (status != _status) {
revert("Mismatched Marketplace status");
}
}
}
Updates

Lead Judging Commences

0xnevi Lead Judge
about 1 year ago
0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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