Tadle

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

Premarket.sol

Documentation for PreMarkets.sol.sol

PreMarkets Smart Contract Documentation


Overview

The PreMarkets smart contract implements the functionalities required for trading in a pre-market environment. It allows users to create, list, close, relist, and abort offers, both as makers and takers. The contract ensures appropriate collateral management and provides mechanisms for handling platform fees and referral bonuses.

Prerequisites

  • Solidity compiler version: 0.8.13

  • Required OpenZeppelin libraries: @openzeppelin/contracts/token/ERC20/IERC20.sol, @openzeppelin/contracts/utils/math/Math.sol

  • Custom external contracts: PerMarketsStorage, OfferStatus, StockStatus, ITadleFactory, ITokenManager, ISystemConfig, IPerMarkets, IWrappedNativeToken

  • Custom libraries: RelatedContractLibraries, MarketPlaceLibraries, OfferLibraries, GenerateAddress, Constants

  • Custom utilities: Rescuable, Related, Errors


Modules and Structures

Storage Modules

  1. PerMarketsStorage: Inherited for storing market-specific data.

  2. OfferStatus: Contains enumerations like OfferStatus, AbortOfferStatus, OfferType, OfferSettleType used for tracking offers.

  3. StockStatus: Tracks the status of different stocks using enumerations like StockStatus, StockType.

Interfaces

  1. IPerMarkets: Implements offer-related function signatures.

  2. ITadleFactory: Provides methods to interact with the Tadles factory.

  3. ITokenManager: Manages token-related functionalities.

  4. ISystemConfig: Handles system configurations.

  5. IWrappedNativeToken: For wrapped native token management.


Key Functions

Constructor

  • constructor(): Initializes the contract.

Create Offer

  • createOffer(CreateOfferParams calldata params) external payable:

    • Validates input parameters.

    • Checks the marketplace status.

    • Generates addresses for maker, offer, and stock.

    • Transfers collateral from the sender.

    • Updates relevant mappings (makerInfoMap, offerInfoMap, stockInfoMap).

    • Emits the CreateOffer event.

Create Taker

  • createTaker(address _offer, uint256 _points) external payable:

    • Validates points.

    • Checks offer status.

    • Generates a stock address.

    • Transfers collateral from the taker.

    • Updates offerInfo and stockInfo.

    • Emits the CreateTaker event.

List Offer

  • listOffer(address _stock, uint256 _amount, uint256 _collateralRate) external payable:

    • Validates input amounts and collateral rate.

    • Checks if the stock type is valid for listing.

    • Transfers the required collateral.

    • Updates offer and stock information.

    • Emits the ListOffer event.

Close Offer

  • closeOffer(address _stock, address _offer) external:

    • Checks offer status.

    • Performs appropriate refunds to the maker.

    • Updates offer status to Canceled.

    • Emits the CloseOffer event.

Relist Offer

  • relistOffer(address _stock, address _offer) external payable:

    • Validates the offer status for re-listing.

    • Transfers required collateral back to the capital pool.

    • Marks the offer status as Virgin.

    • Emits the RelistOffer event.

Abort Offers

  • abortAskOffer(address _stock, address _offer) external:

    • Validates conditions for aborting an ask offer.

    • Updates relevant refund amounts.

    • Sets offerStatus to Settled and abortOfferStatus to Aborted.

    • Emits the AbortAskOffer event.

  • abortBidTaker(address _stock, address _offer) external:

    • Checks conditions for aborting a bid taker.

    • Updates the refund amount.

    • Sets stock status to Finished.

    • Emits the AbortBidTaker event.

Update Functions

  • updateOfferStatus(address _offer, OfferStatus _status) external:

    • Updates the status of an offer.

    • Emits the OfferStatusUpdated event.

  • updateStockStatus(address _stock, StockStatus _status) external:

    • Updates the status of a stock.

    • Emits the StockStatusUpdated event.


