Skip to content

Latest commit

 

History

History
72 lines (50 loc) · 2.15 KB

File metadata and controls

72 lines (50 loc) · 2.15 KB

Mythical Flaxen Hamster

High

Price Oracle Absence in VVVVCInvestmentLedger Creates Arbitrage Window

Summary

The VVVVCInvestmentLedger contract relies on off-chain signed exchange rates that remain static during the signature validity window, creating potential arbitrage opportunities during significant price movements of the payment token.

Root Cause

The exchange rate mechanism in invest() uses a fixed exchangeRateNumerator that's signed off-chain and remains valid until the deadline:

uint256 preFeeStableAmountEquivalent = (_params.amountToInvest * _params.exchangeRateNumerator) /
    exchangeRateDenominator;

Internal Pre-conditions

  • Valid investment parameters signed by authorized signer
  • Investment round is active
  • User has sufficient payment tokens

External Pre-conditions

  • Significant price movement of payment token occurs between signature issuance and execution
  • Market conditions allow for profitable arbitrage

Attack Path

  1. Attacker obtains signed investment parameters with fixed exchangeRateNumerator
  2. Monitors payment token for price movements
  3. When price drops significantly:
function invest(InvestParams memory _params) external {
    // Price check absent here
    uint256 preFeeStableAmountEquivalent = (_params.amountToInvest * _params.exchangeRateNumerator) /
        exchangeRateDenominator;
    // Execute investment at old rate
}
  1. Executes investment using devalued tokens at the original higher exchange rate

Impact

  • Project receives fewer dollars worth of investment than intended
  • Creates unfair advantage over fiat investors
  • Particularly risky with volatile tokens or during market stress

Mitigation

Implement on-chain price oracle integration:

interface IPriceOracle {
    function getExchangeRate(address token) external view returns (uint256);
}

function invest(InvestParams memory _params) external {
    uint256 currentRate = oracle.getExchangeRate(_params.paymentTokenAddress);
    require(
        currentRate >= _params.exchangeRateNumerator * 95 / 100,
        "Price deviation too high"
    );
    // Continue with investment
}