Skip to content

Latest commit

 

History

History
124 lines (88 loc) · 3.85 KB

File metadata and controls

124 lines (88 loc) · 3.85 KB

Joyous Chambray Dolphin

High

Insufficient liquidity and pricing manipulation in ReputationMarket.sol allows attackers to manipulate the market with minimal funds

Summary

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.

Root Cause

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:

  1. Low liquidity (0.002 ETH): with minimal liquidity, prices react sharply to small transactions.
  2. Single vote (1 trust, 1 distrust): voting changes have exaggerated effects on price calculations.

Internal pre-conditions

Setup: Default DEFAULT_PRICE = 0.01 ETH. Initial trust votes = 1, distrust votes = 1. Liquidity = 0.002 ETH (from the Default tier configuration).

External pre-conditions

No response

Attack Path

  1. Attacker creates a market using the Default tier:
contractInstance.createMarketWithConfig(0, { value: 0.002 ether });
  1. Initial state: Trust votes: 1 Distrust votes: 1 Trust price: 0.01 ETH Distrust price: 0.01 ETH

  2. Attacker votes for trust with 5 additional votes:

contractInstance.voteTrust(profileId, 5, { value: 0.005 ether });
  1. 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

  1. Attacker votes against trust, reducing trust votes:
contractInstance.voteDistrust(profileId, 5, { value: 0.001 ether });
  1. 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.

Impact

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.

PoC

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.

Mitigation

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;