Events

  • CreateOffer: Emitted when an offer is created.

  • CreateTaker: Emitted when a taker is created.

  • ListOffer: Emitted when an offer is listed.

  • CloseOffer: Emitted when an offer is closed.

  • RelistOffer: Emitted when an offer is relisted.

  • AbortAskOffer: Emitted when an ask offer is aborted.

  • AbortBidTaker: Emitted when a bid taker is aborted.

  • OfferStatusUpdated: Emitted when offer status is updated.

  • StockStatusUpdated: Emitted when stock status is updated.

  • SettledAskOffer: Emitted when an ask offer is settled.

  • SettledBidTaker: Emitted when a bid taker is settled.


Best Practices

  1. Validation: Always ensure appropriate validations for input parameters to prevent mishandling.

  2. Events: Emit relevant event logs for every state change for better traceability.

  3. Handling Funds: Make sure to handle fund transfers securely and accurately to maintain user trust.

  4. Mappings and Address Generations: Ensure proper management and updating of storage mappings and address generations to maintain consistency.

  5. Modifiers: Use modifiers like onlyDeliveryPlace to control access to sensitive operations.


Security Issues for PreMarkets.sol.sol

This Solidity code defines a smart contract named PreMarkets, which implements a system for managing offers and stocks in a marketplace. While the code appears to be structured and logical, it contains several potential security issues and vulnerabilities that need to be addressed for improved safety and reliability. Below, I detail these security issues and suggest ways to fix them:

1. Missing Checks on External Calls and Reentrancy Guard

Issue

The contract makes multiple external calls (e.g., to tadleFactory.getSystemConfig() and tokenManager.tillIn{value: msg.value}()) without reentrancy protection. This could lead to reentrancy vulnerabilities, where an attacker calls back into the contract before the first function invocation fully completes.

Fix

Use the ReentrancyGuard contract from OpenZeppelin to prevent reentrancy attacks. Applying the nonReentrant modifier to functions that make external calls can mitigate the risk of reentrancy attacks.

Updated Code Example

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract PreMarkets is PerMarketsStorage, Rescuable, Related, IPerMarkets, ReentrancyGuard {
// Constructor stays the same
constructor() Rescuable() {}
function createOffer(CreateOfferParams calldata params) external payable nonReentrant {
// Function body remains the same
}
function createTaker(address _offer, uint256 _points) external payable nonReentrant {
// Function body remains the same
}
function listOffer(address _stock, uint256 _amount, uint256 _collateralRate) external payable nonReentrant {
// Function body remains the same
}
// Apply nonReentrant to other functions making external calls
}

2. Unchecked Address Generation

Issue

Addresses for maker, offer, and stock are generated without ensuring that they are unique or valid, and the generated address could potentially be manipulated.

Fix

Use keccak256 for deterministic address generation and confirm uniqueness by checking against relevant mappings.

Updated Code Example

function _generateAddress(bytes32 salt) internal view returns (address) {
return address(uint160(uint256(keccak256(abi.encodePacked(address(this), salt)))));
}
function uniqueGenerateAddress(uint256 id) internal view returns (address) {
address newAddr = _generateAddress(keccak256(abi.encodePacked(id)));
require(makerInfoMap[newAddr].authority == address(0), "Address already exists");
return newAddr;
}
function createOffer(CreateOfferParams calldata params) external payable nonReentrant {
// ... previous code remains
address makerAddr = uniqueGenerateAddress(offerId);
address offerAddr = uniqueGenerateAddress(offerId);
address stockAddr = uniqueGenerateAddress(offerId);
// Continue as normal
}

3. Lack of Access Control on Critical Functions

Issue

Functions such as updateOfferStatus and updateStockStatus can be called by anyone if the onlyDeliveryPlace modifier is compromised. Additionally, onlyDeliveryPlace modifier seems custom and should be analyzed for potential risks.

Fix

Explicitly verify the caller using standardized access control patterns, such as OpenZeppelin's AccessControl.

Updated Code Example

