Narrow Lipstick Moose
High
The createMarketWithConfig
function in the ReputationMarket.sol
contract allows users to create markets using predefined configurations (Default, Deluxe, Premium) with associated liquidity and vote levels. However, the _createMarket
function sets the initial votes for Trust and Distrust to 1, regardless of the selected tier. This discrepancy results in all markets being initialized at the Default
tier's vote levels, even when users pay for higher-tier configurations like Deluxe
or Premium
.
This behavior misaligns with the intended design and user expectations, potentially leading to disputes and dissatisfaction from users who do not receive what they pay for.
Prices are determined by a bonding curve formula based on the ratio of Trust and Distrust votes. Initializing both with a minimal value (1) creates disproportionate sensitivities to small changes in votes, resulting in unpredictable and unstable pricing dynamics.
The issue can be observed here : https://github.com/sherlock-audit/2024-12-ethos-update/blob/main/ethos/packages/contracts/contracts/ReputationMarket.sol#L318-L355
function _createMarket(
uint256 profileId,
address recipient,
uint256 marketConfigIndex
) private nonReentrant {
// ensure a market doesn't already exist for this profile
if (markets[profileId].votes[TRUST] != 0 || markets[profileId].votes[DISTRUST] != 0)
revert MarketAlreadyExists(profileId);
// ensure the specified config option is valid
if (marketConfigIndex >= marketConfigs.length)
revert InvalidMarketConfigOption("Invalid config index");
uint256 creationCost = marketConfigs[marketConfigIndex].creationCost;
// Handle creation cost, refunds and market funds for non-admin users
if (!hasRole(ADMIN_ROLE, msg.sender)) {
if (msg.value < creationCost) revert InsufficientLiquidity(creationCost);
marketFunds[profileId] = creationCost;
if (msg.value > creationCost) {
_sendEth(msg.value - creationCost);
}
} else {
// when an admin creates a market, there is no minimum creation cost; use whatever they sent
marketFunds[profileId] = msg.value;
}
// Create the new market using the specified config
markets[profileId].votes[TRUST] = 1;
markets[profileId].votes[DISTRUST] = 1;
markets[profileId].basePrice = marketConfigs[marketConfigIndex].basePrice;
markets[profileId].liquidityParameter = marketConfigs[marketConfigIndex].liquidity;
donationRecipient[profileId] = recipient;
emit MarketCreated(profileId, msg.sender, marketConfigs[marketConfigIndex]);
_emitMarketUpdate(profileId);
}
In this function, no matter what the marketIndexConfig
(0,1 or 2) is, the market will always be of type default
because
markets[profileId].votes[TRUST] = 1; //@audit always default type
markets[profileId].votes[DISTRUST] = 1; //@audit always default type
No response
No response
No response
- Users who create markets at higher tiers (Deluxe or Premium) are not assigned the appropriate vote levels, reducing the liquidity and stability of their markets.
- Users paying higher creation costs do not receive the benefits associated with these tiers, leading to potential disputes and reputational risks for the protocol.
- Market behaviors and pricing based on vote levels will be skewed due to incorrectly initialized markets, affecting fairness in price discovery.
Steps to Reproduce:
-
Call the
createMarketWithConfig
function with ex.marketConfigIndex = 2
(Premium tier), which should initialize 10,000 votes for Trust and Distrust. -
Observe that the actual votes for the created market are set to 1 for both Trust and Distrust.
Add initialVotes
in the MarketConfigs
struct.
And update the _createMarket
by doing:
markets[profileId].votes[TRUST] = marketConfigs[marketConfigIndex].initialVotes;
markets[profileId].votes[DISTRUST] = marketConfigs[marketConfigIndex].initialVotes;