> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phylax.systems/llms.txt
> Use this file to discover all available pages before exploring further.

# Cream Finance 2

> Cream Finance suffered a price manipulation hack

Cream Finance suffered a 130M USD hack in October 2021.

Detailed Analysis: [https://mudit.blog/cream-hack-analysis/](https://mudit.blog/cream-hack-analysis/)

## What Happened

The attack stem from a sudden price manipulation of a supported asset (yUSDVault) in the protocol.
The attacker built up leveraged positions and then manipulated the price of the asset by donating
the underlying into the yUSDVault.

## Assertion Pattern

One possible solution is to check price deviations from touched assets in the protocol during the transaction.
This would avoid flashloan price manipulation attacks.

```solidity theme={null}
uint256 constant MAX_DEVIATION_BPS = 500; // 5% max deviation

function assertion_priceDeviation() external view {
    // Get pre-transaction prices first
    PhEvm.ForkId memory preFork = _preTx();
    PhEvm.Log[] memory logs = ph.getLogs();

    // Count relevant logs to size our array
    uint256 count = 0;
    for (uint256 i = 0; i < logs.length; i++) {
        bytes32 topic = logs[i].topics[0];
        if (topic == CTokenInterface.Mint.selector ||
            topic == CTokenInterface.Redeem.selector ||
            topic == CTokenInterface.Borrow.selector ||
            topic == CTokenInterface.RepayBorrow.selector) {
            count++;
        }
    }

    // Collect touched assets and their pre-prices
    address[] memory touchedAssets = new address[](count);
    uint256[] memory prePrices = new uint256[](count);
    uint256 idx = 0;

    for (uint256 i = 0; i < logs.length; i++) {
        bytes32 topic = logs[i].topics[0];
        address asset;

        if (topic == CTokenInterface.Mint.selector) {
            asset = getAssetFromLog(logs[i]);
        } else if (topic == CTokenInterface.Redeem.selector) {
            asset = getAssetFromLog(logs[i]);
        } else if (topic == CTokenInterface.Borrow.selector) {
            asset = getAssetFromLog(logs[i]);
        } else if (topic == CTokenInterface.RepayBorrow.selector) {
            asset = getAssetFromLog(logs[i]);
        } else {
            continue;
        }

        touchedAssets[idx] = asset;
        prePrices[idx] = priceOracle.getPrice(asset);
        idx++;
    }

    // Get post-transaction prices and compare
    PhEvm.ForkId memory postFork = _postTx();

    for (uint256 i = 0; i < touchedAssets.length; i++) {
        uint256 postPrice = priceOracle.getPrice(touchedAssets[i]);
        uint256 prePrice = prePrices[i];

        // Check deviation in both directions
        uint256 deviation;
        if (postPrice > prePrice) {
            deviation = ((postPrice - prePrice) * 10000) / prePrice;
        } else {
            deviation = ((prePrice - postPrice) * 10000) / prePrice;
        }

        require(deviation <= MAX_DEVIATION_BPS, "Price deviation too high");
    }
}

// Helper to extract asset address from log (implementation depends on log structure)
function getAssetFromLog(PhEvm.Log memory log) internal pure returns (address) {
    // Decode asset address from log topics or data
    // Implementation depends on the specific event structure
    return abi.decode(log.data, (address));
}
```