import "@openzeppelin/contracts/access/AccessControl.sol";
contract PreMarkets is PerMarketsStorage, Rescuable, Related, IPerMarkets, ReentrancyGuard, AccessControl {
bytes32 public constant DELIVERY_ROLE = keccak256("DELIVERY_ROLE");
constructor() Rescuable() {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function updateOfferStatus(address _offer, OfferStatus _status) external onlyRole(DELIVERY_ROLE) {
OfferInfo storage offerInfo = offerInfoMap[_offer];
offerInfo.offerStatus = _status;
emit OfferStatusUpdated(_offer, _status);
}
function updateStockStatus(address _stock, StockStatus _status) external onlyRole(DELIVERY_ROLE){
StockInfo storage stockInfo = stockInfoMap[_stock];
stockInfo.stockStatus = _status;
emit StockStatusUpdated(_stock, _status);
}
// Restrict role assignments for enhanced security
function grantDeliveryRole(address account) external onlyRole(DEFAULT_ADMIN_ROLE) {
grantRole(DELIVERY_ROLE, account);
}
function revokeDeliveryRole(address account) external onlyRole(DEFAULT_ADMIN_ROLE) {
revokeRole(DELIVERY_ROLE, account);
}
}

4. Inadequate Input Validation

Issue

Inputs such as amounts and addresses are not always validated properly, allowing the possibility of passing in invalid values.

Fix

Implement comprehensive checks for input validation to ensure the input values are within allowed ranges and are not zero or invalid.

Updated Code Example

function createOffer(CreateOfferParams calldata params) external payable nonReentrant {
require(params.points > 0, "Points must be greater than zero");
require(params.amount > 0, "Amount must be greater than zero");
require(params.eachTradeTax <= Constants.EACH_TRADE_TAX_DECIMAL_SCALER, "Invalid eachTradeTax");
require(params.collateralRate >= Constants.COLLATERAL_RATE_DECIMAL_SCALER, "Invalid collateralRate");
require(params.marketPlace != address(0), "Invalid marketplace address");
require(params.tokenAddress != address(0), "Invalid token address");
// Continue as normal
}

5. Hard-Coded Constants and Magic Numbers

Issue

Magic numbers and hardcoded values in smart contracts can obscure the intended behavior and make maintenance difficult. They also introduce risk for errors when values need changes.

Fix

Extract magic numbers and hardcoded values into constants or configuration variables.

Updated Code Example

uint256 constant INVALID_POINTS = 0;
uint256 constant INVALID_AMOUNT = 0;
function createOffer(CreateOfferParams calldata params) external payable nonReentrant {
require(params.points != INVALID_POINTS, "Points must be greater than zero");
require(params.amount != INVALID_AMOUNT, "Amount must be greater than zero");
// Continue as before
}

6. Missing Events on Critical State Changes

Issue

Important state changes should emit events to provide transparency and aid in monitoring and troubleshooting.

Fix

Ensure that an event is emitted in all critical state-changing functions not already emitting one.

Updated Code Example

event OfferClosed(address indexed offer, address indexed caller);
event OfferRelisted(address indexed offer, address indexed caller);
function closeOffer(address _stock, address _offer) external {
// ... existing logic
emit OfferClosed(_offer, _msgSender());
}
function relistOffer(address _stock, address _offer) external payable nonReentrant {
// ... existing logic
emit OfferRelisted(_offer, _msgSender());
}

By addressing these security issues and incorporating these fixes, the smart contract's safety and reliability will be significantly enhanced. Properly securing a smart contract is critical in protecting users' assets and maintaining trust in the decentralized system.

Vulnerability for PreMarkets.sol.sol

not an issue

CWE-480 (SWC-129) - Typographical Error

A typographical error can occur for example when the intent of a defined operation is to sum a number to a variable (+=) but it has accidentally been defined in a wrong way (=+), introducing a typo which happens to be a valid operator. Instead of calculating the sum it initializes the variable again. The unary + operator is deprecated in new solidity compiler versions.

not an issue

CWE-1164 (SWC-131) - Presence of unused variables

Unused variables are allowed in Solidity and they do not pose a direct security issue. It is best practice though to avoid them as they can: cause an increase in computations (and unnecessary gas consumption) indicate bugs or malformed data structures and they are generally a sign of poor code quality cause code noise and decrease readability of the code

SWC-129: Typographical Error

Issue:
Typographical errors in smart contracts can lead to unexpected behaviors and security vulnerabilities. They also make the code harder to read and maintain.

Details: The contract name PreMarktes in the contract declaration is a typographical error. It should be PreMarkets.

Updates

Lead Judging Commences

0xnevi Lead Judge
about 1 year ago
0xnevi Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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